Skip to content

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:

  • MaterialStateVariable names 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;
  • MaterialStateSchema gives the complete state vector a stable versioned identity and owns initialization, validation and unpacking;
  • MaterialTangentConvention declares 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

tangent = constitutive.MaterialTangentConvention.first_piola_deformation_gradient()

which represents

\[ \mathbb A = \frac{\partial\mathbf P}{\partial\mathbf F}. \]

The restricted Abaqus UMAT route instead declares the Abaqus spatial Jacobian and engineering-shear ordering:

tangent = constitutive.MaterialTangentConvention.abaqus_umat()

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

response = constitutive.validated_material_update(material, point)

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:

state = constitutive.MaterialQuadratureState.create(
    domain,
    material.state_schema,
    degree=2,
)

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:

evidence = constitutive.check_material_tangent(material, point)
evidence.accepted

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:

agentfem inspect-user-material legacy.for \
  --write legacy.inspection.json --json

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:

  1. compile a restricted UHYPER routine into a shared library;
  2. call it at selected invariants;
  3. map the returned energy derivatives into an AgentFEM constitutive law;
  4. compare stress and tangent over prescribed deformation paths;
  5. 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.