NEML2 1.4.0
|
The following tutorials serve as a developer-facing step-by-step guide for creating and testing a custom material model. A simple linear isotropic hardening is used as the example in this tutorial. The model can be mathematically written as
\begin{align*} h &= K \bar{\varepsilon}^p, \end{align*}
where \(\bar{\varepsilon}^p\) is the equivalent plastic strain and \(h\) is the isotropic hardening. The input variable for this model is \(\boldsymbol{\varepsilon}\), the output variable for this model is \(k\), and the parameters of the model is \(K\).
The development of every model begins with the declaration and registration of its input and output variables. Here, we first define an abstract base class that will be later used to define the linear isotropic hardening relation. The abstract base class defines the isotropic hardening relation
\[ h = f\left( \bar{\varepsilon}^p \right), \]
mapping the equivalent plastic strain to the isotropic hardening. The base class is named IsotropicHardening
following the naming conventions. The header file IsotropicHardening.h is displayed below
Since isotropic hardening is a model, the class inherits from Model
. The user-facing expected options are defined by the static method expected_options
. NEML2 handles the parsing of user-specified options and pass them to the constructor (see Input file syntax on how the input file works). The input variable of the model is the equivalent plastic strain, and the output variable of the model is the isotropic hardening. Their corresponding variable value references are stored as _ep
and _h
, respectively, again following the naming conventions.
The expected options and the constructor are defined as
Recall that variable names on LabeledAxis
are always fully qualified, the equivalent plastic strain and the isotropic hardening are denoted as "state/internal/ep" and "state/internal/k", respectively. An instance of the class is constructed by extracting user-specified options (of type OptionSet
). Note how declare_input_variable<Scalar>
and declare_output_variable<Scalar>
are used to declare and register the input and output variables.
Now that the abstract base class IsotropicHardening
has been implemented, we are ready to define our first concrete NEML2 model that describes a linear isotropic hardening relation
\[ h = K \bar{\varepsilon}^p. \]
Note that \(K\) is a model parameter. Following the naming convention, the concrete class is named LinearIsotropicHardening
. The header file is displayed below.
It derives from the abstract base class IsotropicHardening
and implements the method set_value
as the forward operator. The model parameter \(K\) is stored as a protected member variable _K
. The model implementation is shown below.
Note that an additional option named "hardening_modulus" is requested from the user. The model parameter is registered using the API declare_parameter<Scalar>
. In the set_value
method, the current value of the input variable, equivalent plastic strain, is stored in the member _ep
, and so the isotropic hardening can be computed as
The computed result is copied into the model output variable _h
by
In addition, the first derivative of the forward operator is defined as
Last but not the least, the model is registed in the NEML2 model factory using the macro
so that an instance of the class can be created at runtime.
In the examples above, we have added Doxygen-style in-code documentation for the class and member variables. These documentation strings are automatically parsed and translated by Doxygen, and the resulting page can be found at neml2::LinearIsotropicHardening.
On the other hand, as the number of models grows, it becomes increasingly challenging to maintain a list of input file options so that users can refer to. For example, the input file syntax for specifying LinearIsotropicHardening
is shown below
Some natural questions are, how is the user supposed to know, without inspecting the source code,
Doxygen-style in-code documentation cannot directly address the above issues. Therefore, NEML2 provides another form of in-code documentation to generate the so-called Syntax Documentation.
Again, using the IsotropicHardening
as an example, the following in-code documentation can be added in the expected_options
method:
The object description is added using neml2::OptionSet::doc, and each expected option is accompanied with a brief explanation. NEML2 can then automatically extract and build the syntax documentation.