Data-driven surrogates for hyperelastic constitutive models in finite element analysis
Project description
hyper-surrogate
Define hyperelastic materials in Python, deploy them in your finite element solver.
- Github repository: https://github.com/jpsferreira/hyper-surrogate/
- Documentation: https://jpsferreira.github.io/hyper-surrogate/
Table of Contents
Why hyper-surrogate?
Finite element solvers need constitutive models. Writing and maintaining those models — especially user-material subroutines for Abaqus, FEAP and similar Fortran-based solvers — is repetitive: kinematics, second Piola–Kirchhoff stress, consistent tangent, Jaumann correction, reference-configuration freedom, all in Fortran 77 or 90.
hyper-surrogate lets you define your material once in Python and emit a self-contained Fortran 90 user subroutine deployable in any Fortran-based FE solver. You choose how the material is defined:
- Built-in symbolic SEF — one of ten classical isotropic and anisotropic models (Neo-Hooke, Mooney-Rivlin, Yeoh, Holzapfel-Ogden, Gasser-Ogden-Holzapfel, …).
- Custom symbolic SEF — subclass
Materialwith asefproperty inSymPyand the framework derives stress and tangent automatically. - Data-driven surrogate — train an MLP, ICNN, or polyconvex ICNN on energy and stress samples from any ground-truth source and emit a hybrid UMAT whose energy is the trained network and whose stress and tangent are computed analytically in Fortran.
All three paths produce the same artefact: a .f90 with Cauchy stress,
analytical consistent tangent, and stress-freedom at the reference
configuration enforced exactly at emission time. No Python runtime
is required at solve time.
Architecture
Material ─> DeformationGenerator ─> Dataset ─> MLP / ICNN ─> HybridUMATEmitter ─> .f90
│ │
│ (symbolic SEF) │ (trained NN weights)
│ │
└──── UMATHandler ─────────────────────────────┘
(analytical Fortran via SymPy CSE)
Features
- Three entry points, one output — built-in SEF, custom SymPy SEF, or trained surrogate, all emit a structurally identical Fortran UMAT.
- Symbolic mechanics — automatic PK2 stress and stiffness tensor derivation via SymPy; analytical Cauchy push-forward and Jaumann correction emitted with common-subexpression elimination.
- NN architectures — MLP, Input-Convex NN, and polyconvex ICNN, trained with an energy-plus-stress dual loss that backpropagates the gradient target through autograd.
- Hybrid UMAT — neural-network strain energy with closed-form analytical kinematics, stress, and consistent tangent in Fortran; layer-additive Hessian backpropagation verified against autograd at $10^{-5}$ tolerance.
- Stress freedom at reference — enforced exactly at emission time by subtracting a compile-time offset; no surprise residual stress at $\mathbf{C} = \mathbf{I}$.
- Anisotropic support — fiber pseudo-invariants $I_4, I_5$ for one or two fiber families with arbitrary orientations.
Quick Start
Three short pipelines, mirroring the three ways to define a material:
Path A — built-in symbolic SEF
from hyper_surrogate import NeoHooke, UMATHandler
UMATHandler(NeoHooke({"C10": 0.5, "KBULK": 1000.0})).generate("neohooke.f90")
Path B — custom user-defined SEF
import sympy as sp
from hyper_surrogate import Material, UMATHandler
class MyOgdenLike(Material):
DEFAULT_PARAMS = {"mu": 1.0, "alpha": 2.0, "KBULK": 1000.0}
def __init__(self, parameters=None):
super().__init__({**self.DEFAULT_PARAMS, **(parameters or {})})
@property
def sef(self):
h = self._handler
mu, alpha, K = (self._symbols[k] for k in ("mu", "alpha", "KBULK"))
return ((mu / alpha) * (h.isochoric_invariant1 ** (alpha / 2) - 3)
+ 0.5 * K * (sp.sqrt(h.invariant3) - 1) ** 2)
UMATHandler(MyOgdenLike()).generate("mysef.f90")
Path C — data-driven surrogate
from hyper_surrogate import (
NeoHooke, MLP, Trainer, EnergyStressLoss,
create_datasets, extract_weights, HybridUMATEmitter,
)
material = NeoHooke({"C10": 0.5, "KBULK": 1000.0})
train_ds, val_ds, in_norm, energy_norm = create_datasets(
material, n_samples=4000, input_type="invariants",
target_type="energy", deformation_mode="combined_compressible",
)
model = MLP(input_dim=3, output_dim=1, hidden_dims=[64, 64, 64], activation="softplus")
result = Trainer(model, train_ds, val_ds,
loss_fn=EnergyStressLoss(alpha=1.0, beta=1.0),
max_epochs=2000, patience=200).fit()
exported = extract_weights(result.model, in_norm, energy_norm)
HybridUMATEmitter(exported).write("neohooke_hybrid.f90")
See the documentation for the full tutorial set, including custom materials, anisotropic models, and the export-path decision tree.
Installation
pip install hyper-surrogate # core (NumPy, SymPy)
pip install hyper-surrogate[ml] # with PyTorch for ML surrogates
From source with uv:
git clone https://github.com/jpsferreira/hyper-surrogate.git
cd hyper-surrogate
uv sync --all-groups --extra ml
Examples
Runnable scripts are in the examples/ directory:
| Script | Path | Description |
|---|---|---|
analytical_umat.py |
A | Built-in NeoHooke → analytical UMAT via UMATHandler |
custom_sef.py |
B | Custom Ogden-like SEF → analytical UMAT |
export_hybrid_umat.py |
C | End-to-end train + HybridUMATEmitter export |
train_neohooke_sef.py |
C | Train MLP on NeoHooke SEF with hybrid inference |
train_icnn_energy.py |
C | Train ICNN with EnergyStressLoss |
train_polyconvex.py |
C | Train PolyconvexICNN with per-invariant convexity |
train_holzapfel_ogden.py |
C | Anisotropic fiber-reinforced training pipeline |
Run any example with:
uv run python examples/<script>.py
Contributing
Contributions are welcome! See CONTRIBUTING.md for setup instructions and guidelines.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file hyper_surrogate-0.4.0.tar.gz.
File metadata
- Download URL: hyper_surrogate-0.4.0.tar.gz
- Upload date:
- Size: 310.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.15 {"installer":{"name":"uv","version":"0.11.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
df7ee90e17b7c841b791c728df76e6e3dfdca8e211a1e5c5248ba3fed3f92cfd
|
|
| MD5 |
357a133baade590cbabea10e545c4486
|
|
| BLAKE2b-256 |
5300bc450bb455ee37c941b9b34bed03e444b538296b162edb1c3f6e47bc4fbf
|
File details
Details for the file hyper_surrogate-0.4.0-py3-none-any.whl.
File metadata
- Download URL: hyper_surrogate-0.4.0-py3-none-any.whl
- Upload date:
- Size: 62.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.15 {"installer":{"name":"uv","version":"0.11.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
33637e243bc081ee900ac1bd7e0aa4702262df397f88b8c5567a18255301da45
|
|
| MD5 |
2f65d2cc33cb96a504eba3c923208378
|
|
| BLAKE2b-256 |
8a1888f06d4bde57ae492e7d07f973e3e22758d1483f3c9c692d1da3f00b3bfa
|