Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 4 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,11 @@ jobs:
# scikit-build-core honors CMAKE_ARGS; the compiler-launcher property
# only works with the Ninja generator (ignored by Visual Studio), so
# the MSVC dev env + ninja (installed below) are required for sccache.
$sc = $env:SCCACHE_PATH -replace '\\','/'
"SCCACHE_GHA_ENABLED=true" | Out-File $env:GITHUB_ENV -Append
"CMAKE_ARGS=-DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache" | Out-File $env:GITHUB_ENV -Append
"SCCACHE_IDLE_TIMEOUT=0" | Out-File $env:GITHUB_ENV -Append
"CMAKE_ARGS=-DCMAKE_C_COMPILER_LAUNCHER=$sc -DCMAKE_CXX_COMPILER_LAUNCHER=$sc" | Out-File $env:GITHUB_ENV -Append
"CMAKE_GENERATOR=Ninja" | Out-File $env:GITHUB_ENV -Append

- name: Editable install
run: |
Expand Down
19 changes: 15 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,17 @@ jobs:
if: runner.os == 'Windows'
run: |
pip install ninja
# Absolute launcher path (forward slashes for CMake): the sccache
# action exports SCCACHE_PATH but does NOT put sccache on PATH, and
# msvc-dev-cmd rewrites PATH anyway. Idle timeout 0 keeps the server
# (and its stats) alive across the whole job.
$sc = $env:SCCACHE_PATH -replace '\\','/'
"SCCACHE_GHA_ENABLED=true" | Out-File $env:GITHUB_ENV -Append
"CMAKE_ARGS=-DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache" | Out-File $env:GITHUB_ENV -Append
"SCCACHE_IDLE_TIMEOUT=0" | Out-File $env:GITHUB_ENV -Append
"CMAKE_ARGS=-DCMAKE_C_COMPILER_LAUNCHER=$sc -DCMAKE_CXX_COMPILER_LAUNCHER=$sc" | Out-File $env:GITHUB_ENV -Append
# scikit-build-core only picks Ninja over Visual Studio when ninja is
# importable/visible to the python actually running the build
"CMAKE_GENERATOR=Ninja" | Out-File $env:GITHUB_ENV -Append

