NEML2 2.1.0
Loading...
Searching...
No Matches
Getting Started

Once the NEML2 library is built following the installation guide, the immediate question is

How do I evaluate a NEML2 material model?

Downstream C++ project

NEML2 core capabilities are implemented as a library, not a program. As a library, it will be used by another C++ program to parse and evaluate a material model defined in an input file. Boilerplate for the C++ program can be found in the quick start guide below as well as in this set of tutorials, and external project integration is documented in the installation guide.

Python script

The other option to evaluate NEML2 material models is to use the NEML2 Python package. As mentioned in the installation guide, NEML2 also provides a Python package which provides bindings for the primitive tensors and parsers for deserializing and running material models. The following quick start guide as well as this set of tutorials describe the usage of the package.

Quick start

The following is a quick summary of the most common model API usage patterns. Each topic is covered in full detail in the model tutorials.

Loading a model

Given an input file, a model is loaded with a single call:

  • C++
    #include "neml2/neml2.h"
    int
    main()
    {
    using namespace neml2;
    auto model = load_model("input.i", "my_model");
    std::cout << *model << std::endl;
    }
    Definition DiagnosticsInterface.h:31
    std::shared_ptr< Model > load_model(const std::filesystem::path &path, const std::string &mname)
    A convenient function to load an input file and get a model.
  • Python
    import neml2
    model = neml2.load_model("input.i", "my_model")
    print(model)

load_model parses the file and returns the named model ready for evaluation. The running your first model tutorial walks through a complete example.

Calling forward operators

All NEML2 models expose three forward operators that accept a map of input variable values:

Operator Returns
value output variable values \( y = f(x) \)
dvalue first derivatives \( \partial y / \partial x \)
value_and_dvalue both simultaneously
  • C++
    #include "neml2/neml2.h"
    #include "neml2/tensors/SR2.h"
    int
    main()
    {
    using namespace neml2;
    auto model = load_model("input.i", "my_model");
    // Create the strain
    auto strain = SR2::fill(0.1, 0.05, -0.03, 0.02, 0.06, 0.03);
    // Evaluate the model
    auto output = model->value({{"strain", strain}});
    // Get the stress
    auto & stress = output["stress"];
    std::cout << "strain: \n" << strain << std::endl;
    std::cout << "stress: \n" << stress << std::endl;
    }
    static SR2 fill(const CScalar &a, const TensorOptions &options=default_tensor_options())
    Fill the diagonals with a11 = a22 = a33 = a.
    constexpr auto kFloat64
    Definition types.h:54
    void set_default_dtype(Dtype dtype)
  • Python
    import neml2
    from neml2.tensors import SR2
    import torch
    torch.set_default_dtype(torch.double)
    model = neml2.load_model("input.i", "my_model")
    # Create the strain
    strain = SR2.fill(0.1, 0.05, -0.03, 0.02, 0.06, 0.03)
    # Evaluate the model
    output = model.value({"strain": strain})
    # Get the stress
    stress = output["stress"]
    print("strain:")
    print(strain)
    print("stress:")
    print(stress)

The return value of neml2::Model::value is a dictionary keyed by output variable name. neml2::Model::dvalue returns a nested dictionary keyed by (output, input) variable names.

Modifying parameter values

Model parameters can be updated at runtime — useful for optimization or training loops. Parameters are accessed by name and assigned new tensor values:

  • C++
    #include "neml2/neml2.h"
    #include "neml2/tensors/Tensor.h"
    #include "neml2/tensors/Scalar.h"
    int
    main()
    {
    using namespace neml2;
    auto model = load_model("input.i", "my_model");
    // Before modification
    auto & G = model->get_parameter("G");
    std::cout << "G (before modification):\n" << Tensor(G) << std::endl;
    // After modification
    G = Scalar::full(59000);
    std::cout << "G (after modification):\n" << Tensor(G) << std::endl;
    }
    static Scalar full(const CScalar &init, const TensorOptions &options=default_tensor_options())
    Definition PrimitiveTensor.h:276
    Definition Tensor.h:53
  • Python
    import neml2
    from neml2.tensors import Scalar
    model = neml2.load_model("input.i", "my_model")
    # Before modification
    print("G (before modification):")
    print(model.G.tensor())
    # After modification
    model.G = Scalar.full(59000)
    print("G (after modification):")
    print(model.G.tensor())

The model parameters tutorial covers parameters and buffers in detail, including how parameters can themselves be defined by other models.

Utility binaries

We acknowledge the common need to use NEML2 as a standalone program and therefore provide utility binaries for common tasks.

As documented in build customization, the NEML2_TOOLS CMake option can be used to create these binaries.

When tools are enabled, NEML2 builds the following standalone executables:

  • neml2-diagnose
  • neml2-inspect
  • neml2-run
  • neml2-syntax
  • neml2-time

When installed, these binaries are placed in the installed bin directory.

For the Python package, matching CLI wrappers are registered in pyproject.toml:

  • neml2-diagnose
  • neml2-inspect
  • neml2-run
  • neml2-syntax
  • neml2-time

These commands dispatch to the shipped binaries bundled inside the Python package. See each tool's help message (for example, neml2-run --help) for further details.