FEniCS
and MFront
for complex non linear solid mechanics simulationThis document is meant to show how FEniCS
and MFront
can be combined to build almost arbitrary complex non linear solid mechanics simulation. As MFront
currently allows the implementation of small and finite strain mechanical behaviours, the current scope of this coupling is limited to standard first order theories1. Generalised behaviours, usable in monolithic multiphysics simulations and/or higher order mechanical theories, will be available in the next version2.
FEniCS
will handle:
The MFront
behaviour will handle, at each integration point:
The interface with FEniCS
will be handled by the MFrontGenericInterfaceSupport
project (MGIS
)3. This project aims at proving tools (functions, classes, bindings, etc…) to handle behaviours written using MFront
generic interface. Written in C++
, it provides bindings for various languages: C
, python
, fortran
. This library also provides the so-called FEniCS
bindings briefly described below.
Two approaches are available:
python
bindings. This approach requires the user to write its own version of the Newton solver.fenics-solid-mechanics
project written by Kristian B. Ølgaard and Garth N. Wells4, will allow the usage of the standard Newton-Raphson procedure delivered by dolfin
. This approach is the basis of the FEniCS
bindings.Each approach has its strengths and weaknesses:
C++
and small strain behaviours5. The computation of the gradients and the construction of inner forces and the consistent tangent operator are handled at element level: this explain why only a limited range of behaviours are currently supported. This approach also requires to go deep in the very gory details of FEniCS
internals which are far from trivial and, to the authors opinion, currently insufficiently described for new comers in the source code and the doxygen
documentation.This document will focus on the coupling at the python
level
MGIS
projectIn this paper, a limited number of classes and functions of the MGIS
project will be considered:
Behaviour
class handles all the information about a specific MFront
behaviour. It is created by the load
function which takes the path to a library, the name of a behaviour and a modelling hypothesis.MaterialDataManager
class handles a bunch of integration points. It is instantiated using an instance of the Behaviour
class and the number of integration points6. The MaterialDataManager
contains various interesting members:
s0
: data structure of the MaterialStateManager
type which stands for the material state at the beginning of the time step.s1
: data structure of the MaterialStateManager
type which stands for the material state at the end of the time step.K
: a numpy
array containing the consistent tangent operator at each integration points.MaterialStateManager
class describe the state of a material. The following members will be useful in the following:
gradients
: a numpy array containing the value of the gradients at each integration points. The number of components of the gradients at each integration points is given by the gradients_stride
member.thermodynamic_forces
:a numpy array containing the value of the thermodynamic forces at each integration points. The number of components of the thermodynamic forces at each integration points is given by the thermodynamic_forces_stride
member.internal_state_variables
: a numpy array containing the value of the internal state variables at each integration points. The number of internal state variables at each integration points is given by the internal_state_variables_stride
member.setMaterialProperty
and setExternalStateVariable
functions can be used to set the value a material property or a state variable respectively.update
function updates an instance of the MaterialStateManager
by copying the state s1
at the end of the time step in the state s0
at the beginning of the time step.revert
function reverts an instance of the MaterialStateManager
by copying the state s0
at the beginning of the time step in the state s1
at the end of the time step.integrate
function triggers the behaviour integration at each integration points. Various overloads of this function exist. We will use a version taking as argument a MaterialStateManager
, the time increment and a range of integration points.Those classes and functions are available in the mgis.behaviour
python
module.
This section is extracted from the following tutorial:
https://comet-fenics.readthedocs.io/en/latest/demo/plasticity_mfront/plasticity_mfront.py.html
The idea is here to focus on
Assuming that number of integration points is known and stored in the ng
variable, a possible initialisation of a behaviour and a material data manager can be:
# modelling hypothesis
= mgis_bv.Hypothesis.PlaneStrain
h # loading the behaviour
= mgis_bv.load('src/libBehaviour.so','IsotropicLinearHardeningPlasticity',h)
b # material data manager
= mgis_bv.MaterialDataManager(b,ngauss)
m for s in [m.s0, m.s1]:
"YoungModulus", 150e9)
mgis_bv.setMaterialProperty(s, "PoissonRatio", 0.3)
mgis_bv.setMaterialProperty(s, "HardeningSlope", 150e6)
mgis_bv.setMaterialProperty(s, "YieldStrength", 200e6)
mgis_bv.setMaterialProperty(s, "Temperature", 293.15) mgis_bv.setExternalStateVariable(s,
The following code shows how a simple Newton-Raphson can be setup in the case of a single material:
for (i, t) in enumerate(load_steps):
= t
loading.t = assemble_system(a_Newton, res, bc)
A, Res = Res.norm("l2")
nRes0 = nRes0
nRes
u1.assign(u)print("Increment:", str(i+1))
= 0
niter while nRes/nRes0 > tol and niter < Nitermax:
"mumps")
solve(A, du.vector(), Res, # current estimate of the displacement at the end of the time step
+du)
u1.assign(u1# project the strain on the Quadrature space with `MFront` conventions
local_project(eps_MFront(u1), Weps, deps)# assigning the values in the material data manager
= deps.vector().get_local().reshape((m.n, m.gradients_stride))
m.s1.gradients[:, :] # behaviour integration
= mgis_bv.IntegrationType.IntegrationWithConsitentTangentOperator
it 0, 0, m.n);
mgis_bv.integrate(m, it, # getting the thermodynamic forces and the consistent tangent operator for FEniCS
sig.vector().set_local(m.s1.thermodynamic_forces.flatten())apply("insert")
sig.vector().
Ct.vector().set_local(m.K.flatten())apply("insert")
Ct.vector().# solve Newton system
= assemble_system(a_Newton, res, bc)
A, Res = Res.norm("l2")
nRes print(" Residual:", nRes)
+= 1
niter # update for new increment
u.assign(u1) mgis_bv.update(m)
m
is an instance of the MaterialDataManger
class. The key function here is local_project
which computes the current estimate of the strain at the end of the time step (stored using MFront
conventions).
This code also relies on the previous definition of the consistent tangent operator and the stress tensor, which is standard FEniCS
code:
a_Newton = inner(eps_MFront(v), dot(Ct, eps_MFront(u_)))*dxm
res = -inner(eps(u_), as_3D_tensor(sig))*dxm + F_ext(
This code suffers from the following drawbacks:
FEniCS
to MGIS
and back:Finite strain behaviours generated by MFront
can also be used quite easily.
The mechanical equilibrium is written in weak-form on the initial configuration using the first Piola-Kirchhoff stress in the axisymmetric case:
= -inner(grad_MFront(u_), pk1)*x[0]*dxm res
The stiffness matrix naturally introduces the derivative of the first Piola-Kirchhoff stress with respect to the deformation gradient, denoted Ct
:
= inner(grad_MFront(v), dot(Ct, grad_MFront(u_)))*x[0]*dxm a_Newton
To tell MFront
that we want to use the first Piola-Kirchhoff stress and compute its derivative, one have to modify the call to the load
function, as follows:
# Loading the behaviour
= mgis_bv.Hypothesis.Axisymmetrical
h = mgis_bv.FiniteStrainBehaviourOptions()
bopts = mgis_bv.FiniteStrainBehaviourOptionsStressMeasure.PK1
bopts.stress_measure = mgis_bv.FiniteStrainBehaviourOptionsTangentOperator.DPK1_DF
bopts.tangent_operator = mgis_bv.load(bopts,'src/libBehaviour.so','LogarithmicStrainPlasticity',h) b
Cohesive zone models are not considered here, mostly because the authors don’t know if it is even possible to introduce them in FEniCS
.↩︎
Indeed, being able to test this new feature is one of the main reason why an interface to FEniCS
has been considered.↩︎
\(2D\) simulations is theoretically supported, but the authors acknowledges that this is not currently functional.↩︎
Note that an instance of MaterialDataManager
keeps a reference to the behaviour which has been used for its initialization: the user must ensure that this behaviour outlives the instance of the MaterialDataManager
, otherwise memory corruption may occur.↩︎