Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
0b30336
Add batch benchmark and bit-for-bit result dumps
chemiskyy Oct 26, 2026
502d389
Fix quadrature race and MIHEN/MISCN bugs; honour n_threads
chemiskyy Oct 26, 2026
dfe86e1
Reuse ModularUMAT instances and trim per-call overhead
chemiskyy Oct 26, 2026
c0836a8
Speed up Eshelby integration and cache homogenization
chemiskyy Oct 26, 2026
bdee373
Use fixed-size 3x3 spectral and small dense kernels
chemiskyy Oct 26, 2026
5e40575
Return the native dS/dE of finite-strain laws on demand
chemiskyy Oct 26, 2026
e8614a7
Add opt-in numerical options to schemes and Newton solves
chemiskyy Oct 26, 2026
eefaff6
Add bounded least squares and threads to identification
chemiskyy Oct 26, 2026
769dcd3
Add rotate_voigt: batch Voigt rotation by DR matrices
chemiskyy Oct 26, 2026
fc27c23
Rename bench -> benchmark and update docs/paths
chemiskyy Nov 3, 2026
aa7e49a
Update umat_catalog.rst
chemiskyy Nov 3, 2026
ad0d239
Make ncp a named run option and always use the EPICP closed-form tangent
chemiskyy Nov 4, 2026
d4002e6
Document the complementarity functions of the cutting plane
chemiskyy Nov 4, 2026
23d8a96
Apply min-NCP row by row on uncoupled local systems
chemiskyy Nov 4, 2026
0479eec
Separate the local integrator from the tangent operator
chemiskyy Nov 4, 2026
8705b5a
Merge master into perf/optimization-v2
chemiskyy Nov 4, 2026
a78c236
Replace copy/apply key ops with KeyTemplate
chemiskyy Nov 4, 2026
9757fe9
KeyTemplate: support per-test constants
chemiskyy Nov 5, 2026
eb9949e
Update CHANGELOG.md
chemiskyy Nov 5, 2026
658b235
Update CHANGELOG.md
chemiskyy Nov 5, 2026
8b2d26e
Update test_umat_condensed.py
chemiskyy Nov 5, 2026
b0bce20
Enforce closest-point integrator support per law
chemiskyy Nov 5, 2026
d80cdb3
Add cubic/isotropic checks & spectral utilities
chemiskyy Nov 5, 2026
1ccd367
Add ANSYS USERMAT plugin test and assorted fixes
chemiskyy Nov 5, 2026
0c7a8a6
Add Ansys USERMAT support and plugin infra
chemiskyy Nov 6, 2026
1781d96
Update CMakeLists.txt
chemiskyy Nov 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
195 changes: 195 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
# Changelog

