Skip to content

3. Creating material models in Florence

Roman edited this page Jun 30, 2023 · 13 revisions

In this section, we will have a look at how to define material models in Florence. One of the core features of Florence is in its large amount of predefined material models for different types of variational formulations, as all analyses in Florence require defining a material model, even solving a Poisson equation. These set of material models are extremely high performant as they are implemented on the fly using the SIMD based tensor contraction framework Fastor. Fastor can generate the Hessian/tangent operators and gradients of different types of materials by employing FLOP reduction algorithm to determine the least amount of FLOP count for a given constitutive law and then produce data parallel SIMD code for them targeting all types of modern heterogeneous architectures.

a) Defining material models for electrostatic/Poisson type problems

To define an anisotropic material for Poisson type problems, i.e. anisotropic Poisson equation we can for instance do

material = AnisotropicIdealDielectric(ndim, e=np.eye(ndim))

All material models need to know about the dimension of the problem that you are solving as they need to generate the right tangent operator/Hessian and work/energy conjugates. The parameter e in this case is the anisotropic matrix defining the the material constants for instance the anisotropic permittivity tensor in case of electrostatics. For standard Possion type problems the material model can be defined as

material = IdealDielectric(ndim, eps=1.)

b) Defining linear elastic material models

The linear elastic material model can be defined as

material = LinearElastic(ndim, youngs_modulus=1e9, poisson_ratio=0.32)

or alternatively, using Lame constants

material = LinearElastic(ndim, mu=5e8, lamb=1e9)

Note that, Florence strictly disallows using LinearElastic model with multiple load increments for quasi-static analyses, as solving a linear elastic problem in multiple step can just be done using linear superposition. In cases where there are prestresses in the material or the residual changes due to other external reasons, the equivalent IncremrentalLinearElastic model can be used instead, which behaves just like LinearElastic model but allows prestressed/non-zero residual state and also supports load increments.

material = IncremrentalLinearElastic(ndim, youngs_modulus=1e9, poisson_ratio=0.32)

Transversely isotropic and anisotropic linear elastic models are also available

material = TranservselyIsotropicLinearElastic(ndim, 
                       youngs_modulus=1e9, 
                       poisson_ratio=0.32,
                       E_A=1e5,  # out of plane Young's modulus
                       G_A=5e4,  # out of plane shear modulus 
           )

c) Defining nonlinear hyperelastic material models

A suite of nonlinear hyperelastic material models are available

material = NeoHookean(ndim, mu=5e8, lamb=1e9) # or
material = NeoHookean(ndim, youngs_modulus=1e9, poisson_ratio=0.4)
material = RegularisedNeoHookean(ndim, lamb=1e9, mu=5e8)
material = CoerciveNeoHookean(ndim, lamb=1e9, mu=5e8)
material = MooneyRivlin(ndim, mu1=1e8, mu2=1e8, lamb=1e9)

Generic anisotropic hyperelastic material models are available as well

material = TranservselyIsotropicHyperElastic(ndim,
                       youngs_modulus=1e9, 
                       poisson_ratio=0.32,
                       E_A=1e5,  # out of plane Young's modulus
                       anisotropic_orientations=numpy.random.rand(mesh.nelem,ndim)
           )

where anisotropic_orientations is the vector of anisotropy that is defined for every element of the computational mesh

d) Defining nonlinear electro-hyperelastic material models

A suite of nonlinear electro-hyperelastic material models are available

material = IsotropicElectroMechanics_101(ndim, mu=5e8, lamb=1e9, eps_1=2e-11) # NeoHookean based
material = IsotropicElectroMechanics_108(ndim, mu1=5e8, mu2=5e8, lamb=1e9, eps_2=2e-11) # MooneyRivlin based
material = IsotropicElectroMechanics_107(ndim, mu1=5e8, mu2=5e8, mue=1e7, lamb=1e9, 
                                         eps_1=1e-11, eps_2=2e-11, eps_e=1e-13) 

Generic anisotropic/piezoelectric hyperelastic material models are available as well

material = Piezoelectric_100(ndim, mu1=5e8, mu2=5e8, mu3=1e7, lamb=1e9, 
                                     eps_1=1e-11, eps_2=2e-11, eps_3=1e-13,
                                     anisotropic_orientations=numpy.random.rand(mesh.nelem,ndim))

where anisotropic_orientations is the vector of anisotropy that is defined for every element of the computational mesh

To check the corresponding energy of any material or constitutive law, in the ipython shell you can do:

In [0]: IsotropicElectroMechanics_107?
Out[0]: 
    """Electromechanical model in terms of internal energy 
        
            W(C,D0) = W_mn(C) + 1/2/eps_1 (D0*D0) + 1/2/eps_2/J (FD0*FD0) + W_reg(C,D0)
            W_mn(C) = u1*C:I+u2*G:I - 2*(u1+2*u2+6*mue)*lnJ + lamb/2*(J-1)**2 + mue*(C:I)**2
            W_reg(C,D_0) = 2/eps_e/mue (F:F)(FD0*FD0) + 1/mu/eps_e**2*(FD0*FD0)**2
    """

which explains all the material constants used and their energy form.

e) User defined material models and automatic linearisation

Support for user defined materials is limited at the moment, but will be incorporated into Florence soon, as this is a high priority. In essence, Florence, using Fastor backend should be able to generate optimised low level code for the tangent operator of any given energy and consistently linearise any complex expression on the fly. The user only has to supply the energy form and related parameters as a dictionary, like so:

user_material_context = Material()
user_material_context.Linearise(
    dict("name":"MooneyRivlinType",
    "energy_expression":"u_1*(F:F-3) + u_2*(H:H-3) - 2*(u_1+2*u_2)*ln(J)+lamb/2*(J-1)**2",
    "fields":"mechanics",
    "nature":"nonlinear",
    "constants":"u_1,u_2,lamb",
    "variables":dict("F":"deformation_gradient","H":"cofactor(F)","J":"determinant(F)")
    )
)
user_material_context.Generate()

This will generate a low level code for material model called MooneyRivlinType which can be used like any other material model in Florence

user_material = MooneyRivlinType(ndim, u_1=1, u_2=1, lamb=10)