Calling other behaviours from a behaviour is useful in many situations and allows, for instance, to

This document describes a solution based on so-called behaviour variables (i.e. variables that are in fact behaviours) which are introduced by the @BehaviourVariable keyword.

Example of usage

Declaration

The following snippet declares a variable named b1 associated with a behaviour Plasticity defined in the file BehaviourVariablePlasticity.mfront.

@BehaviourVariable b1 {
  file: "Plasticity.mfront",
  variables_suffix: "1",
  external_names_prefix: "FirstPhase",
  store_gradients: true,
  store_thermodynamic_forces: true,
  shared_external_state_variables: {".+"}
};

This example illustrates the complexity of the declaration of a behaviour variable. The main reason for this complexity is due to the fact that the calling behaviour is responsible for declaring and managing the variables associated with b1 (material properties, internal state variables, external state variable), etc.

In particular, the behaviour variable and the calling behaviour may share some variables (material properties, external state variables).

In this example, since no material property is declared as shared, the calling behaviour will create one material property for each material property declared in the behaviour Plasticity (see the shared_material_properties option below for details on how to declare shared material properties). To avoid conflicts, the names and external names of this new material properties are modified using the options variables_prefix, variables_suffix, external_names_prefix or external_names_suffix.

To illustrate this, let us assume that the behaviour defined in Plasticity.mfront defines the following state variables:

This can be verified by using mfront-query:

$ mfront-query --unicode-output=false --state-variables Plasticity.mfront
- ElasticStrain (eel): The elastic strain
- EquivalentPlasticStrain (p): the equivalent plastic strain

Those state variables are automatically declared as auxiliary state variables by the calling behaviour, but their names is changed, as follows:

$ mfront-query --unicode-output=false --auxiliary-state-variables MacroscopicBehaviour.mfront 
- FirstPhaseStrain (eto1)
- FirstPhaseStress (sig1)
- FirstPhaseElasticStrain (eel1)
- FirstPhaseEquivalentPlasticStrain (p1)

This output only indicates that, due to the store_gradients and store_thermodynamic_forces options, the strain and stress of the behaviour are also declared as auxiliary state variables

Finally, the last option, shared_external_state_variables, states that all external state variables are shared with the calling behaviour. As a result, the macroscopic behaviour declares the same state variable as the behaviour defined in Plasticity.mfront:

$ mfront-query --unicode-output=false --external-state-variables tests.mfront 
- Temperature (T): the temperature
$ mfront-query --unicode-output=false --external-state-variables MacroscopicBehaviour.mfront 
- Temperature (T): the temperature

Integration of a behaviour variable

A behaviour variable can be integrated using the integrate method as follows:

const auto r = b1.integrate(smflag, smt);

where smflag and smt are parameters associated with the computation of the consistent tangent operator (see below).

Retrieveing the tangent operator

The tangent operator can be retrieved using the getTangentOperator method as follows:

Dt = b1.getTangentOperator();

Options of the @BehaviourVariable keyword

Treatment of the gradients or thermodynamic variables of the behaviour variable

Setting the store_gradients option to true, which is the default value, has the following effects:

If the store_gradients option to false, the calling behaviour is responsible for setting the gradients at the beginning of the time step and either their increments or their values at the end of the time step, depending on the case.

The store_thermodynamic_forces option has a similar role for thermodynamic forces.

Note on orthotropic behaviours

If the called behaviour is orthotropic, the gradients and thermodynamic forces must be defined in the material frame associated with the behaviour variable. The calling behaviour is responsible for making the appropriate rotations.

Note on the strain measures

If the called behaviour is based on a strain measure, then the calling behaviour is responsible for consistently initializing the strain at the beginning of the time step (in particular if store_gradients is set to false), the thermodynamic forces (in particular if store_thermodynamic_forces is set to false) and the strain increment.

Note on stress free strains

Strain based Behaviours requires special care if the called behaviour declares stress free expansions (volumetric swelling, thermal expansion, etc.). In the case, the called behaviour exposes a method called computeStressFreeStrain that shall only be called after the initialization of the behaviour. This method returns a pair containing the stress free strains at the beginning of the time step and at the end of the time step.

Assuming that the calling behaviour wants to assign a total strain increment deto_b1, the method computeStressFreeStrain can be used as follows:

// assuming that the behaviour is able to compute the thermal strains
const auto [eth_bts, eth_ets] = b1.computeStressFreeStrain();
b1.deto = deto_b1 - eth_ets + eth_bts;

Note that these stress free strains are:

Treatment of the persistent variables of the behaviour variable

A behaviour variable may declares persistent variables, i.e. state variables or auxiliary state variables. Those persistent variables are automatically declared as auxiliary state variables by the calling behaviour. The transformation rules on the names and external names are applied to define those new variables (see the variables_prefix, variables_suffix, external_names_prefix or external_names_suffix options).

The persistent variables of the behaviour variable are automatically initialized by copying the values of the associated auxiliary state variables of the calling behaviour.

If the automatically_save_associated_auxiliary_state_variables option is set to true, the persistent variables of the behaviour variable are automatically saved in the associated auxiliary state variables at the beginning of the updateAuxiliaryStateVariables method of the calling behaviour.

Treatment of the material properties and external state variables of the behaviour variable

When a material property (or an external state variable) of the behaviour variable is declared as shared (see the shared_material_properties and shared_external_state_variables), the calling behaviour will check if a matching material property (or an external state variable) is declared. If not, it will declare exactly the same material property (or external state variable), i.e. the transformation rules on the names and external names are not applied.

When a material property (or an external state variable) of the behaviour variable is not declared as shared (the default), a new material property (or an external state variable) is automatically declaring applying the transformation rules on names.

Access to the variables of the behaviour variable

The calling behaviour has access to all the variables of the behaviour variable (material properties, parameters, external state variables, gradients, local variables, etc..).

Initialization of the behaviour variable

A specialized version of the initialize method which takes the behaviour variable as its only argument is automatically defined and can be called as follows:

initialize(b1);

This method initializes:

This method is automatically called by the main initialize method of the calling behaviour (which is always called) after initializing the material properties, external state variables, persistent variables of the behaviour variables.

Reinitializing and resetting a behaviour variable

The initialize method associated with a behaviour variable can be called several times. This might be useful to integrate this behaviour variable several times.

However, this does not guarantee that calling the integration of the behaviour variable will lead to the same result as some internal variables may have evolved.

In particular, the increment of the integration variables will not zeroed. Not zeroing those increment may accelerate the integration when the behaviour integration is called multiple times as the solution of the previous call may be a good estimate for the new resolution.

To initialize the behaviour and zero the increment of the integration variables , one may call the reset method instead:

reset(b1); // calls initialize and zeros integration variable increments

Note that even the reset method does not absolutely guarantee that calling the integration of the behaviour variable will lead to the same result as some internal variables may have evolved. This will probably be the case assuming that the implementation of the called behaviour does not make any strange things internally.

Integration

The integrate method performs the integration of the behaviour variable.

Note that this method must be called after having the gradients at the beginning of the time step (see also the store_gradients option for details), the thermodynamic forces at the beginning of the time step (see also the store_thermodynamic_forces option for details), and either the gradients at the end of the time step or their increments depending on the case.

The integrate method takes two arguments:

Here is an example on how to call the integrate method of a behaviour variable which is not a standard finite strain behaviour:

constexpr auto b1_smflag = TangentOperatorTraits<
    MechanicalBehaviourBase::STANDARDSTRAINBASEDBEHAVIOUR>::
    STANDARDTANGENTOPERATOR;
const auto r = b1.integrate(b1_smflag, CONSISTENTTANGENTOPERATOR);

The integrate method returns IntegrationResult object which is implicitly convertible to a boolean. This boolean is true if the integration succeeded.

Retrieving the tangent operator

The tangent operator computed by the integrate method can be retrieved using the getTangentOperator method. If the integrate method did not compute the tangent operator (i.e. if the value NOSTIFFNESSREQUESTED was passed as the second argument), the result is undefined.

Note on orthotropic behaviours

If the called behaviour is orthotropic, the tangent operator is defined in the material frame associated with the behaviour variable. The calling behaviour is responsible for making the appropriate rotations.

Note on the strain measures

If the called behaviour is based on a strain measure, the tangent operator relates the dual stress and the strain measure. The calling behaviour is responsible for making the appropriate conversions, if required.

Updating the auxiliary state variables associated with a behaviour variable

As stated in the previous paragraph, the automatically_save_associated_auxiliary_state_variables option controls if the auxiliary state variables associated with a behaviour variable are automatically saved.

If this option is false, the author of the calling behaviour is responsible for updating those state variables by hand. This task can be deleguated to a specialized version of the updateAuxiliaryStateVariables method which takes the behaviour variable as its only argument, as follows:

updateAuxiliaryStateVariables(b1);

The last solution is to cherry-pick the variables to be saved by hand.