This 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:

Each approach has its strengths and weaknesses:

This document will focus on the coupling at the python level

Rapid description of useful classes and functions introduced by the MGIS project

In this paper, a limited number of classes and functions of the MGIS project will be considered:

Those classes and functions are available in the mgis.behaviour python module.

Application to a small strain behaviour

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

Initialisation of a single material

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
h = mgis_bv.Hypothesis.PlaneStrain
# loading the behaviour        
b = mgis_bv.load('src/libBehaviour.so','IsotropicLinearHardeningPlasticity',h)
# material data manager
m = mgis_bv.MaterialDataManager(b,ngauss)
for s in [m.s0, m.s1]:
    mgis_bv.setMaterialProperty(s, "YoungModulus", 150e9)
    mgis_bv.setMaterialProperty(s, "PoissonRatio", 0.3)
    mgis_bv.setMaterialProperty(s, "HardeningSlope", 150e6)
    mgis_bv.setMaterialProperty(s, "YieldStrength", 200e6)
    mgis_bv.setExternalStateVariable(s, "Temperature", 293.15)

An example of a Newton-Raphson loop for a single material

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):
    loading.t = t
    A, Res = assemble_system(a_Newton, res, bc)
    nRes0 = Res.norm("l2")
    nRes = nRes0
    u1.assign(u)
    print("Increment:", str(i+1))
    niter = 0
    while nRes/nRes0 > tol and niter < Nitermax:
        solve(A, du.vector(), Res, "mumps")
        # current estimate of the displacement at the end of the time step 
        u1.assign(u1+du)
        # 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
        m.s1.gradients[:, :] = deps.vector().get_local().reshape((m.n, m.gradients_stride))
        # behaviour integration
        it = mgis_bv.IntegrationType.IntegrationWithConsitentTangentOperator
        mgis_bv.integrate(m, it, 0, 0, m.n);
        # getting the thermodynamic forces and the consistent tangent operator for FEniCS
        sig.vector().set_local(m.s1.thermodynamic_forces.flatten())
        sig.vector().apply("insert")
        Ct.vector().set_local(m.K.flatten())
        Ct.vector().apply("insert")
        # solve Newton system
        A, Res = assemble_system(a_Newton, res, bc)
        nRes = Res.norm("l2")
        print("    Residual:", nRes)
        niter += 1
    # 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:

Application to finite strain behaviours

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:

res = -inner(grad_MFront(u_), pk1)*x[0]*dxm

The stiffness matrix naturally introduces the derivative of the first Piola-Kirchhoff stress with respect to the deformation gradient, denoted Ct:

a_Newton = inner(grad_MFront(v), dot(Ct, grad_MFront(u_)))*x[0]*dxm

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
h = mgis_bv.Hypothesis.Axisymmetrical
bopts = mgis_bv.FiniteStrainBehaviourOptions()
bopts.stress_measure = mgis_bv.FiniteStrainBehaviourOptionsStressMeasure.PK1
bopts.tangent_operator = mgis_bv.FiniteStrainBehaviourOptionsTangentOperator.DPK1_DF
b = mgis_bv.load(bopts,'src/libBehaviour.so','LogarithmicStrainPlasticity',h)

  1. Cohesive zone models are not considered here, mostly because the authors don’t know if it is even possible to introduce them in FEniCS.↩︎

  2. Indeed, being able to test this new feature is one of the main reason why an interface to FEniCS has been considered.↩︎

  3. https://github.com/thelfer/MFrontGenericInterfaceSupport↩︎

  4. https://bitbucket.org/fenics-apps/fenics-solid-mechanics↩︎

  5. \(2D\) simulations is theoretically supported, but the authors acknowledges that this is not currently functional.↩︎

  6. 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.↩︎