Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the MORPH material model formulation #771

Merged
merged 3 commits into from
May 14, 2024
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file. The format
- Add an optional relative-residuals argument to `ConstitutiveMaterial.optimize(relative=False)`.
- Add a class-decorator `constitutive_material(Msterial, name=None)`.
- Add the MORPH material formulation implemented by the concept of representative directions `morph_representative_directions(p)` to be used in `Hyperelastic()`.
- Add the MORPH material formulation `morph(p)` to be used in `Hyperelastic()`.

### Changed
- Recfactor the `constitution` module.
Expand Down
3 changes: 3 additions & 0 deletions docs/felupe/constitution.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ There are many different pre-defined constitutive material formulations availabl
finite_strain_viscoelastic
miehe_goektepe_lulei
mooney_rivlin
morph
morph_representative_directions
neo_hooke
ogden
Expand Down Expand Up @@ -229,6 +230,8 @@ There are many different pre-defined constitutive material formulations availabl

.. autofunction:: felupe.mooney_rivlin

.. autofunction:: felupe.morph

.. autofunction:: felupe.morph_representative_directions

.. autofunction:: felupe.neo_hooke
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ dynamic = ["version"]
dependencies = [
"numpy",
"scipy",
"tensortrax",
"tensortrax>=0.21.1",
]

[project.optional-dependencies]
Expand Down
2 changes: 2 additions & 0 deletions src/felupe/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
linear_elastic_plastic_isotropic_hardening,
miehe_goektepe_lulei,
mooney_rivlin,
morph,
morph_representative_directions,
neo_hooke,
ogden,
Expand Down Expand Up @@ -188,6 +189,7 @@
"isochoric_volumetric_split",
"miehe_goektepe_lulei",
"mooney_rivlin",
"morph",
"morph_representative_directions",
"neo_hooke",
"ogden",
Expand Down
2 changes: 2 additions & 0 deletions src/felupe/constitution/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
isochoric_volumetric_split,
miehe_goektepe_lulei,
mooney_rivlin,
morph,
morph_representative_directions,
neo_hooke,
ogden,
Expand Down Expand Up @@ -52,6 +53,7 @@
"isochoric_volumetric_split",
"miehe_goektepe_lulei",
"mooney_rivlin",
"morph",
"morph_representative_directions",
"neo_hooke",
"ogden",
Expand Down
3 changes: 2 additions & 1 deletion src/felupe/constitution/hyperelasticity/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from ._helpers import isochoric_volumetric_split
from ._miehe_goektepe_lulei import miehe_goektepe_lulei
from ._mooney_rivlin import mooney_rivlin
from ._morph import morph_representative_directions
from ._morph import morph, morph_representative_directions
from ._neo_hooke import neo_hooke
from ._ogden import ogden
from ._ogden_roxburgh import ogden_roxburgh
Expand All @@ -33,6 +33,7 @@
"isochoric_volumetric_split",
"miehe_goektepe_lulei",
"mooney_rivlin",
"morph",
"morph_representative_directions",
"neo_hooke",
"ogden",
Expand Down
114 changes: 112 additions & 2 deletions src/felupe/constitution/hyperelasticity/models/_morph.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,118 @@
along with FElupe. If not, see <http://www.gnu.org/licenses/>.
"""
from .microsphere import affine_stretch_statevars
from tensortrax.math import array, abs as tensor_abs, maximum, sqrt, exp
from tensortrax.math.special import try_stack
from tensortrax.math import (
array,
abs as tensor_abs,
maximum,
sqrt,
exp,
if_else,
real_to_dual,
)
from tensortrax.math.special import try_stack, from_triu_1d, triu_1d, sym, dev, ddot
from tensortrax.math.linalg import det, inv, eigvalsh, expm


def morph(C, statevars, p):
"""Strain energy function of the
`MORPH <https://doi.org/10.1016/s0749-6419(02)00091-8>`_ model formulation [1]_.