- name: Prepare conda environment (Unix)
if: runner.os != 'Windows'
Expand All @@ -88,11 +97,12 @@ jobs:
run: |
cmake -S . -B build -G Ninja `
-DCMAKE_BUILD_TYPE=Release `
-DCMAKE_C_COMPILER_LAUNCHER=sccache `
-DCMAKE_CXX_COMPILER_LAUNCHER=sccache `
-DCMAKE_C_COMPILER_LAUNCHER="$env:SCCACHE_PATH" `
-DCMAKE_CXX_COMPILER_LAUNCHER="$env:SCCACHE_PATH" `
-DCMAKE_INSTALL_PREFIX="$env:CONDA_PREFIX/Library" `
-Wno-dev
cmake --build build
& $env:SCCACHE_PATH --show-stats

- name: Tests (Unix)
if: runner.os != 'Windows'
Expand All @@ -119,8 +129,9 @@ jobs:
- name: Install simcoon Python bindings (Windows)
if: runner.os == 'Windows'
run: |
pip install scikit-build-core pybind11 numpy
pip install scikit-build-core pybind11 numpy ninja
pip install . --no-build-isolation
& $env:SCCACHE_PATH --show-stats

- name: Smoke test simcoon Python (Windows)
if: runner.os == 'Windows'
Expand Down
1 change: 1 addition & 0 deletions docs/simulation/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Simulation
solver.rst
python_solver.rst
umat_catalog.rst
modular_python.rst
umat_tutorial.rst
identification.rst
output.rst
Expand Down
219 changes: 219 additions & 0 deletions docs/simulation/modular_python.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
==========================================
Building materials in Python (``modular``)
==========================================

.. module:: simcoon.modular

The :mod:`simcoon.modular` package is the Python builder for the composable
``MODUL`` engine: a constitutive model is assembled from an **elasticity**
definition plus any combination of **mechanisms** (plasticity,
viscoelasticity, damage), and serialized into the self-describing props
stream that the C++ engine consumes. The same object drives the in-memory
solver, the file solver, or any FEA coupling — see the
:doc:`UMAT catalog <umat_catalog>` for how ``MODUL`` fits among the other
material names. Units are MPa; Voigt order is [11, 22, 33, 12, 13, 23].

Quick start
-----------

.. code-block:: python

from simcoon.modular import (
ModularMaterial, IsotropicElasticity,
Plasticity, VonMisesYield, VoceHardening, ArmstrongFrederickHardening,
)
from simcoon import solver

mat = ModularMaterial(
elasticity=IsotropicElasticity(C1=210000.0, C2=0.3, alpha=1.2e-5,
convention="Enu"),
mechanisms=[
Plasticity(
sigma_Y=300.0,
yield_criterion=VonMisesYield(),
isotropic_hardening=VoceHardening(Q=200.0, b=10.0),
kinematic_hardening=ArmstrongFrederickHardening(C=20000.0, D=100.0),
),
],
)
print(mat.summary())

step = solver.StepMeca(control=['strain'] + ['stress'] * 5,
value=[0.02, 0, 0, 0, 0, 0], ninc=100)
res = solver.solve(step, "MODUL", mat.props, mat.nstatev)

``mat.props`` and ``mat.nstatev`` are all any caller needs — they work
identically with ``material.dat`` files, :func:`simcoon.umat` point
evaluation, micromechanics phase files (``Nellipsoids``/``Nlayers``) and FEA
couplings such as fedoo.

Elasticity
----------

Exactly one elasticity definition per material. The elastic constants are
**ordinal slots** ``C1..Cn`` whose meaning is fixed by the ``convention``
argument (enum, int, or string aliases):

.. list-table::
:header-rows: 1
:widths: 26 34 40

* - Class
- Parameters
- Conventions (string aliases)
* - :class:`IsotropicElasticity`
- ``C1, C2, alpha``
- ``"Enu"`` (C1=E, C2=nu, default), ``"nuE"``, ``"Kmu"``/``"KG"``,
``"muK"``, ``"lambdamu"``, ``"mulambda"``
* - :class:`CubicElasticity`
- ``C1, C2, C3, alpha``
- ``"EnuG"`` (default), ``"Cii"`` (C11, C12, C44)
* - :class:`TransverseIsotropicElasticity`
- ``EL, ET, nuTL, nuTT, GLT, alpha_L, alpha_T, axis``
- ``"EnuG"`` only (axis = isotropy axis, default 3)
* - :class:`OrthotropicElasticity`
- ``C1..C9, alpha1..alpha3``
- ``"EnuG"`` (E1,E2,E3,nu12,nu13,nu23,G12,G13,G23; default), ``"Cii"``

``alpha`` are the thermal-expansion coefficients (per direction where
applicable).

Yield criteria
--------------

Used inside :class:`Plasticity`; the criterion defines the equivalent stress
:math:`\sigma_{eq}` of the yield function
:math:`f = \sigma_{eq}(\boldsymbol{\sigma} - \mathbf{X}) - (\sigma_Y + R(p))`:

.. list-table::
:header-rows: 1
:widths: 28 30 42

* - Class
- Parameters
- Criterion
* - :class:`VonMisesYield`
- —
- :math:`\sqrt{\tfrac{3}{2}\,\mathbf{s}:\mathbf{s}}`
* - :class:`TrescaYield`
- —
- Maximum shear stress
* - :class:`DruckerYield`
- ``b, n``
- Drucker :math:`J_2`–:math:`J_3` criterion
* - :class:`HillYield`
- ``F, G, H, L, M, N``
- Hill 1948 quadratic anisotropy
* - :class:`DFAYield`
- ``F, G, H, L, M, N, K``
- Deshpande–Fleck–Ashby (pressure-sensitive)
* - :class:`AnisotropicYield`
- ``P11, P22, P33, P12, P13, P23, P44, P55, P66``
- Full quadratic form. **P must be an admissible (convex) form**:
symmetric with zero row sums on the normal block — an indefinite P
produces ``sqrt(<0) = NaN``.

Isotropic hardening
-------------------

The isotropic hardening law :math:`R(p)` of the accumulated plastic strain
:math:`p`:

.. list-table::
:header-rows: 1
:widths: 30 24 46

* - Class
- Parameters
- Law
* - :class:`NoIsotropicHardening`
- —
- :math:`R = 0` (perfect plasticity, default)
* - :class:`LinearIsotropicHardening`
- ``H``
- :math:`R = H\,p`
* - :class:`PowerLawHardening`
- ``k, m``
- :math:`R = k\,p^m` — for :math:`m < 1` the singular onset slope is
C\ :sup:`1`-regularized below :math:`p = 10^{-6}` (exact above)
* - :class:`VoceHardening`
- ``Q, b``
- :math:`R = Q\,(1 - e^{-b\,p})`
* - :class:`CombinedVoceHardening`
- ``terms = ((Q_1, b_1), ...)``
- :math:`R = \sum_i Q_i\,(1 - e^{-b_i p})` (standard independent sum —
note this differs from the removed legacy EPCHG coupling, see the
:doc:`catalog <umat_catalog>`)

Kinematic hardening
-------------------

The back stress :math:`\mathbf{X}` shifting the yield surface. The stored
internal variable is the **back-strain** :math:`\boldsymbol{\alpha}`
(thermodynamic variable); :math:`\mathbf{X} = \tfrac{2}{3} C \boldsymbol{\alpha}`:

.. list-table::
:header-rows: 1
:widths: 32 26 42

* - Class
- Parameters
- Law
* - :class:`NoKinematicHardening`
- —
- :math:`\mathbf{X} = 0` (default)
* - :class:`PragerHardening`
- ``C``
- Linear: :math:`\dot{\boldsymbol{\alpha}} = \dot{p}\,\mathbf{n}`
* - :class:`ArmstrongFrederickHardening`
- ``C, D``
- :math:`\dot{\mathbf{X}} = \tfrac{2}{3}C\,\dot{\boldsymbol{\varepsilon}}^p - D\,\mathbf{X}\dot{p}`
* - :class:`ChabocheHardening`
- ``terms = ((C_1, D_1), ...)``
- :math:`\mathbf{X} = \sum_i \mathbf{X}_i`, each branch
Armstrong–Frederick

Mechanisms
----------

.. list-table::
:header-rows: 1
:widths: 26 40 34

* - Class
- Parameters
- Physics
* - :class:`Plasticity`
- ``sigma_Y, yield_criterion, isotropic_hardening, kinematic_hardening``
- Rate-independent plasticity (Fischer–Burmeister return mapping)
* - :class:`Viscoelasticity`
- ``terms = ((E_i, nu_i, etaB_i, etaS_i), ...)``
- Generalized Maxwell (Prony) branches: per branch a spring
(:math:`E_i, \nu_i`) in series with bulk/shear dashpots
(:math:`\eta_B, \eta_S`) — same rheology and layout as the kept
``PRONK`` kernel
* - :class:`Damage`
- ``Y_0, Y_c, damage_type, A, n``
- Scalar stiffness-degradation damage; ``damage_type`` selects the
evolution law: ``LINEAR``, ``EXPONENTIAL``, ``POWER_LAW`` (uses
``A, n``) or ``WEIBULL``

Multiple mechanisms compose additively on the inelastic strain; the
registration order defines the statev layout (see the
:doc:`catalog <umat_catalog>` statev section).

Tangent operator and finite strain
----------------------------------

``MODUL`` honors the solver's ``tangent_mode`` (continuum or algorithmic,
algorithmic being the 2.0 default — :doc:`solver`). Under the finite-strain
control types the composition acts as a Hencky hyperelastic law on the
logarithmic strain and requires ``corate_type = 3`` (log_R).

See also
--------

- :doc:`umat_catalog` — where ``MODUL`` and the adapter-served legacy names
meet, props streams and statev layouts
- :doc:`umat_tutorial` — writing a dedicated UMAT by hand instead
- ``examples/mechanical/MODUL.py`` — runnable gallery example
Loading