-
Notifications
You must be signed in to change notification settings - Fork 21
Constitutive Models
Hyperelastic material models often rely upon the strain energy density function W formulated in terms of strain invariants. Under the assumption of an isotropic incompressible behavior of the material under uniaxial loading, the principal Cauchy stress constitutive models as a function of invariants yields:
where, the Cauchy-Green invariants I1 and I2, are in this particular case a function of the stretch lambda:
For the case of an incompressible Mooney–Rivlin material under uniaxial elongation,
Where,
With the initial shear modulus:
The Neo-Hookean model is a simple model that is typically only accurate for strains less than 20%.
Where,
With the initial shear modulus:
The Mooney-Rivlin material law is typically accurate for strains up to 100%
def MooneyRivlinModel(cVec, Strain, order, data_type):
"""Mooney Rivlin hyperelastic model (incompressible material under uniaxial tension)"""
# cVec = [C10,C01,C20]
cVec = np.append(cVec, np.zeros(3-order) ) #To ensure CXX is zero if unsed
C10 = cVec[0]
C01 = cVec[1]
C20 = cVec[2]
if data_type == 'True':
lambd = np.exp(Strain) # lambd i.e lambda
Stress = 2*(lambd**2 - 1/lambd)*(C10 + C01/lambd + 2*C20*(lambd**2 + 2/lambd -3))
elif data_type == 'Engineering':
lambd = 1 + Strain
Stress = 2*(lambd - 1/lambd**2)*(C10 + C01/lambd + 2*C20*(lambd**2 + 2/lambd -3))
else:
print("Data type error. Data is neither 'True' or 'Engineering'. ")
return StressUnder the assumption of an incompressible material under uniaxial tension [2]:
For material stability, it is required that each material constant pair :
import numpy as np
class Hyperelastic:
def __init__(self, model, parameters, order, data_type):
self.model = model
self.order = order
self.parameters = parameters
self.param_names = []
self.data_type = data_type
self.fitting_method = 'lm'
if model == 'Ogden':
initialGuessMu = np.array([1.0]*self.order)
initialGuessAlpha = np.array([1.0]*self.order)
self.initialGuessParam = np.append(initialGuessMu,initialGuessAlpha)
self.nbparam = self.order*2
muVec_names = ["µ1","µ2","µ3"][0:self.order]
alphaVec_names = ["α1","α2","α3"][0:self.order]
self.param_names = np.append(muVec_names,alphaVec_names)
self.fitting_method = 'trust-constr'
elif model == 'Yeoh':
self.initialGuessParam = np.array([0.1]*self.order)
self.nbparam = self.order
self.param_names = ["C1","C2","C3"][0:self.order]
self.fitting_method = 'lm'
else:
print("Error")
def OgdenModel(self, parameters, Strain):
"""Ogden hyperelastic model (incompressible material under uniaxial tension)"""
# parameter is a 1D array : [mu0,mu1,...,mun,alpha0,alpha1,...,alphan]
muVec = parameters[0:self.order] # [mu0,mu1,...,mun]
alphaVec = parameters[self.order:] # [alpha0,alpha1,...,alphan]
if self.data_type == 'True':
lambd = np.exp(Strain) # lambd i.e lambda
elif self.data_type == 'Engineering':
lambd = 1 + Strain
else:
print("Data type error. Data is neither 'True' or 'Engineering'. ")
# broadcasting method to speed up computation
lambd = lambd[np.newaxis, :]
muVec = muVec[:self.order, np.newaxis]
alphaVec = alphaVec[:self.order, np.newaxis]
if self.data_type == 'True':
Stress = np.sum(muVec*(lambd**alphaVec - 1/(lambd**(alphaVec/2))), axis=0)
elif self.data_type == 'Engineering':
Stress = np.sum((muVec*(lambd**alphaVec - 1/(lambd**(alphaVec/2)))/lambd), axis=0)
return StressThe Mooney Rivlin model requires the following linear constraints for initial shear modulus:
The constraints
and defined using a LinearConstraint object.
from scipy.optimize import LinearConstraint
linear_constraint = LinearConstraint([[1, 1], [0, 0]], [0, 0], [np.inf, np.inf])The Ogden model requires the following non linear constraints for material stability :
We use the trust-region constrained method to deal with constrained minimization problems. The minimize from _scipy.optimize.minimize_function provides algorithms for constrained minimization, namely 'trust-constr'. The method 'trust-constr' requires the constraints to be defined as a sequence of objects LinearConstraint and NonlinearConstraint.
The nonlinear constraint:
with Jacobian matrix:
is defined using a NonlinearConstraint object.
# x = [mu1, mu2, mu3, alpha1, alpha2, alpha3]
def cons_f(x):
return [x[0]*x[3], x[1]*x[4], x[2]*x[5]]
def cons_J(x):
return [[x[3], 0, 0, x[0], 0, 0], [0, x[4], 0, 0, x[1], 0], [0, 0, x[5], 0, 0, x[2]]]
from scipy.optimize import NonlinearConstraint
nonlinear_constraint = NonlinearConstraint(cons_f, 0, np.inf, jac=cons_J)import numpy as np
import matplotlib as plt
from Hyperelastic import Hyperelastic
# Hyperelastic object
hyperelastic = Hyperelastic('Ogden', np.array([0]), 3, 'True') # Instantiate an Hyperalastic object : Ogden model of order 3 using True data type
model_param = np.array([0.354, -0.129, -0.226, 3.316, 3.278, 3.278]) # [mu1, mu2, mu3, alpha1, alpha2, alpha3]
trueStrain = linspace(0, 1.5, 50)
trueStress = hyperelastic.ConsitutiveModel(model_param, trueStrain)
plt.plot(trueStrain, trueStress, 'r')
plt.xlabel('True Strain')
plt.ylabel('True Stress (MPa)')
plt.grid('on')
plt.show()
With the initial shear modulus:
def YeohModel(self, cVec, Strain):
"""Yeoh hyperelastic model (incompressible material under uniaxial tension)"""
if self.data_type == 'True':
lambd = np.exp(Strain)
elif self.data_type == 'Engineering':
lambd = 1 + Strain
else:
print("Data type error. Data is neither 'True' or 'Engineering'. ")
I1 = lambd**2 + 2/lambd
Stress = np.zeros((self.order,len(Strain)))
for i in range (0,self.order):
if self.data_type == 'True':
Stress[i,:] = 2*(lambd**2 - 1/lambd)*(i+1)*cVec[i]*((I1-3)**(i)) # true
elif self.data_type == 'Engineering':
Stress[i,:] = (2*(lambd - 1/(lambd**2))*(i+1)*cVec[i]*(I1-3)**(i))/lambd # eng
else:
print("Data type error. Data is neither 'True' or 'Engineering'. ")
Stress_sum = np.sum(Stress, axis=0)
return Stress_sumimport numpy as np
import matplotlib as plt
from Hyperelastic import Hyperelastic
# Hyperelastic object
hyperelastic = Hyperelastic('Yeoh', np.array([0]), 2, 'Engineering') # Instantiate an Hyperalastic object : Yeoh model of order 2 using Engineering data type
model_param = np.array([3.278, 0.384]) # [C1, C2]
engStrain = linspace(0, 1.5, 50)
engStress = hyperelastic.ConsitutiveModel(model_param, engStrain)
plt.plot(engStrain, engStress, 'r')
plt.xlabel('Engineering Strain')
plt.ylabel('Engineering Stress (MPa)')
plt.grid('on')
plt.show() [1] Rivlin, R. S., Large elastic deformations of isotropic materials. IV. Further developments of the general theory, Philosophical Transactions of the Royal Society of London. Series A, Mathematical and Physical Sciences, 241(835), 1948. pp. 379–397.
[2] Ogden RW, Saccomandi G, Sgura I. Fitting hyperelastic models to experimental data. Computational Mechanics. 2004 nov;34(6):484–502.
[3] Yeoh, O. H., Some forms of the strain energy function for rubber, Rubber Chemistry and technology, Volume 66, Issue 5, November 1993, Pages 754-771.
[3] Martins PALS, Natal Jorge RM, Ferreira AJM. A Comparative Study of Several Material Models for Prediction of Hyperelastic Properties: Application to Silicone-Rubber and Soft Tissues. Strain. 2006;42(3):135–147.
[4] Rackl M. Material testing and hyperelastic material model curve fitting for Ogden, Polynomial and Yeoh models. In: ScilabTEC (7th International Scilab Users Confer ence). Paris; 2015.
[5] Bergström J. Elasticity/Hyperelasticity. In: Mechanics of Solid Polymers: Theory and Computational Modeling. William Andrew Publishing; 2015. p.209–307.