Lab#

Define Experiments and Simulations in the Lab and perform a Curve-Fit to optimize material parameters.

Attention

This section is under construction 🚧.

class hyperelastic.lab.Biaxial(label=None)[source]#

Incompressible biaxial tension/compression load case.

(1)#\[\boldsymbol{F} = \text{diag} \left(\begin{bmatrix} \lambda & \lambda & \frac{1}{\lambda^2} \end{bmatrix} \right)\]
defgrad(stretch)[source]#

Return the Deformation Gradient tensor from given stretches.

stress(F, P, axis=0, traction_free=-1)#

Normal force per undeformed area for a given deformation gradient of an incompressible deformation and the first Piola-Kirchhoff stress tensor.

Parameters:
  • F (ndarray) – The deformation gradient.

  • P (ndarray) – The first Piola-Kirchhoff stress tensor.

  • axis (int, optional) – The primary axis where the longitudinal stretch is applied on (default is 0).

  • traction_free (int, optional) – The secondary axis where the traction-free transverse stretch results from the constraint of incompressibility (default is -1).

Returns:

The one-dimensional normal force per undeformed area.

Return type:

ndarray

class hyperelastic.lab.Experiment(label, displacement, force, area=1.0, length=1.0, time=None, temperature=None)[source]#

Results of an experiment along with methods to convert and plot the data.

label#

The title of the experiment.

Type:

str

displacement#

The measured or applied displacement data.

Type:

array_like

force#

The measured or applied force data.

Type:

array_like

area#

The undeformed reference cross-sectional area used to evaluate the stress.

Type:

float

length#

The undeformed reference length used to evaluate the stretch.

Type:

float

time#

The timetrack of the measurement.

Type:

array_like or None

temperature#

The measured or applied temperature data.

Type:

array_like or None

stretch#

The stretch as the calculated ratio of the deformed vs. the undeformed length.

Type:

array_like

plot_force_displacement(*args, xlabel='Displacement $d$', ylabel='Force $F$', ax=None, label=None, **kwargs)#

Create a force-displacement plot.

plot_stress_stretch(*args, ax=None, xlabel='Stretch $l/L$', ylabel='Force per undeformed area $F/A$', label=None, **kwargs)#

Create a stress-stretch plot.

stress()[source]#

Evaluate the stress as force per undeformed area.

class hyperelastic.lab.IncompressibleHomogeneousStretch[source]#

An incompressible homogeneous stretch load case with a longitudinal stretch and perpendicular transverse stretches in principal directions. This class is intended to be subclassed by another class with a .defgrad() method for the evaluation of the deformation gradient as utilized by the Uniaxial, Planar and Biaxial load cases.

Notes

The Cauchy stress for an incompressible material is given by

(2)#\[\boldsymbol{\sigma} = \boldsymbol{\sigma}' + p \boldsymbol{I}\]

where the Cauchy stress is converted to the first Piola-Kirchhoff stress tensor.

(3)#\[\boldsymbol{P} = J \boldsymbol{\sigma} \boldsymbol{F}^{-T}\]

The deformation gradient and its determinant are evaluated for the homogeneous incompressible deformation.

(4)#\[ \begin{align}\begin{aligned}\boldsymbol{F} &= \text{diag} \left(\begin{bmatrix} \lambda_1 & \lambda_2 & \lambda_3 \end{bmatrix} \right)\\J &= \lambda_1 \lambda_2 \lambda_3 = 1\end{aligned}\end{align} \]

This enables the evaluation of the normal force per undeformed area, where quantities in the traction-free transverse direction are denoted with a subscript \((\bullet)_t\).

(5)#\[\frac{N}{A} = P - P_t \frac{\lambda_t}{\lambda}\]
stress(F, P, axis=0, traction_free=-1)[source]#

Normal force per undeformed area for a given deformation gradient of an incompressible deformation and the first Piola-Kirchhoff stress tensor.

Parameters:
  • F (ndarray) – The deformation gradient.

  • P (ndarray) – The first Piola-Kirchhoff stress tensor.

  • axis (int, optional) – The primary axis where the longitudinal stretch is applied on (default is 0).

  • traction_free (int, optional) – The secondary axis where the traction-free transverse stretch results from the constraint of incompressibility (default is -1).

Returns:

The one-dimensional normal force per undeformed area.

Return type:

ndarray

class hyperelastic.lab.Optimize(experiments, simulations, parameters, mask=None)[source]#

Take lists of experiments and simulations and find material parameters for the simulation model to obtain a best possible representation of the experiments by the simulations.

