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)\]- 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.
- 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
andBiaxial
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 forscipy.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")
- curve_fit(*args, **kwargs)[source]#
Use non-linear least squares to fit a list of functions to a list of data.
- 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)\]- 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 theSimulation
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")
- 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.
- 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)\]- 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