Abaqus User-Material Migration Boundary¶
Restricted VUMAT batch bridge (experimental)¶
constitutive.compile_vumat compiles explicitly trusted source once and loads
one native library per bridge instance. CompiledVumat.update transports an
entire block in one call, rather than calling Python per integration point.
Supported: the legacy lanneal / scalar dt signature, three-dimensional
solids (ndir=3, nshr=3), binary64, and GNU Fortran on macOS, Linux or WSL2.
Modern jInfoArray / dtArray, shells, plane stress, annealing and vendor
utility calls are outside this profile. Formal argument names and ordering
must match the legacy signature.
from agentfem import constitutive
schema = constitutive.MaterialStateSchema(
"my-material-v1",
(constitutive.MaterialStateVariable("history", shape=(8,)),),
)
material = constitutive.compile_vumat(
"material.for", state_schema=schema, properties=[1000., 0.3],
cache_directory=".agentfem/material-build", trusted=True,
)
# request = constitutive.VumatBatchInput(...) # all physical channels required
# response = material.update(request)
Properties above are illustrative; their meaning belongs to the supplied law.
State and field counts are arbitrary, including zero. All physical channels
are required: density, coordinates, characteristic length, old/new stretch and
deformation gradient, temperatures, fields, stress, state, strain and relative
spin increments. There is no implicit unit conversion or fabricated zero input.
The caller supplies corotational quantities. Symmetric order is
11,22,33,12,23,31 with tensor shear; deformation-gradient order is
11,22,33,12,23,31,21,32,13.
The bridge supplies a minimal vaba_param.inc precision declaration, not an
Abaqus runtime or a copy of its header. Reviewed local includes are fingerprinted.
The cache identity includes source graph, wrapper, compiler version, flags and
platform; library integrity is checked before reuse. Compilation downloads
nothing and retains diagnostics on failure. trusted=True is not a sandbox:
native code can terminate a process or access its files. Review sources first.
Inputs are protected against accidental native writes; new state is returned
without committing it. Hidden SAVE/COMMON history is unsuitable for restart
and rollback even though calls on one bridge instance are serialized. Physical
history must live in the declared state vector. Non-finite stress/state or
partially written energy fails; an entirely unwritten optional energy is None,
not zero. Internal/inelastic energies are per mass, not elastic storage or
reference-volume work increments.
This is not automatic global VUMAT compatibility. An adapter to the existing
explicit_user_material must also establish objective kinematics, stress
rotation, density/energy conversion, state layout and stable-step policy.
Procedure owns acceptance and checkpoints; no VUMAT solver or fake tangent is
introduced. Verify material paths, a single element and then a structural path.
Compilation alone establishes neither finite-rotation, deletion nor MPI parity.
See the Abaqus VUMAT reference for conventions. The wrapper uses Fortran C interoperability, not a direct Python call into a compiler-dependent Fortran entry point.
What “compatible” should mean¶
AgentFEM should not advertise arbitrary Abaqus user subroutines as directly portable merely because their Fortran entry-point names are known. A credible bridge must preserve the material-point contract:
- old and new deformation gradients, time, temperature, field variables, properties, and state variables enter one update;
- the update returns Cauchy stress, updated state, energy, and an algorithmic tangent in a declared tensor convention;
- the global nonlinear driver stores state at quadrature points, commits it only after a converged increment, and uses the returned tangent consistently;
- one-point, one-element, and full load-path comparisons establish equivalence.
constitutive.user_material now records this solver-neutral boundary. It is an
interface contract, not an executable Abaqus runtime.
The neutral contract is explicit¶
A finite-strain tangent cannot be identified by its array shape alone. AgentFEM therefore separates three public assets:
MaterialStateVariablenames one scalar or tensor internal variable and declares its shape, scalar-broadcast or explicit tensor initial value, unit, description and optional output field name; this permits, for example, an identity initial plastic deformation gradient rather than silently filling every tensor state with zero;MaterialStateSchemagives the complete state vector a stable versioned identity and owns initialization, validation and unpacking;MaterialTangentConventiondeclares the stress measure, conjugate kinematic perturbation, reference/current configuration, storage layout, component order, shear convention and objective-rate convention.
For example, a native total-Lagrangian provider may declare
which represents
The restricted Abaqus UMAT route instead declares the Abaqus spatial Jacobian and engineering-shear ordering:
These declarations are not interchangeable conversions. A provider or adapter must implement and verify the transformation required by the global residual it serves.
An update becomes eligible for a future global Newton consumer only through
This call checks the input state against the material schema, runs the update,
requires a complete tangent and state declaration, and rejects any schema or
convention drift in the returned response. Legacy MaterialPointOutput
objects without those declarations remain inspectable but fail closed when
require_global_newton_contract() is called.
State storage lowers through the same public schema rather than through an
adapter-specific STATEV array:
Each declared scalar or tensor becomes a committed/trial quadrature-field pair initialized from the schema. The complete schema summary is part of the portable checkpoint identity, so changing a tensor shape, initial value, output alias, unit, or schema version cannot silently reuse an incompatible archive. This container provides storage and atomic lifecycle only; the material update and global residual remain separate consumers.
Finite-strain update_material_points(...) and MaterialQuadratureResponse.update(...)
bound provider calls with max_batch_points=1024 by default. This limits temporary
Python input/response objects independently of mesh size; final numeric fields
still scale with the number of integration points. Users can explicitly choose
another positive bound. A provider must produce point-local responses independent
of batch partitioning. Every chunk reads committed history; no trial field is
assigned until all chunks and ranks succeed. A later-chunk failure rejects the
whole update, not only that chunk. Result evidence counts actual provider calls.
Input/output state definitions are compared in full, not only by name/version.
Optional stored energy has an explicit availability mask; a missing value is
not certified as a physically defined zero.
Providers can additionally implement update_array_batch(request) with
MaterialPointArrayBatchInput and MaterialPointArrayBatchOutput. These are
columnar representations of the same finite-strain point semantics, not
a second material law or acceptance lifecycle. Gradients use (points, 3, 3),
state uses (points, state_schema.size), and tangent shape follows its explicit
convention. Shared properties, optional point temperatures and field variables
retain the ordinary meanings. Buffers are copied and read-only at the provider
boundary. Energy-component sum checks use a per-point tolerance, not a tolerance
scaled by the largest energy elsewhere in the batch.
The quadrature driver prefers this optional path when present, otherwise uses
the existing ordered update_batch or scalar update fallback. Array-call
failure is a failure of the whole update, never permission to silently switch
algorithms. Optional energy/dissipation channels are present for the entire
array batch or absent; providers needing mixed per-point availability can retain
the ordered point protocol. Empty MPI partitions do not call a provider. Native
finite-strain J2 uses the same integration and tangent routines through both
representations. This adds no temperature dependence or new physical capability.
MaterialPointOutput.dissipation_density_increment optionally reports irreversible
energy per reference volume over the update from the fixed committed state.
The batch response preserves a separate availability mask: None means unavailable,
whereas 0.0 means explicitly supplied zero. This is neither plastic work nor
the time-discretization remainder. Finite-strain J2 supplies the increment of its
existing cumulative plastic dissipation history; no additional history variable
or constitutive formula is introduced. Finite values are transported without
clipping; thermodynamic admissibility remains a separate verification decision.
Providers without this quantity remain compatible but cannot claim a complete
dissipation balance solely from successful execution.
For a provider that declares the total-Lagrangian convention (mathbb A=\partial\mathbf P/\partial\mathbf F), the discrete update can be checked directly:
The check holds the old deformation gradient and committed state fixed,
perturbs all nine components of the new deformation gradient, reconstructs
first Piola stress from the returned Cauchy stress, and compares the resulting
central-difference Jacobian with the declared tangent. It intentionally rejects
the Abaqus spatial UMAT convention: DDSDDE needs a verified stress/rate,
rotation and component transformation before it can be compared with
(\partial\mathbf P/\partial\mathbf F).
Inspect before adapting¶
An existing Fortran asset can now enter a deterministic inspection gate:
The command retains a SHA-256 source identity, detects a single UMAT or UHYPER entry point, inventories include files, distinguishes known Abaqus utility calls from project subroutines, and recommends one of three routes:
- restricted UHYPER energy adapter;
- restricted UMAT material-point adapter;
- manual interface identification/adaptation.
This is useful migration automation, not source translation. A clean report means only that the source is a candidate for the next adapter stage. A call to an Abaqus utility is an explicit blocker until its semantics are replaced or a compatible support library is provided.
Why UHYPER is the first practical bridge¶
UHYPER is narrower than UMAT. It describes isotropic hyperelastic energy and its derivatives with respect to invariants. That maps naturally to AgentFEM/UFL energy formulations and has no general inelastic stress-history algorithm to reproduce. A first adapter can therefore:
- compile a restricted UHYPER routine into a shared library;
- call it at selected invariants;
- map the returned energy derivatives into an AgentFEM constitutive law;
- compare stress and tangent over prescribed deformation paths;
- validate a single finite element before a periodic cell.
Why UMAT requires a constitutive driver¶
UMAT is a stateful integration algorithm. Abaqus calls it at every material
point and expects updated Cauchy stress, STATEV, and DDSDDE. A useful bridge
therefore requires more than a Python wrapper:
- quadrature-point storage for stress and state variables;
- trial/commit/rollback semantics across Newton iterations;
- Abaqus tensor ordering and engineering-shear conversion;
- finite-rotation and objective-rate conventions;
- the exact meaning of the old/new deformation gradients;
- handling of time-step suggestions and possibly nonsymmetric tangents;
- explicit policy for Abaqus utility calls, includes, orientations, thermal coupling, and element-dependent modified deformation gradients.
A routine limited to the standard arguments, PROPS, and STATEV is a
reasonable first migration target. Routines that call Abaqus utilities or
depend on solver internals need source-level adaptation and cannot be promised
as drop-in compatible.
Abaqus defines DDSDDE for finite-strain UMAT as a Jacobian associated with
the increment of Kirchhoff stress and the strain increment, with direct
components followed by engineering shear components. It also notes that local
orientations rotate the stored basis and that some first-order elements pass a
modified deformation gradient. AgentFEM records these facts as adapter
metadata; it does not relabel DDSDDE as
\(\partial\mathbf P/\partial\mathbf F\).
Progressive implementation route¶
| Stage | Deliverable | Evidence gate |
|---|---|---|
| 0 | Solver-neutral material-point input/output contract | validation tests |
| 0.5 | Source inspection and route selection | fingerprinted machine-readable report |
| 1 | UHYPER energy adapter | deformation-path stress/tangent comparison |
| 2 | Quadrature state, trial/commit/rollback | one-element inelastic test |
| 3 | Restricted UMAT shared-library adapter | identical material-point paths |
| 4 | Global nonlinear integration | one-element and benchmark agreement |
| 5 | Wider Abaqus conventions and utilities | capability matrix per routine |
The important architectural decision is that AgentFEM's global solver consumes the neutral material-point protocol. Native Python/C++ materials and Abaqus adapters become alternative providers behind the same boundary. This avoids making the public model language depend on Abaqus, while preserving a realistic route for valuable user-material libraries.
References¶
- Abaqus 2025 UMAT reference,
including
DDSDDE, component storage, deformation-gradient and orientation conventions. - C. Miehe, “Numerical computation of algorithmic (consistent) tangent moduli in large-strain computational inelasticity,” Computer Methods in Applied Mechanics and Engineering 134 (1996), 223--240. doi:10.1016/0045-7825(96)01019-5.