experiments#

A list of Experiment.

Type:

list

simulations#

A list of Simulation.

Type:

list

parameters#

The material parameters.

Type:

array_like

mask#

A list of masks to take the optimization-relevant data points.

Type:

list of array_like

Examples

Three different test specimens are subjected to displacement-controlled uniaxial, planar and biaxial tension. The applied displacement and reaction force data is used to create the Experiments. The test specimen for the uniaxial load case has a cross-sectional area of \(A=25~\text{mm}^2\) and a length of \(L=100~\text{mm}\).

>>> area = 25
>>> length = 100

Some synthetic experimental data is generated to demonstrate the capabilities of the optimization.

>>> import numpy as np
>>> displacement = np.linspace(0, 2 * length, 100)
>>> stretch = 1 + displacement / length
>>> force = (stretch - 1 / stretch ** 2 + (stretch - 1)**5 / 10) * area

With this reference experimental data at hand, the list of experiments is created. In this example, the displacement and force data as well as the cross-sectional area are scaled from the synthetic uniaxial experimental data to the other (synthetic) experiments.

>>> from hyperelastic import lab
>>> experiments = [
>>>     lab.Experiment(
>>>         label="Uniaxial Tension",
>>>         displacement=displacement,
>>>         force=force,
>>>         area=area,
>>>         length=length,
>>>     ),
>>>     lab.Experiment(
>>>         label="Planar Tension",
>>>         displacement=displacement[::2],
>>>         force=force[::2],
>>>         area=area / (8 / 7),
>>>         length=length,
>>>     ),
>>>     lab.Experiment(
>>>         label="Biaxial Tension",
>>>         displacement=displacement[::2] / 2,
>>>         force=force[::2],
>>>         area=area / (4 / 5),
>>>         length=length,
>>>     ),
>>> ]

A function which takes the material parameters and returns the hyperelastic constitutive material formulation has to be provided for the simulation objects. Here, we use an isotropic invariant-based third-order deformation material formulation.

>>> def material(**kwargs):
>>>     "A third-order deformation material formulation."
>>>
>>>     tod = hyperelastic.models.invariants.ThirdOrderDeformation(**kwargs)
>>>     framework = hyperelastic.InvariantsFramework(tod)
>>>
>>>     return hyperelastic.DeformationSpace(framework)

The list of labels of the material parameters is used for all simulation objects.

>>> labels = ["C10", "C01", "C11", "C20", "C30"]

Next, the simulations for all three loadcases are created. It is important to take the stretches from the according experiments.

>>> simulations = [
>>>     lab.Simulation(
>>>         loadcase=lab.Uniaxial(),
>>>         stretch=experiments[0].stretch,
>>>         material=material,
>>>         labels=labels,
>>>     ),
>>>     lab.Simulation(
>>>         loadcase=lab.Planar(),
>>>         stretch=experiments[1].stretch,
>>>         material=material,
>>>         labels=labels,
>>>     ),
>>>     lab.Simulation(
>>>         loadcase=lab.Biaxial(),
>>>         stretch=experiments[2].stretch,
>>>         material=material,
>>>         labels=labels,
>>>     ),
>>> ]

Both the list of experiments and the list of simulations are passed to Optimize, where its curve-fit method acts as a simple wrapper for scipy.optimize.curve_fit. The initial material parameters are all set to one.

>>> optimize = lab.Optimize(
>>>     experiments=experiments,
>>>     simulations=simulations,
>>>     parameters=np.ones(5),
>>> )
>>> parameters, pcov = optimize.curve_fit(method="lm")
>>> parameters
array([ 0.50430357, -0.01413309,  0.0141219 , -0.01641752,  0.00492179])
>>> fig, ax = optimize.plot(title="Third-Order Deformation")
../_images/fig_optimize-tod.png
curve_fit(*args, **kwargs)[source]#

Use non-linear least squares to fit a list of functions to a list of data.

init_curve_fit(*args, **kwargs)[source]#
mean_relative_std()[source]#

Return the relative mean of the standard deviations of the material parameters, normalized by the absolute mean-values of the parameters.

norm_residuals()[source]#

Return the norm of the residuals.

plot(title=None)[source]#
class hyperelastic.lab.Planar(label=None)[source]#

Incompressible planar (shear) tension/compression load case.

(6)#\[\boldsymbol{F} = \text{diag} \left(\begin{bmatrix} \lambda & 1 & \frac{1}{\lambda} \end{bmatrix} \right)\]
defgrad(stretch)[source]#