All notable changes to simcoon are listed here. The format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and simcoon uses
[semantic versioning](https://semver.org/). Each pull request adds its entry
under **Unreleased**; the section takes the version number at the release.

## In progress

Known gaps and planned work, not yet in a release. An item moves to
**Unreleased** with the pull request that closes it.

- `ncp="min"` serves the mechanical EPICP, EPKCP and MODUL only: every
thermomechanical law (`_T`, `sim.umat_T`, thermomechanical blocks) is refused
by `check_ncp_serves` and keeps Fischer-Burmeister.
- `ncp="min"` is refused with Armstrong-Frederick back stresses under the
cutting plane (path dependent); whether the closest point, which restarts
from the start of the step, lifts this is not verified.
- `integrator="closest_point"` is provided with its algorithmic tangent only
(`tangent_mode="algorithmic"`): its continuum operator is not implemented.
- Other complementarity functions to measure against Fischer-Burmeister and
`min`, under both integrators: active set, scaled Fischer-Burmeister.
- The numerical options of the mean-field schemes (MIMTN/MISCN closed form,
rule, Anderson, tolerance) are still props slots: they are per phase (nested
schemes), so they need a named builder rather than a run option.
- fedoo does not pass `ncp` and `integrator` through yet.
- The external plugins (UMEXT, UMABA, UMANS) serve the small-strain route only: a finite-strain
entry in the plugin API (law fed the logarithmic strain, returning tau, as the internal
kernels) would let them run under NLGEOM.
- Migration of the laws to the modular engine (MODUL), state in
`benchmark/README.md`. Routed through the adapter (code 201): ELISO, ELIST,
ELORT, EPKCP, EPHIL, EPTRI, EPHAC, EPANI, EPDFA, EPCHG, EPHIN. To do:
- adapters for the hyperelastic laws whose MODUL equivalent exists (NEOHC,
MOORI, YEOHH, ISHAH, GETHH, SWANH, HOLZA; NEOHI to confirm);
- EPICP, EPCHA and PRONK keep their legacy kernel while it is faster;
- no MODUL equivalent yet: OGDEN, SNTVE, HYPOO, EPJCK, LLDM0, ZENER, ZENNK,
the SMA family, the micromechanics schemes;
- the thermomechanical dispatch (`umat_T`) has no adapter: every `_T` law
runs its legacy kernel.

## Planned for 3.0

Removals and renames scheduled for the next major version (breaking, kept in 2.x).

- The migration message for `tangent_mode=3` / `"closest_point"`: the check
`tangent_mode in ("closest_point", 3)` of `solve` (`simcoon/solver/core.py`)
and its C++ counterpart in `kernel_tangent_mode` (`umat_smart.cpp`). The
value then gets the generic error of an unknown tangent mode; the internal
kernel code 3 of the closest point is unchanged.
- Possibly rename `ZENER` / `ZENNK` after their rheology: they are the Poynting-Thomson
(Kelvin) form of the standard linear solid and its generalized Kelvin chain, not the Zener
(Maxwell) form; the 2.x names stay for compatibility.

## [Unreleased]

### Breaking changes

- `copy_parameters`, `apply_parameters`, `copy_constants` and `apply_constants`
are removed. `KeyTemplate(src, params, consts).write(dst)` copies the
templates and substitutes the keys in one call, about 5 times faster
(templates read once, each working file written once).
- The C++ kernel `umat_damage_weibull` is removed: no UMAT name dispatched to it. The
Weibull damage function `damage_weibull` (Functions/damage.hpp, `sim.damage_weibull`) stays.
- The C++ kernel `umat_prony_Nfast_plastic` (no header, no UMAT name) is removed: Prony
viscoelasticity with J2 plasticity is a `ModularMaterial` (MODUL).
- `tangent_mode=3` / `"closest_point"` is refused with a `ValueError`: the local
integrator is now chosen apart, with `integrator="closest_point"`, and
`tangent_mode` only takes `"none"`, `"continuum"` or `"algorithmic"`.
- `integrator="closest_point"` is refused with a `ValueError` for a law without a
closest-point update instead of running its cutting plane silently: it serves
EPICP, EPCHA, EPJCK, MODUL and its adapters and the SMA kernels (mechanical),
EPICP and EPKCP (thermomechanical). A Python law (PYEXT) receives
`tangent_mode` 0, 1 or 2 only.
- The numerical option slots of the props are removed: EPICP `props[6]`
(min-NCP) and `props[7]` (closed-form tangent), EPKCP `props[7]`, and
`ModularMaterial(ncp=...)`. The complementarity function is the run option
`ncp`, and the EPICP closed-form consistent tangent is always used.
- `condense="approximate"` / `"exact"` are renamed `"spatial_face"` /
`"material_face"` (#145).
- The thermomechanical UMATs return the heat of the increment `R` (storage
included), not a rate (#140).

### Added

- The Ansys USERMAT plugin (`UMANS`, `umat_plugin_ans_api`) is dispatched on the small-strain
route, as UMABA, and tested by `TUMABA` on the same case. The example plugin is rebuilt on the
`fea_transfer` component maps (now public: `fea_components`, `ansys_components`, `fe2vec`,
`fe2mat`...): it read the tangent and wrote the rotation row-major (transposed), hid four Wm
slots in the USERMAT's statev, and sent condensed states as 3D. `TUMANS` checks the data layout
on a USERMAT with a non-symmetric tangent and a non-trivial rotation. The Fortran example did
not compile in fixed form. `sim.umat` names the plugins in its error (`is_external_plugin`).
- `KeyTemplate.write(dst, test=i)`: a constant holds one value per test
(`input_values`, e.g. the fibre angle of each specimen) and the value of test
`i` is substituted. A constant with a single value warns: it belongs in the
template, not in a key.
- `identification(..., method="least_squares")`: bounded trust-region
reflective least squares, parameters scaled to [0, 1] (logarithmically for
positive bounds), `n_starts` starting points, `n_threads` for the Jacobian
columns or the generations of differential evolution. `calc_residuals`
returns the residuals whose sum of squares is `calc_cost`. Differential
evolution remains the default.
- Run options `ncp="fischer_burmeister" | "min"` and
`integrator="cutting_plane" | "closest_point"` in `solve`, `sim.umat` and
`sim.umat_T`. `min` applies to EPICP, EPKCP and MODUL (also next to Prony and
damage mechanisms), not to Armstrong-Frederick back stresses.
- `simcoon.rotate_voigt`: batch rotation of Voigt stresses, strains and
stiffness or concentration tensors by one rotation matrix per point, without
the GIL.
- Native dS/dE of the finite-strain laws built on F, on demand.
- C++: `cubic_coefficients` and `is_isotropic(L, Tensor4Type)` (constitutive.hpp; the isotropy
relation follows the Voigt convention of the type), `spectral_congruence` (eig_sym3.hpp),
`add_linearop_eigsym` (contimech.hpp), replacing private copies.
- `isochoric_invariants` takes a batch, (3,3,N) tensors or (6,N) Voigt columns, as
`isochoric_pstretch` does; both share one implementation (parallel, without the GIL).
- Condensed stress states (`nshr`, plane stress, shells, beams, trusses) in
`sim.umat`, the solver and the Abaqus bridges, with `condensation_serves`
(#139, #141, #145).
- Finite strain (NLGEOM) and thermomechanical finite strain in the Abaqus
bridges and the solver, `tangent_output` for `umat_T` (#143).
- LLDM0 ply damage model (Ladevèze–Le Dantec) (#144).
- STATEV size checks and typed exceptions in the Abaqus UMATs: numerical
failures request a step cut, input errors abort (#146).
- `slice_view`: lock-free aliases of cube slices in parallel loops (#147).
- GOH 2006 tube-inflation example for HOLZA (#142).
- `benchmark/`: batch benchmarks and bit-for-bit dumps of the solver outputs.

### Changed

- EPKCP thermomechanical: the cutting plane evaluates the power-law hardening through
`PowerLawHardening` (C1 blend below p = 1e-6), as EPICP and its own closest point; for
m < 1 the first plastic increment no longer meets an infinite slope.
- Faster kernels, results bitwise unchanged unless stated: reuse of the
ModularUMAT instances, fixed-size 3x3 spectral solves and small dense LU,
Eshelby integration and cached homogenization, closed-form
Fischer-Burmeister for one and two mechanisms.
- The Chaboche, composite and MOORI identification examples use the least
squares; the JSON-keys and analytical hyperelastic examples keep
differential evolution.

### Fixed

- An invalid elastic convention ended the process with `exit(0)` (`M_iso`, `L_cubic`, `M_cubic`,
`L_ortho`, `M_ortho`, `L_isotrans`, `M_isotrans`; from Python the interpreter quit with a success
code) or, in `L_iso`, returned a zero stiffness: they now throw `std::invalid_argument`
(`ValueError` in Python).
- Small code defects without effect on results: `assert(Y_crit(n))` out of bounds in
`Fischer_Burmeister(_limits)` (a Debug build aborted), `variant::build` did not store `g`,
the `state_variables_T` default constructor left `Wm`/`Wm_start` to the Armadillo default,
an unreachable `HfR = 0.5*a2* -a3` branch of the thermomechanical unified_T closest point.
- Copies of `step_meca` / `step_thermomeca` lost their loading: the copy constructor set
`BC_mecas` from `mecas`, the assignment skipped `BC_mecas`, `BC_Ts`, `control_type` and
`tab_data`. The copy operations of `step`, `step_meca` and `step_thermomeca` are now the
memberwise defaults (test `Tstep`). Nothing in simcoon copied a step.
- Under finite strain the solver ran UMEXT as a no-op (unchanged, zero stress) and failed on
UMABA with "Unknown umat name": the plugins are now refused with an explicit error.
- `Eshelby_penny` set the in-plane shear S_2323 (Voigt 23) to 1 and S_1212 to 0: now
S_1212 = S_1313 = 1/2 (1 in engineering Voigt) and S_2323 = 0, the flat oblate limit.
No homogenization scheme called it.
- `d2lagrange_pow_1` placed `p0` wrongly (exact only for p0 = 1); its test now checks it
against a finite difference of `dlagrange_pow_1`. No law called it.
- Documentation: .cpp comments cut to short implementation notes, contracts (props,
statev, theory) moved to the header Doxygen, dead code and wrong `@file` banners removed;
the EPCHA header example read the back-strains as the backstresses (statev 20-31).
- `isochoric_pstretch` ignored `J` on a single point (it recomputed it from the
tensor), unlike its batch form.
- Race on the Eshelby quadrature tables between concurrent solves.
- MIHEN crash (null pointer) and MISCN failure on the second block of a
loading path.
- `n_threads` only took effect for 1 thread: it is now honoured under GCD and
OpenMP, and `Lt_convert` takes it too.

## [2.2.0] - 2026-10-14

Tensor bases (#126, #127, #128), cached rotation operators (#130), Eshelby memo
and lazy fields (#129), closest-point return mapping (#131, #133), Johnson-Cook
(#85), analytic SMA tangents (#136), logarithmic U (#137). See the
[release notes](https://github.com/3MAH/simcoon/releases/tag/2.2.0).

## [2.1.0] - 2026-10-01

See the [release notes](https://github.com/3MAH/simcoon/releases/tag/2.1.0).

## [2.0.1] - 2026-09-09

See the [release notes](https://github.com/3MAH/simcoon/releases/tag/2.0.1).

## [2.0.0] - 2026-09-07

See the [release notes](https://github.com/3MAH/simcoon/releases/tag/2.0.0).

[Unreleased]: https://github.com/3MAH/simcoon/compare/2.2.0...HEAD
[2.2.0]: https://github.com/3MAH/simcoon/compare/2.1.0...2.2.0
[2.1.0]: https://github.com/3MAH/simcoon/compare/2.0.1...2.1.0
[2.0.1]: https://github.com/3MAH/simcoon/compare/2.0.0...2.0.1
[2.0.0]: https://github.com/3MAH/simcoon/compare/2.0.0b1...2.0.0
19 changes: 17 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -371,14 +371,29 @@ if(SIMCOON_BUILD_TESTS)
if(NOT MSVC)
# Fortran is only needed for Abaqus UMAT plugin tests
enable_language(Fortran)
set_source_files_properties(testBin/Umats/UMABA/external/UMAT_ABAQUS_ELASTIC.f PROPERTIES Fortran_PREPROCESS OFF)
add_library(umat_plugin_aba SHARED testBin/Umats/UMABA/external/UMAT_ABAQUS_ELASTIC.f testBin/Umats/UMABA/external/umat_plugin_aba.cpp)
set_source_files_properties(external/UMAT_ABAQUS_ELASTIC.f PROPERTIES Fortran_PREPROCESS OFF)
add_library(umat_plugin_aba SHARED external/UMAT_ABAQUS_ELASTIC.f external/umat_plugin_aba.cpp)
# Use default PREFIX (lib) and SUFFIX (.so on Linux, .dylib on macOS)
# to match dylib::decorations::os_default() expectations
set_target_properties(umat_plugin_aba PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/testBin/Umats/UMABA/external
)
target_link_libraries(umat_plugin_aba PRIVATE simcoon ${ARMADILLO_LIBRARIES})

# Ansys USERMAT plugin, built from the external/ example: TUMABA runs it on the same case
set_source_files_properties(external/USERMAT_ANSYS_ELASTIC.for PROPERTIES Fortran_PREPROCESS OFF)
add_library(umat_plugin_ans SHARED external/USERMAT_ANSYS_ELASTIC.for external/umat_plugin_ans.cpp)
set_target_properties(umat_plugin_ans PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/testBin/Umats/UMABA/external
)
target_link_libraries(umat_plugin_ans PRIVATE simcoon ${ARMADILLO_LIBRARIES})

# the same plugin on a USERMAT that exposes what it receives (TUMANS: data layout)
add_library(umat_plugin_ans_layout SHARED external/umat_plugin_ans.cpp test_extern/Umats/UMANS/usermat_layout.cpp)
set_target_properties(umat_plugin_ans_layout PROPERTIES OUTPUT_NAME umat_plugin_ans
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/testBin/Umats/UMANS/external
)
target_link_libraries(umat_plugin_ans_layout PRIVATE simcoon ${ARMADILLO_LIBRARIES})
endif()

add_library(umat_plugin_ext SHARED
Expand Down
Loading
Loading