Parameters
----------
C : tensortrax.Tensor
Right Cauchy-Green deformation tensor.
statevars : array
Vector of stacked state variables (CTS, C, SA).
p : list of float
A list which contains the 8 material parameters.

Examples
--------
.. pyvista-plot::
:context:

>>> import felupe as fem
>>>
>>> umat = fem.Hyperelastic(
... fem.morph,
... p=[0.039, 0.371, 0.174, 2.41, 0.0094, 6.84, 5.65, 0.244],
... nstatevars=13,
... )
>>> ax = umat.plot(
... incompressible=True,
... ux=fem.math.linsteps(
... [1, 2, 1, 2.75, 1, 3.5, 1, 4.2, 1, 4.8, 1, 4.8, 1],
... num=50,
... ),
... ps=None,
... bx=None,
... )

.. pyvista-plot::
:include-source: False
:context:
:force_static:

>>> import pyvista as pv
>>>
>>> fig = ax.get_figure()
>>> chart = pv.ChartMPL(fig)
>>> chart.show()

References
----------
.. [1] D. Besdo and J. Ihlemann, "A phenomenological constitutive model for
rubberlike materials and its numerical applications", International Journal
of Plasticity, vol. 19, no. 7. Elsevier BV, pp. 1019–1036, Jul. 2003. doi:
`10.1016/s0749-6419(02)00091-8 <https://doi.org/10.1016/s0749-6419(02)00091-8>`_.
"""

# extract old state variables
CTSn = array(statevars[0], like=C[0, 0])
Cn = from_triu_1d(statevars[1:7], like=C)
SAn = from_triu_1d(statevars[7:], like=C)

# distortional part of right Cauchy-Green deformation tensor
I3 = det(C)
CG = C * I3 ** (-1 / 3)

# inverse of and incremental right Cauchy-Green deformation tensor
invC = inv(C)
dC = C - Cn

# eigenvalues of right Cauchy-Green deformation tensor (sorted in ascending order)
λCG = eigvalsh(CG)

# Tresca invariant of distortional part of right Cauchy-Green deformation tensor
CTG = λCG[-1] - λCG[0]

# maximum Tresca invariant in load history
CTS = maximum(CTG, CTSn)

def sigmoid(x):
"Algebraic sigmoid function."
return 1 / sqrt(1 + x**2)

# material parameters
α = p[0] + p[1] * sigmoid(p[2] * CTS)
β = p[3] * sigmoid(p[2] * CTS)
γ = p[4] * CTS * (1 - sigmoid(CTS / p[5]))

LG = sym(dev(invC @ dC)) @ CG
λLG = eigvalsh(LG)
LTG = λLG[-1] - λLG[0]
LG_LTG = if_else(LTG > 0, LG / LTG, LG)

# limiting stresses "L" and additional stresses "A"
SL = (γ * expm(p[6] * LG_LTG * CTG / CTS) + p[7] * LG_LTG) @ invC
SA = (SAn + β * LTG * SL) / (1 + β * LTG)

# second Piola-Kirchhoff stress tensor
dψdC = α * dev(CG) @ invC + dev(SA @ C) @ invC / 2
statevars_new = try_stack([[CTS], triu_1d(C), triu_1d(SA)], fallback=statevars)

return real_to_dual(dψdC, C, mul=ddot), statevars_new


def morph_representative_directions(C, statevars, p, ε=1e-8):
Expand Down
7 changes: 7 additions & 0 deletions tests/test_constitution.py
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,13 @@ def test_umat_hyperelastic_statevars():
),
True,
),
(
fem.constitution.morph,
dict(
p=[0.039, 0.371, 0.174, 2.41, 0.0094, 6.84, 5.65, 0.244], nstatevars=13
),
True,
),
]:
umat = fem.Hyperelastic(model, **kwargs)

Expand Down
Loading