Return the Deformation Gradient tensor from given stretches.

stress(F, P, axis=0, traction_free=-1)#

Normal force per undeformed area for a given deformation gradient of an incompressible deformation and the first Piola-Kirchhoff stress tensor.

Parameters:
  • F (ndarray) – The deformation gradient.

  • P (ndarray) – The first Piola-Kirchhoff stress tensor.

  • axis (int, optional) – The primary axis where the longitudinal stretch is applied on (default is 0).

  • traction_free (int, optional) – The secondary axis where the traction-free transverse stretch results from the constraint of incompressibility (default is -1).

Returns:

The one-dimensional normal force per undeformed area.

Return type:

ndarray

class hyperelastic.lab.Simulation(loadcase, stretch, labels, material, parameters=None)[source]#

Results of a simulation along with methods to convert and plot the data.

loadcase#

A class with methods for evaluating the deformation gradient and the stress as normal force per undeformed area, e.g. Uniaxial.

Type:

class

stretch#

The stretch as the ratio of the deformed vs. the undeformed length.

Type:

ndarray

labels#

A list of the material parameter labels.

Type:

list of str

material#

A class with a method for evaluating the gradient of the strain energy function w.r.t. the deformation gradient, e.g. DistortionalSpace.

Type:

class

parameters#

The material parameters.

Type:

array_like

Examples

The material model response behaviour of a hyperelastic material model formulation is evaluated for a uniaxial tension load case. A given stretch data is used to create the Simulation object.

>>> import numpy as np
>>> import hyperelastic
>>> from hyperelastic import lab
>>>
>>> stretch = np.linspace(0.7, 2.5, 181)

A function which takes the material parameters and returns the hyperelastic constitutive material formulation has to be provided for the simulation objects. Here, we use an isotropic invariant-based third-order deformation material formulation.

>>> def material(**kwargs):
>>>     "A third-order deformation material formulation."
>>>
>>>     tod = hyperelastic.models.invariants.ThirdOrderDeformation(**kwargs)
>>>     framework = hyperelastic.InvariantsFramework(tod)
>>>
>>>     return hyperelastic.DeformationSpace(framework)

A list of (string) labels is used to apply the list or array of parameter values to the material formulation.

>>> simulation = lab.Simulation(
>>>     loadcase=lab.Uniaxial(),
>>>     stretch=stretch,
>>>     material=material,
>>>     labels=["C10", "C01", "C11", "C20", "C30"],
>>>     parameters=[0.4, 0.1, 0.02, -0.04, 0.01],
>>> )

The stress-stretch plot returns a figure which visualizes the force per undeformed area vs. the ratio of the undeformed and deformed length.

>>> fig, ax = simulation.plot_stress_stretch()
>>>
>>> ax.legend()
>>> ax.set_title("Third-Order Deformation")
../_images/fig_simulation-tod.png
plot_force_displacement(*args, xlabel='Displacement $d$', ylabel='Force $F$', ax=None, label=None, **kwargs)#

Create a force-displacement plot.

plot_stress_stretch(*args, ax=None, xlabel='Stretch $l/L$', ylabel='Force per undeformed area $F/A$', label=None, **kwargs)#

Create a stress-stretch plot.

stress()[source]#

Evaluate the stress as force per undeformed area.

stress_curve_fit(x, *parameters)[source]#

Evaluate the stress as force per undeformed area for given material parameters.

class hyperelastic.lab.Uniaxial(label=None)[source]#

Incompressible uniaxial tension/compression load case.

(7)#\[\boldsymbol{F} = \text{diag} \left(\begin{bmatrix} \lambda & \frac{1}{\sqrt{\lambda}} & \frac{1}{\sqrt{\lambda}} \end{bmatrix} \right)\]
defgrad(stretch)[source]#

Return the Deformation Gradient tensor from given stretches.

stress(F, P, axis=0, traction_free=-1)#

Normal force per undeformed area for a given deformation gradient of an incompressible deformation and the first Piola-Kirchhoff stress tensor.

Parameters:
  • F (ndarray) – The deformation gradient.

  • P (ndarray) – The first Piola-Kirchhoff stress tensor.

  • axis (int, optional) – The primary axis where the longitudinal stretch is applied on (default is 0).

  • traction_free (int, optional) – The secondary axis where the traction-free transverse stretch results from the constraint of incompressibility (default is -1).

Returns:

The one-dimensional normal force per undeformed area.

Return type:

ndarray