diff --git a/.gitmodules b/.gitmodules index e787498bcc4b..1db96522d012 100644 --- a/.gitmodules +++ b/.gitmodules @@ -57,3 +57,7 @@ path = framework/contrib/neml2 url = ../../applied-material-modeling/neml2.git update = none +[submodule "framework/contrib/pytorch"] + path = framework/contrib/pytorch + url = ../../pytorch/pytorch.git + update = none diff --git a/conda/moose-dev/meta.yaml b/conda/moose-dev/meta.yaml index ca798fc64919..a756f7db4675 100644 --- a/conda/moose-dev/meta.yaml +++ b/conda/moose-dev/meta.yaml @@ -2,7 +2,7 @@ # REMEMBER TO UPDATE the .yaml files for the following packages: # moose/conda_build_config.yaml # As well as any directions pertaining to modifying those files. -{% set version = "2026.04.21" %} +{% set version = "2026.05.06" %} package: name: moose-dev diff --git a/framework/contrib/neml2 b/framework/contrib/neml2 index 9b8d8b934095..95801ac8db50 160000 --- a/framework/contrib/neml2 +++ b/framework/contrib/neml2 @@ -1 +1 @@ -Subproject commit 9b8d8b934095b7f49fe2f92eb00937e9209c38aa +Subproject commit 95801ac8db50c62ec850a47989aaacd971e2eb7d diff --git a/framework/contrib/neml2.mk b/framework/contrib/neml2.mk index a2aa737216cf..12b6c893432a 100644 --- a/framework/contrib/neml2.mk +++ b/framework/contrib/neml2.mk @@ -21,9 +21,20 @@ endif # NEML2 flags comma := , neml2_CPPFLAGS += -DNEML2_ENABLED -neml2_INCLUDES += $(shell pkg-config --cflags $(NEML2_PC)) -neml2_LDFLAGS += $(foreach libdir,$(shell pkg-config --libs-only-L $(NEML2_PC)),$(patsubst -L%,-Wl$(comma)-rpath$(comma)%,$(libdir))) -neml2_LIBS += $(shell pkg-config --libs $(NEML2_PC)) + +# When MOOSE manages torch separately (ENABLE_LIBTORCH=true), filter torch flags out of +# NEML2's bundled pkg-config. Otherwise libtool deduplicates the -l flags keeping the last +# occurrence (embedded deep in the .la chain), pushing torch after petsc. +NEML2_TORCH_PC := $(NEML2_DIR)/share/pkgconfig/neml2-torch.pc +ifneq ($(wildcard $(NEML2_TORCH_PC)),) +neml2_torch_INCLUDES := $(shell pkg-config --cflags $(NEML2_TORCH_PC)) +neml2_torch_LDIRS := $(shell pkg-config --libs-only-L $(NEML2_TORCH_PC)) +neml2_torch_LIBS := $(shell pkg-config --libs $(NEML2_TORCH_PC)) +endif + +neml2_INCLUDES += $(filter-out $(neml2_torch_INCLUDES),$(shell pkg-config --cflags $(NEML2_PC))) +neml2_LDFLAGS += $(foreach libdir,$(filter-out $(neml2_torch_LDIRS),$(shell pkg-config --libs-only-L $(NEML2_PC))),$(patsubst -L%,-Wl$(comma)-rpath$(comma)%,$(libdir))) +neml2_LIBS += $(filter-out $(neml2_torch_LIBS),$(shell pkg-config --libs $(NEML2_PC))) # Append to libmesh flags libmesh_CXXFLAGS += $(neml2_CPPFLAGS) # I think MOOSE Makefiles tend to abuse libmesh_CXXFLAGS for preprocessor flags diff --git a/framework/contrib/pytorch b/framework/contrib/pytorch new file mode 160000 index 000000000000..7838379d23f0 --- /dev/null +++ b/framework/contrib/pytorch @@ -0,0 +1 @@ +Subproject commit 7838379d23f0992146def26886786164b3d8b83f diff --git a/framework/doc/content/source/neml2/userobjects/MOOSEMaterialPropertyToNEML2.md b/framework/doc/content/source/neml2/userobjects/MOOSEMaterialPropertyToNEML2.md deleted file mode 100644 index 1a78c224d621..000000000000 --- a/framework/doc/content/source/neml2/userobjects/MOOSEMaterialPropertyToNEML2.md +++ /dev/null @@ -1,35 +0,0 @@ -# MOOSEMaterialPropertyToNEML2 - -!if! function=hasCapability('neml2') - -!alert note -Users are +NOT+ expected to directly use this object in an input file. Instead, it is always recommended to use the [NEML2 action](syntax/NEML2/index.md). - -## Description - -This family of objects collect a MOOSE material property given by [!param](/UserObjects/MOOSERealMaterialPropertyToNEML2/from_moose) for use as a NEML2 input variable or model parameter [!param](/UserObjects/MOOSERealMaterialPropertyToNEML2/to_neml2). - -The following flavors exist: - -| Class | MOOSE MaterialProperty type | -| :--------------------------------------------------- | :-------------------------- | -| `MOOSERealMaterialPropertyToNEML2` | `Real` | -| `MOOSERankTwoTensorMaterialPropertyToNEML2` | `RankTwoTensor` | -| `MOOSESymmetricRankTwoTensorMaterialPropertyToNEML2` | `SymmetricRankTwoTensor` | -| `MOOSEStdVectorRealMaterialPropertyToNEML2` | `std::vector` | - -Each class has an "old" counterpart to retrieve the corresponding MOOSE material property from the previous time step. The naming convention is - -``` -MOOSE[Old]MaterialPropertyToNEML2 -``` - -For example, `MOOSEOldRealMaterialPropertyToNEML2` gathers the `Real`-valued material property from the previous time step. - -!syntax parameters /UserObjects/MOOSERealMaterialPropertyToNEML2 - -!if-end! - -!else - -!include neml2/neml2_warning.md diff --git a/framework/doc/content/source/neml2/userobjects/MOOSEPostprocessorToNEML2.md b/framework/doc/content/source/neml2/userobjects/MOOSEPostprocessorToNEML2.md deleted file mode 100644 index 32e5145e3a26..000000000000 --- a/framework/doc/content/source/neml2/userobjects/MOOSEPostprocessorToNEML2.md +++ /dev/null @@ -1,28 +0,0 @@ -# MOOSEPostprocessorToNEML2 - -!if! function=hasCapability('neml2') - -!syntax description /UserObjects/MOOSEPostprocessorToNEML2 - -!alert note -Users are +NOT+ expected to directly use this object in an input file. Instead, it is always recommended to use the [NEML2 action](syntax/NEML2/index.md). - -## Description - -This family of objects collect a MOOSE postprocessor value given by [!param](/UserObjects/MOOSEPostprocessorToNEML2/from_moose) for use as a NEML2 input variable or model parameter [!param](/UserObjects/MOOSEPostprocessorToNEML2/to_neml2). The given postprocessor value is broadcast to all quadrature points. - -The naming convention is - -``` -MOOSE[Old]PostprocessorToNEML2 -``` - -For example, `MOOSEPostprocessorToNEML2` gathers the postprocessor value from the +current+ time step, and `MOOSEOldPostprocessorToNEML2` gathers the postprocessor value from the +previous+ time step. - -!syntax parameters /UserObjects/MOOSEPostprocessorToNEML2 - -!if-end! - -!else - -!include neml2/neml2_warning.md diff --git a/framework/doc/content/source/neml2/userobjects/MOOSEQuantityToNEML2.md b/framework/doc/content/source/neml2/userobjects/MOOSEQuantityToNEML2.md new file mode 100644 index 000000000000..92d33e52f116 --- /dev/null +++ b/framework/doc/content/source/neml2/userobjects/MOOSEQuantityToNEML2.md @@ -0,0 +1,18 @@ +# MOOSEMaterialPropertyToNEML2 + +!if! function=hasCapability('neml2') + +!alert note +Users are +NOT+ expected to directly use this object in an input file. Instead, it is always recommended to use the [NEML2 action](syntax/NEML2/index.md). + +## Description + +This object collects a MOOSE quantity given by [!param](/UserObjects/MOOSEQuantityToNEML2/from_moose) for use as a NEML2 input variable or model parameter [!param](/UserObjects/MOOSEQuantityToNEML2/to_neml2). The source of data is specified by [!param](/UserObjects/MOOSEQuantityToNEML2/quantity_type). This object has an "old" counterpart to retrieve the corresponding MOOSE data from the previous time step. The naming convention is + +!syntax parameters /UserObjects/MOOSEQuantityToNEML2 + +!if-end! + +!else + +!include neml2/neml2_warning.md diff --git a/framework/doc/content/source/neml2/userobjects/MOOSEVariableToNEML2.md b/framework/doc/content/source/neml2/userobjects/MOOSEVariableToNEML2.md deleted file mode 100644 index 193d3dbaca97..000000000000 --- a/framework/doc/content/source/neml2/userobjects/MOOSEVariableToNEML2.md +++ /dev/null @@ -1,28 +0,0 @@ -# MOOSEVariableToNEML2 - -!if! function=hasCapability('neml2') - -!syntax description /UserObjects/MOOSEVariableToNEML2 - -!alert note -Users are +NOT+ expected to directly use this object in an input file. Instead, it is always recommended to use the [NEML2 action](syntax/NEML2/index.md). - -## Description - -This family of objects collect a MOOSE variable or auxiliary variable given by [!param](/UserObjects/MOOSEVariableToNEML2/from_moose) for use as a NEML2 input variable or model parameter [!param](/UserObjects/MOOSEVariableToNEML2/to_neml2). The given variable is interpolated at each quadrature point. - -The naming convention is - -``` -MOOSE[Old]VariableToNEML2 -``` - -For example, `MOOSEVariableToNEML2` gathers the (auxiliary) variable from the +current+ time step, and `MOOSEOldVariableToNEML2` gathers the (auxiliary) variable from the +previous+ time step. - -!syntax parameters /UserObjects/MOOSEVariableToNEML2 - -!if-end! - -!else - -!include neml2/neml2_warning.md diff --git a/framework/doc/content/source/neml2/userobjects/NEML2ModelExecutor.md b/framework/doc/content/source/neml2/userobjects/NEML2ModelExecutor.md index 4ddc6169cef2..76e7c3fbd738 100644 --- a/framework/doc/content/source/neml2/userobjects/NEML2ModelExecutor.md +++ b/framework/doc/content/source/neml2/userobjects/NEML2ModelExecutor.md @@ -13,12 +13,6 @@ This object uses the specified NEML2 material model to perform mesh-wise (or sub Each NEML2 model +input variable+ is gathered from MOOSE by a `MOOSEToNEML2` user object (gatherer) given in [!param](/UserObjects/NEML2ModelExecutor/gatherers). Optionally, NEML2 model +parameters+ can also be gathered from MOOSE by gatherers given in [!param](/UserObjects/NEML2ModelExecutor/param_gatherers). -Currently, three types of gatherers are available: - -- [MOOSEMaterialPropertyToNEML2](MOOSEMaterialPropertyToNEML2.md) gathers material property stored at each quadrature point. -- [MOOSEVariableToNEML2](MOOSEVariableToNEML2.md) gathers (auxiliary) variables interpolated at quadrature points. -- [MOOSEPostprocessorToNEML2](MOOSEPostprocessorToNEML2.md) gathers postprocessor value broadcast to all quadrature points. - Each model +output+ and its +derivatives+ with respect to input variables and model parameters can be retireved by a [NEML2ToMOOSEMaterialProperty](NEML2ToMOOSEMaterialProperty.md) material object. ## NEML2 model execution diff --git a/framework/doc/content/syntax/NEML2/index.md b/framework/doc/content/syntax/NEML2/index.md index ed2e421c413a..e35e25ab0818 100644 --- a/framework/doc/content/syntax/NEML2/index.md +++ b/framework/doc/content/syntax/NEML2/index.md @@ -35,29 +35,21 @@ In each sub-block, there are a total of 6 groups of parameters that can be speci The configuration of model is controlled by parameters such as [!param](/NEML2/model), [!param](/NEML2/verbose), [!param](/NEML2/device), etc., each of which is explained in the syntax documentation at the bottom of the page. -The other 5 groups of parameters are all related to data transfer between MOOSE and NEML2. The 2nd and the 3rd groups of parameters correspond to the transfer of data +from MOOSE to NEML2+. The 4th, 5th and the 6th groups of parameters correspond to the transfer of data +from NEML2 to MOOSE+. +[!param](/NEML2/input_types) is a list of enums denoting the type of the MOOSE data structure used to hold the input variables. The following enums are supported -Each group has three parameters in the following form: - -- `moose_<*>_types`: List of types denoting the type of the MOOSE data structure. -- `moose_<*>s`: Names of quantities to be transferred from/to MOOSE. -- `neml2_<*>s`: Names of quantities to be transferred from/to NEML2. - -where `<*>` are placeholders representing the data being transferred, e.g., `input`, `parameter`, `output`, `derivative`, `parameter_derivative`. Using `input` as an example, the three parameters are - -- `moose_input_types` -- `moose_inputs` -- `neml2_inputs` +- `TIME`: Simulation time. +- `SCALAR`: The input variables are retrieved from a scalar variable and broadcast to all quadrature points. +- `FUNCTION`: The input variables are retrieved from a function evaluated at each quadrature points. +- `VARIABLE`: The input variables are retrieved from (auxiliary) variables interpolated at each quadrature point. +- `MATERIAL`: The input variables are retrieved from material properties stored at each quadrature point. -The length of the three lists must be the same. [!param](/NEML2/moose_input_types) is a list of enums denoting the type of the MOOSE data structure used to hold the input variables. The following enums are supported +All NEML2 input variables are automatically retrieved from the host MOOSE simulation. Quantities with the same name as each input variable are retrieved. An error is raised if ambiguity exists, in which case [!param](/NEML2/input_types) and [!param](/NEML2/inputs) can be used to explicitly specify the type of quantities to be retrieved. -- `MATERIAL`: The input variables are retrieved from material properties stored at each quadrature point. -- `VARIABLE`: The input variables are retrieved from (auxiliary) variables interpolated at each quadrature point. -- `POSTPROCESSOR`: The input variables are retrieved from a postprocessor and broadcast to all quadrature points. +All NEML2 output variables are retrieved and stored as MOOSE material properties after each evaluation, unless [!param](/NEML2/auto_output) is set to `false`. -Currently, for the groups of parameters that control the data transfer from NEML2 to MOOSE, only the `MATERIAL` is supported, i.e., NEML2 output variables and derivatives can only be transferred to MOOSE material properties. +For stateful variables, i.e., input variables needing values from previous time steps (usually with suffix `~N` with `N` being the number of steps backward in time), the corresponding MOOSE quantities from previous time steps are automatically retrieved. The advance of stateful variables is managed by the MOOSE native material system, unless [!param](/NEML2/manage_state_advance) is set to true, in which case NEML2 handles the storage and advance of stateful variables. Note that currently `manage_state_advance = true` is not compatible with mesh change events. -It is worth noting that for [!param](/NEML2/neml2_derivatives) and [!param](/NEML2/neml2_parameter_derivatives), a pair of names must be specified for each entry. The first name in the pair denotes the quantity (NEML2 output variable) to take derivative of, and the second name in the pair denotes the quantity (NEML2 input variable or model parameter) to take derivative with respect to. +It is worth noting that for [!param](/NEML2/neml2_derivatives) and [!param](/NEML2/neml2_parameter_derivatives), a pair of names must be specified for each entry. The first name in the pair denotes the quantity (NEML2 output variable) to take derivative of, and the second name in the pair denotes the quantity (NEML2 input variable or model parameter) to take derivative with respect to. Pairs are delimited by `;`. ## Inspect NEML2 information diff --git a/framework/include/neml2/actions/NEML2Action.h b/framework/include/neml2/actions/NEML2Action.h index 2cc170a31266..871344c642c4 100644 --- a/framework/include/neml2/actions/NEML2Action.h +++ b/framework/include/neml2/actions/NEML2Action.h @@ -16,13 +16,15 @@ #endif #include "Action.h" +#include "NEML2Utils.h" +#include "DerivativeMaterialPropertyNameInterface.h" class NEML2ActionCommon; /** * Action to set up NEML2 objects. */ -class NEML2Action : public Action +class NEML2Action : public Action, public DerivativeMaterialPropertyNameInterface { public: static InputParameters validParams(); @@ -38,78 +40,47 @@ class NEML2Action : public Action const FileName & fname() const { return _fname; } - enum class MOOSEIOType - { - MATERIAL, - VARIABLE, - POSTPROCESSOR - }; - - struct MOOSEIO - { - const std::string name; - const MOOSEIOType type; - }; - - struct NEML2IO - { - const neml2::VariableName name; - const neml2::TensorType type; - }; - - struct NEML2Param - { - const std::string name; - const neml2::TensorType type; - }; - struct VariableMapping { - const MOOSEIO moose; - const NEML2IO neml2; + std::string name; + NEML2Utils::MOOSEIOType moose_type; + neml2::TensorType neml2_type; + std::size_t history_order; }; struct ParameterMapping { - const MOOSEIO moose; - const NEML2Param neml2; + std::string name; + NEML2Utils::MOOSEIOType moose_type; + neml2::TensorType neml2_type; }; struct DerivativeMapping { - const MOOSEIO moose; - const struct NEML2Derivative - { - const NEML2IO y; - const NEML2IO x; - } neml2; - }; - - struct ParameterDerivativeMapping - { - const MOOSEIO moose; - const struct NEML2Derivative - { - const NEML2IO y; - const NEML2Param x; - } neml2; + std::string name; + std::string y; + std::string x; }; /// Set up MOOSE-NEML2 input variable mappings void setupInputMappings(const neml2::Model &); - /// Set up MOOSE-NEML2 model parameter mappings - void setupParameterMappings(const neml2::Model &); - /// Set up MOOSE-NEML2 output variable mappings void setupOutputMappings(const neml2::Model &); + /// Set up MOOSE-NEML2 model parameter mappings + void setupParameterMappings(const neml2::Model &); + /// Set up MOOSE-NEML2 derivative mappings void setupDerivativeMappings(const neml2::Model &); /// Set up MOOSE-NEML2 parameter derivative mappings void setupParameterDerivativeMappings(const neml2::Model &); + /// Infer the MOOSE IO type from the variable name and type + NEML2Utils::MOOSEIOType inferMOOSEIOType(const neml2::VariableName & name, + const neml2::TensorType & type) const; + /// Name of the NEML2 input file FileName _fname; @@ -132,7 +103,7 @@ class NEML2Action : public Action std::vector _derivs; /// MOOSE-NEML2 parameter derivative mappings - std::vector _param_derivs; + std::vector _param_derivs; #endif /// Name of the NEML2Executor user object @@ -144,6 +115,9 @@ class NEML2Action : public Action /// Blocks this sub-block action applies to const std::vector _block; + /// Input variables to skip (i.e., not to set up mappings for) + std::vector _skip_input_variables; + /// Material property initial conditions std::map _initialize_output_values; @@ -153,22 +127,17 @@ class NEML2Action : public Action private: #ifdef NEML2_ENABLED /// Get parameter lists for mapping between MOOSE and NEML2 quantities - template - std::tuple, std::vector, std::vector> - getInputParameterMapping(const std::string & moose_type_opt, - const std::string & moose_name_opt, - const std::string & neml2_name_opt) const + template + std::tuple, std::vector> + getInputParameterMapping(const std::string & source_opt, const std::string & name_opt) const { - const auto moose_types = getParam(moose_type_opt).getSetValueIDs(); - const auto moose_names = getParam>(moose_name_opt); - const auto neml2_names = getParam>(neml2_name_opt); + const auto moose_types = getParam(source_opt).getSetValueIDs(); + const auto neml2_names = getParam>(name_opt); - if (moose_types.size() != moose_names.size()) - paramError(moose_name_opt, moose_name_opt, " must have the same length as ", moose_type_opt); - if (moose_names.size() != neml2_names.size()) - paramError(moose_name_opt, moose_name_opt, " must have the same length as ", neml2_name_opt); + if (moose_types.size() != neml2_names.size()) + paramError(source_opt, source_opt, " must have the same length as ", name_opt); - return {moose_types, moose_names, neml2_names}; + return {moose_types, neml2_names}; } /// Print a summary of the NEML2 model diff --git a/framework/include/neml2/actions/NEML2ActionCommon.h b/framework/include/neml2/actions/NEML2ActionCommon.h index 73d1e0a82dd4..0566c6d3c363 100644 --- a/framework/include/neml2/actions/NEML2ActionCommon.h +++ b/framework/include/neml2/actions/NEML2ActionCommon.h @@ -20,17 +20,17 @@ * a = 1 * b = 2 * c = 3 - * [block1] + * [model1] * d = 4 * e = 5 * block = 1 * [] - * [block2] + * [model2] * d = 6 * e = 7 * block = 2 * [] - * [block3] + * [model3] * d = 8 * e = 9 * block = 3 @@ -39,7 +39,7 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * This object defines input parameters a, b, and c, which will be applied to each of the - * block-restricted NEML2Action: block1, block2, and block3. + * block-restricted NEML2Action: model1, model2, and model3. */ class NEML2ActionCommon : public Action { diff --git a/framework/include/neml2/interfaces/MOOSEToNEML2.h b/framework/include/neml2/interfaces/MOOSEToNEML2.h index 93558db7efd5..1a23586aa153 100644 --- a/framework/include/neml2/interfaces/MOOSEToNEML2.h +++ b/framework/include/neml2/interfaces/MOOSEToNEML2.h @@ -33,56 +33,17 @@ class MOOSEToNEML2 MOOSEToNEML2(const InputParameters & params); #ifdef NEML2_ENABLED - enum class Mode - { - VARIABLE, - OLD_VARIABLE, - PARAMETER, - UNDEFINED - }; - - /** - * Change the mode of operation - * - * The NEML2ModelExecutor user object performs run-time introspection of the NEML2 model to - * determine if the supplied name is for a NEML2 variable or for a NEML2 model parameter. - * It then uses this method to change the mode of operation of the MOOSEToNEML2 gatherer. - */ - void setMode(Mode) const; - - /// Get the current mode of operation - Mode getMode() const { return _mode; } - - /// Perform error checking after _mode has been set - virtual void checkMode() const; - - /// Raw name of the NEML2 variable/parameter - const std::string & NEML2Name() const { return _raw_name; } - - /// Name of the NEML2 input variable (only meaningful when _mode == VARIABLE) - const neml2::VariableName & NEML2VariableName() const; - - /// Name of the NEML2 parameter (only meaningful when _mode == PARAMETER) - const std::string & NEML2ParameterName() const; + /// Name of the NEML2 variable/parameter + const std::string & NEML2Name() const { return _neml2_name; } /// Convert data gathered from MOOSE into neml2::Tensor virtual neml2::Tensor gatheredData() const = 0; /// Insert the gathered data into the NEML2 material model - void insertInto(neml2::ValueMap &, std::map &) const; - -protected: - /// Whether we should insert into NEML2 input variable or NEML2 model parameter - mutable Mode _mode; - - /// NEML2 input variable to transfer data to - mutable neml2::VariableName _neml2_variable; - - /// NEML2 parameter to transfer data to - mutable std::string _neml2_parameter; + void insertInto(std::map &) const; private: - /// Raw name of the input variable or model parameter - const std::string _raw_name; + /// Name of the input variable or model parameter + const std::string _neml2_name; #endif }; diff --git a/framework/include/neml2/userobjects/MOOSEMaterialPropertyToNEML2.h b/framework/include/neml2/userobjects/MOOSEMaterialPropertyToNEML2.h deleted file mode 100644 index fe858e9a268b..000000000000 --- a/framework/include/neml2/userobjects/MOOSEMaterialPropertyToNEML2.h +++ /dev/null @@ -1,44 +0,0 @@ -//* This file is part of the MOOSE framework -//* https://mooseframework.inl.gov -//* -//* All rights reserved, see COPYRIGHT for full restrictions -//* https://github.com/idaholab/moose/blob/master/COPYRIGHT -//* -//* Licensed under LGPL 2.1, please see LICENSE for details -//* https://www.gnu.org/licenses/lgpl-2.1.html - -#pragma once - -#include "MOOSEToNEML2Batched.h" - -#include "RankTwoTensor.h" -#include "SymmetricRankTwoTensor.h" - -/** - * Gather a MOOSE material property for insertion into the NEML2 model. - */ -template -class MOOSEMaterialPropertyToNEML2 : public MOOSEToNEML2Batched -{ -public: - static InputParameters validParams(); - - MOOSEMaterialPropertyToNEML2(const InputParameters & params); - -#ifdef NEML2_ENABLED -protected: - const MooseArray & elemMOOSEData() const override { return _mat_prop.get(); } - - /// MOOSE material property to read data from - const MaterialProperty & _mat_prop; -#endif -}; - -#define DefineMOOSEMaterialPropertyToNEML2Alias(T, alias) \ - using MOOSE##alias##MaterialPropertyToNEML2 = MOOSEMaterialPropertyToNEML2; \ - using MOOSEOld##alias##MaterialPropertyToNEML2 = MOOSEMaterialPropertyToNEML2 - -DefineMOOSEMaterialPropertyToNEML2Alias(Real, Real); -DefineMOOSEMaterialPropertyToNEML2Alias(RankTwoTensor, RankTwoTensor); -DefineMOOSEMaterialPropertyToNEML2Alias(SymmetricRankTwoTensor, SymmetricRankTwoTensor); -DefineMOOSEMaterialPropertyToNEML2Alias(RealVectorValue, RealVectorValue); diff --git a/framework/include/neml2/userobjects/MOOSEPostprocessorToNEML2.h b/framework/include/neml2/userobjects/MOOSEPostprocessorToNEML2.h deleted file mode 100644 index d8dc35b7399d..000000000000 --- a/framework/include/neml2/userobjects/MOOSEPostprocessorToNEML2.h +++ /dev/null @@ -1,35 +0,0 @@ -//* This file is part of the MOOSE framework -//* https://mooseframework.inl.gov -//* -//* All rights reserved, see COPYRIGHT for full restrictions -//* https://github.com/idaholab/moose/blob/master/COPYRIGHT -//* -//* Licensed under LGPL 2.1, please see LICENSE for details -//* https://www.gnu.org/licenses/lgpl-2.1.html - -#pragma once - -#include "MOOSEToNEML2Unbatched.h" - -/** - * Gather a MOOSE postprocessor value for insertion into the NEML2 model. - */ -template -class MOOSEPostprocessorToNEML2Templ : public MOOSEToNEML2Unbatched -{ -public: - static InputParameters validParams(); - - MOOSEPostprocessorToNEML2Templ(const InputParameters & params); - -#ifdef NEML2_ENABLED - neml2::Tensor gatheredData() const override; - -protected: - /// Coupled MOOSE postprocessor value to read data from - const Real & _moose_pp; -#endif -}; - -using MOOSEPostprocessorToNEML2 = MOOSEPostprocessorToNEML2Templ<0>; -using MOOSEOldPostprocessorToNEML2 = MOOSEPostprocessorToNEML2Templ<1>; diff --git a/framework/include/neml2/userobjects/MOOSEQuantityToNEML2.h b/framework/include/neml2/userobjects/MOOSEQuantityToNEML2.h new file mode 100644 index 000000000000..b807b87e64c3 --- /dev/null +++ b/framework/include/neml2/userobjects/MOOSEQuantityToNEML2.h @@ -0,0 +1,75 @@ +//* This file is part of the MOOSE framework +//* https://mooseframework.inl.gov +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#pragma once + +#include "MOOSEToNEML2.h" +#include "NEML2Utils.h" +#include "ElementUserObject.h" + +#include "RankTwoTensor.h" +#include "SymmetricRankTwoTensor.h" + +/** + * Gather a MOOSE quantity for insertion into the NEML2 model. + */ +template +class MOOSEQuantityToNEML2 : public MOOSEToNEML2, public ElementUserObject +{ +public: + static InputParameters validParams(); + + MOOSEQuantityToNEML2(const InputParameters & params); + +#ifndef NEML2_ENABLED + void initialize() override {} + void execute() override {} + void finalize() override {} + void threadJoin(const UserObject &) override {} +#else + void initialize() override; + void execute() override; + void finalize() override {} + void threadJoin(const UserObject &) override; + + neml2::Tensor gatheredData() const override; + +protected: + T qpData(unsigned int) const; + + /// MOOSE quantity type to read from + const NEML2Utils::MOOSEIOType _type; + + ///@{ + /// candidate MOOSE quantities to read data from + const VariableValue * _var_scalar = nullptr; + const VariableValue * _var_scalar_old = nullptr; + const Function * _func = nullptr; + const MaterialProperty * _mat_prop = nullptr; + const MaterialProperty * _mat_prop_old = nullptr; + const VariableValue * _var = nullptr; + const VariableValue * _var_old = nullptr; + ///@} + + /// Whether the gathered data should be batched + bool _batched = false; + + /// Intermediate data buffer, filled during the element loop + std::vector _buffer; +#endif +}; + +#define defineMOOSEQuantityToNEML2(T) \ + using MOOSE##T##ToNEML2 = MOOSEQuantityToNEML2; \ + using MOOSEOld##T##ToNEML2 = MOOSEQuantityToNEML2 +defineMOOSEQuantityToNEML2(Real); +defineMOOSEQuantityToNEML2(RankTwoTensor); +defineMOOSEQuantityToNEML2(SymmetricRankTwoTensor); +defineMOOSEQuantityToNEML2(RealVectorValue); +#undef defineMOOSEQuantityToNEML2 diff --git a/framework/include/neml2/userobjects/MOOSEToNEML2Batched.h b/framework/include/neml2/userobjects/MOOSEToNEML2Batched.h deleted file mode 100644 index b95573e84108..000000000000 --- a/framework/include/neml2/userobjects/MOOSEToNEML2Batched.h +++ /dev/null @@ -1,116 +0,0 @@ -//* This file is part of the MOOSE framework -//* https://mooseframework.inl.gov -//* -//* All rights reserved, see COPYRIGHT for full restrictions -//* https://github.com/idaholab/moose/blob/master/COPYRIGHT -//* -//* Licensed under LGPL 2.1, please see LICENSE for details -//* https://www.gnu.org/licenses/lgpl-2.1.html - -#pragma once - -#include "MOOSEToNEML2.h" -#include "ElementUserObject.h" - -/** - * @brief Generic gatherer for collecting "batched" MOOSE data for NEML2 - * - * It is generic in the sense that it can be used for most MOOSE data types that take the form of - * MooseArray. - * - * It is not so generic in the sense that the collected data is always a std::vector of - * MooseArray, where the vector size is generally the number of elements this ElementUserObject - * operates on, and the MooseArray size is generally the number of quadrature points in each - * element. - * - * @tparam T Type of the underlying MOOSE data, e.g., Real, SymmetricRankTwoTensor, etc. - */ -template -class MOOSEToNEML2Batched : public MOOSEToNEML2, public ElementUserObject -{ -public: - static InputParameters validParams(); - - MOOSEToNEML2Batched(const InputParameters & params); - -#ifndef NEML2_ENABLED - void initialize() override {} - void execute() override {} - void finalize() override {} - void threadJoin(const UserObject &) override {} -#else - void initialize() override; - void execute() override; - void finalize() override {} - void threadJoin(const UserObject &) override; - - neml2::Tensor gatheredData() const override; - - // The number of batches - std::size_t size() const { return _buffer.size(); } - -protected: - /// MOOSE data for the current element - virtual const MooseArray & elemMOOSEData() const = 0; - - /// Intermediate data buffer, filled during the element loop - std::vector _buffer; -#endif -}; - -template -InputParameters -MOOSEToNEML2Batched::validParams() -{ - auto params = MOOSEToNEML2::validParams(); - params += ElementUserObject::validParams(); - - // Since we use the NEML2 model to evaluate the residual AND the Jacobian at the same time, we - // want to execute this user object only at execute_on = LINEAR (i.e. during residual evaluation). - // The NONLINEAR exec flag below is for computing Jacobian during automatic scaling. - ExecFlagEnum execute_options = MooseUtils::getDefaultExecFlagEnum(); - execute_options = {EXEC_INITIAL, EXEC_LINEAR, EXEC_NONLINEAR}; - params.set("execute_on") = execute_options; - - return params; -} - -template -MOOSEToNEML2Batched::MOOSEToNEML2Batched(const InputParameters & params) - : MOOSEToNEML2(params), ElementUserObject(params) -{ -} - -#ifdef NEML2_ENABLED -template -void -MOOSEToNEML2Batched::initialize() -{ - _buffer.clear(); -} - -template -void -MOOSEToNEML2Batched::execute() -{ - const auto & elem_data = this->elemMOOSEData(); - for (auto i : index_range(elem_data)) - _buffer.push_back(elem_data[i]); -} - -template -void -MOOSEToNEML2Batched::threadJoin(const UserObject & uo) -{ - // append vectors - const auto & m2n = static_cast &>(uo); - _buffer.insert(_buffer.end(), m2n._buffer.begin(), m2n._buffer.end()); -} - -template -neml2::Tensor -MOOSEToNEML2Batched::gatheredData() const -{ - return NEML2Utils::fromBlob(_buffer); -} -#endif diff --git a/framework/include/neml2/userobjects/MOOSEToNEML2Unbatched.h b/framework/include/neml2/userobjects/MOOSEToNEML2Unbatched.h deleted file mode 100644 index 0fe9d2ce129b..000000000000 --- a/framework/include/neml2/userobjects/MOOSEToNEML2Unbatched.h +++ /dev/null @@ -1,25 +0,0 @@ -//* This file is part of the MOOSE framework -//* https://mooseframework.inl.gov -//* -//* All rights reserved, see COPYRIGHT for full restrictions -//* https://github.com/idaholab/moose/blob/master/COPYRIGHT -//* -//* Licensed under LGPL 2.1, please see LICENSE for details -//* https://www.gnu.org/licenses/lgpl-2.1.html - -#pragma once - -#include "MOOSEToNEML2.h" -#include "GeneralUserObject.h" - -class MOOSEToNEML2Unbatched : public MOOSEToNEML2, public GeneralUserObject -{ -public: - static InputParameters validParams(); - - MOOSEToNEML2Unbatched(const InputParameters & params); - - void initialize() override {} - void execute() override {} - void finalize() override {} -}; diff --git a/framework/include/neml2/userobjects/MOOSEVariableToNEML2.h b/framework/include/neml2/userobjects/MOOSEVariableToNEML2.h deleted file mode 100644 index 6204616deb45..000000000000 --- a/framework/include/neml2/userobjects/MOOSEVariableToNEML2.h +++ /dev/null @@ -1,35 +0,0 @@ -//* This file is part of the MOOSE framework -//* https://mooseframework.inl.gov -//* -//* All rights reserved, see COPYRIGHT for full restrictions -//* https://github.com/idaholab/moose/blob/master/COPYRIGHT -//* -//* Licensed under LGPL 2.1, please see LICENSE for details -//* https://www.gnu.org/licenses/lgpl-2.1.html - -#pragma once - -#include "MOOSEToNEML2Batched.h" - -/** - * Gather a MOOSE variable for insertion into the NEML2 model. - */ -template -class MOOSEVariableToNEML2Templ : public MOOSEToNEML2Batched -{ -public: - static InputParameters validParams(); - - MOOSEVariableToNEML2Templ(const InputParameters & params); - -#ifdef NEML2_ENABLED -protected: - const MooseArray & elemMOOSEData() const override { return _moose_variable; } - - /// Coupled MOOSE variable to read data from - const VariableValue & _moose_variable; -#endif -}; - -using MOOSEVariableToNEML2 = MOOSEVariableToNEML2Templ<0>; -using MOOSEOldVariableToNEML2 = MOOSEVariableToNEML2Templ<1>; diff --git a/framework/include/neml2/userobjects/NEML2ModelExecutor.h b/framework/include/neml2/userobjects/NEML2ModelExecutor.h index 97d3595315e6..8a26124e3516 100644 --- a/framework/include/neml2/userobjects/NEML2ModelExecutor.h +++ b/framework/include/neml2/userobjects/NEML2ModelExecutor.h @@ -72,9 +72,6 @@ class NEML2ModelExecutor : public NEML2ModelInterface /// Fill input variables and model parameters using the gatherers virtual void fillInputs(); - /// Apply the predictor to set current trial state - virtual void applyPredictor(); - /// Perform the material update virtual bool solve(); @@ -84,14 +81,14 @@ class NEML2ModelExecutor : public NEML2ModelInterface /// Expand tensor shapes if necessary to conformal sizes virtual void expandInputs(); - /// Update cached inputs/outputs for on-device state advance - void advanceDeviceCaches(); + /// Save stateful variables for on-device state advance + void advanceState(); /// The NEML2BatchIndexGenerator used to generate the element-to-batch-index map const NEML2BatchIndexGenerator & _batch_index_generator; /// Advance state on device (rather than via MOSOE material properties) - const bool _keep_tensors_on_device; + const bool _manage_state_advance; /// Dump input tensor info on failure to aid debugging const bool _debug_inputs_on_failure; @@ -108,18 +105,12 @@ class NEML2ModelExecutor : public NEML2ModelInterface /// The output variables of the material model neml2::ValueMap _out; - /// Cached state outputs from the last successful step (for on-device advance) - neml2::ValueMap _device_state_cache; - - /// Cached force inputs from the last successful step (for on-device advance) - neml2::ValueMap _device_forces_cache; + /// Cached variables from the last successful step (for on-device advance) + neml2::ValueMap _state_vars; /// The derivative of the output variables w.r.t. the input variables neml2::DerivMap _dout_din; - // set of variables to skip - std::set _skip_vars; - // set of gathered NEML2 input variables std::set _gathered_variable_names; @@ -128,6 +119,7 @@ class NEML2ModelExecutor : public NEML2ModelInterface /// MOOSE data gathering user objects std::vector _gatherers; + std::vector _param_gatherers; /// set of output variables that were retrieved (by other objects) mutable neml2::ValueMap _retrieved_outputs; @@ -139,12 +131,6 @@ class NEML2ModelExecutor : public NEML2ModelInterface mutable std::map> _retrieved_parameter_derivatives; - /// Whether the model has any state variable - bool _has_state = false; - - /// Whether the model has any old state variable - bool _has_old_state = false; - private: /// Whether an error was encountered bool _error; diff --git a/framework/include/neml2/utils/NEML2Utils.h b/framework/include/neml2/utils/NEML2Utils.h index e1bf1f595301..722b26546d7e 100644 --- a/framework/include/neml2/utils/NEML2Utils.h +++ b/framework/include/neml2/utils/NEML2Utils.h @@ -14,8 +14,6 @@ #ifdef NEML2_ENABLED #include "neml2/tensors/tensors.h" -#include "neml2/base/LabeledAxisAccessor.h" -#include "neml2/base/Parser.h" #include "neml2/base/Factory.h" #include "neml2/models/Model.h" #include "RankTwoTensor.h" @@ -34,6 +32,19 @@ namespace NEML2Utils { #ifdef NEML2_ENABLED +enum class MOOSEIOType +{ + // unbatched + TIME, + SCALAR, + // batched + FUNCTION, + VARIABLE, + MATERIAL +}; + +std::string stringify(MOOSEIOType type); + /** * @brief Get the NEML2 Model * @@ -44,15 +55,6 @@ namespace NEML2Utils std::shared_ptr getModel(neml2::Factory & factory, const std::string & name, neml2::Dtype dtype = neml2::kFloat64); -/// Assert that the NEML2 variable name sits on either the forces or the state subaxis -void assertVariable(const neml2::VariableName &); - -/// Assert that the NEML2 variable name sits on either the old_forces or the old_state subaxis -void assertOldVariable(const neml2::VariableName &); - -/// Parse a raw string into NEML2 variable name -neml2::VariableName parseVariableName(const std::string &); - template struct Layout { diff --git a/framework/src/neml2/actions/NEML2Action.C b/framework/src/neml2/actions/NEML2Action.C index 112256a3e956..f0653c432ecc 100644 --- a/framework/src/neml2/actions/NEML2Action.C +++ b/framework/src/neml2/actions/NEML2Action.C @@ -16,7 +16,8 @@ #ifdef NEML2_ENABLED #include "neml2/neml2.h" -#include "neml2/base/Parser.h" +#include "neml2/base/Settings.h" +#include "neml2/models/VariableBase.h" #endif registerMooseAction("MooseApp", NEML2Action, "parse_neml2"); @@ -82,6 +83,9 @@ NEML2Action::NEML2Action(const InputParameters & params) const auto & common_action = getCommonAction(); sub_block_params.applyParameters(common_action.parameters()); + // Variables to skip + _skip_input_variables = getParam>("skip_input_variables"); + // Set up optional output variable initialization auto init_vars = getParam>("initialize_outputs"); auto init_vals = getParam>("initialize_output_values"); @@ -128,6 +132,15 @@ NEML2Action::act() #else +static std::string +obscureObjectName(const std::string & name, + const std::string & prefix, + const std::string & suffix, + const std::string & block) +{ + return "__" + prefix + "_" + name + "_" + suffix + "_" + block + "__"; +} + void NEML2Action::act() { @@ -153,111 +166,54 @@ NEML2Action::act() std::vector gatherers; for (const auto & input : _inputs) { - if (input.moose.type == MOOSEIOType::MATERIAL) - { - auto obj_name = "__moose(" + input.moose.name + ")->neml2(" + - neml2::utils::stringify(input.neml2.name) + ")_" + name() + "__"; - if (!tensor_type_map.count(input.neml2.type)) - mooseError("NEML2 type ", input.neml2.type, " not yet mapped to MOOSE"); - auto obj_moose_type = tensor_type_map.at(input.neml2.type) + "MaterialProperty"; - if (input.neml2.name.is_old_force() || input.neml2.name.is_old_state()) - obj_moose_type = "Old" + obj_moose_type; - auto obj_type = "MOOSE" + obj_moose_type + "ToNEML2"; - auto obj_params = _factory.getValidParams(obj_type); - obj_params.set("from_moose") = input.moose.name; - obj_params.set("to_neml2") = neml2::utils::stringify(input.neml2.name); - obj_params.set>("block") = _block; - _problem->addUserObject(obj_type, obj_name, obj_params); - gatherers.push_back(obj_name); - } - else if (input.moose.type == MOOSEIOType::VARIABLE) - { - auto obj_name = "__moose(" + input.moose.name + ")->neml2(" + - neml2::utils::stringify(input.neml2.name) + ")_" + name() + "__"; - std::string obj_moose_type = "Variable"; - if (input.neml2.name.is_old_force() || input.neml2.name.is_old_state()) - obj_moose_type = "Old" + obj_moose_type; - auto obj_type = "MOOSE" + obj_moose_type + "ToNEML2"; - auto obj_params = _factory.getValidParams(obj_type); - obj_params.set>("from_moose") = {input.moose.name}; - obj_params.set("to_neml2") = neml2::utils::stringify(input.neml2.name); - obj_params.set>("block") = _block; - _problem->addUserObject(obj_type, obj_name, obj_params); - gatherers.push_back(obj_name); - } - else if (input.moose.type == MOOSEIOType::POSTPROCESSOR) - { - auto obj_name = "__moose(" + input.moose.name + ")->neml2(" + - neml2::utils::stringify(input.neml2.name) + ")" + name() + "__"; - auto obj_moose_type = std::string("Postprocessor"); - if (input.neml2.name.is_old_force() || input.neml2.name.is_old_state()) - obj_moose_type = "Old" + obj_moose_type; - auto obj_type = "MOOSE" + obj_moose_type + "ToNEML2"; - auto obj_params = _factory.getValidParams(obj_type); - obj_params.set("from_moose") = input.moose.name; - obj_params.set("to_neml2") = neml2::utils::stringify(input.neml2.name); - _problem->addUserObject(obj_type, obj_name, obj_params); - gatherers.push_back(obj_name); - } - else - paramError("moose_input_types", - "Unsupported type corresponding to the moose input ", - input.moose.name); + auto obj_name = obscureObjectName( + input.name, "moose_to_neml2", std::to_string(input.history_order), name()); + if (!tensor_type_map.count(input.neml2_type)) + mooseError("NEML2 type ", input.neml2_type, " not yet mapped to MOOSE"); + auto obj_moose_type = + (input.history_order == 1 ? "Old" : "") + tensor_type_map.at(input.neml2_type); + auto obj_type = "MOOSE" + obj_moose_type + "ToNEML2"; + auto obj_params = _factory.getValidParams(obj_type); + const auto sep = _model->settings().history_separator(); + obj_params.set("from_moose") = input.name; + obj_params.set("to_neml2") = + neml2::history_name(input.name, input.history_order, sep); + obj_params.set("quantity_type").assign(static_cast(input.moose_type)); + obj_params.set>("block") = _block; + _problem->addUserObject(obj_type, obj_name, obj_params); + gatherers.push_back(obj_name); } // Additional NEML2Kernels that provide input data { - auto kernels = getParam>("moose_input_kernels"); - gatherers.insert(gatherers.end(), kernels.begin(), kernels.end()); + const auto & kernels = getParam>("input_kernels"); + for (const auto & kernel_name : kernels) + { + if (!_model->input_variables().count(kernel_name)) + paramError("input_kernels", + "The NEML2 kernel ", + kernel_name, + " name does not match any NEML2 input variable."); + gatherers.push_back(kernel_name); + } } // MOOSEToNEML2 parameter gatherers std::vector param_gatherers; for (const auto & param : _params) { - if (param.moose.type == MOOSEIOType::MATERIAL) - { - auto obj_name = - "__moose(" + param.moose.name + ")->neml2(" + param.neml2.name + ")_" + name() + "__"; - if (!tensor_type_map.count(param.neml2.type)) - mooseError("NEML2 type ", param.neml2.type, " not yet mapped to MOOSE"); - auto obj_moose_type = tensor_type_map.at(param.neml2.type); - auto obj_type = "MOOSE" + obj_moose_type + "MaterialPropertyToNEML2"; - auto obj_params = _factory.getValidParams(obj_type); - obj_params.set("from_moose") = param.moose.name; - obj_params.set("to_neml2") = param.neml2.name; - obj_params.set>("block") = _block; - _problem->addUserObject(obj_type, obj_name, obj_params); - param_gatherers.push_back(obj_name); - } - else if (param.moose.type == MOOSEIOType::VARIABLE) - { - auto obj_name = - "__moose(" + param.moose.name + ")->neml2(" + param.neml2.name + ")_" + name() + "__"; - auto obj_type = "MOOSEVariableToNEML2"; - auto obj_params = _factory.getValidParams(obj_type); - obj_params.set>("from_moose") = {param.moose.name}; - obj_params.set("to_neml2") = neml2::utils::stringify(param.neml2.name); - obj_params.set>("block") = _block; - _problem->addUserObject(obj_type, obj_name, obj_params); - param_gatherers.push_back(obj_name); - } - else if (param.moose.type == MOOSEIOType::POSTPROCESSOR) - { - auto obj_name = - "__moose(" + param.moose.name + ")->neml2(" + param.neml2.name + ")" + name() + "__"; - auto obj_moose_type = std::string("Postprocessor"); - auto obj_type = "MOOSE" + obj_moose_type + "ToNEML2"; - auto obj_params = _factory.getValidParams(obj_type); - obj_params.set("from_moose") = param.moose.name; - obj_params.set("to_neml2") = param.neml2.name; - _problem->addUserObject(obj_type, obj_name, obj_params); - param_gatherers.push_back(obj_name); - } - else - paramError("moose_parameter_types", - "Unsupported type corresponding to the moose parameter ", - param.moose.name); + auto obj_name = obscureObjectName(param.name, "moose_to_neml2", "", name()); + if (!tensor_type_map.count(param.neml2_type)) + mooseError("NEML2 type ", param.neml2_type, " not yet mapped to MOOSE"); + auto obj_moose_type = tensor_type_map.at(param.neml2_type); + auto obj_type = "MOOSE" + obj_moose_type + "ToNEML2"; + auto obj_params = _factory.getValidParams(obj_type); + obj_params.set("from_moose") = param.name; + obj_params.set("to_neml2") = param.name; + obj_params.set("quantity_type").assign(static_cast(param.moose_type)); + obj_params.set>("block") = _block; + _problem->addUserObject(obj_type, obj_name, obj_params); + param_gatherers.push_back(obj_name); } // The index generator UO @@ -285,196 +241,277 @@ NEML2Action::act() // NEML2ToMOOSE output retrievers for (const auto & output : _outputs) { - if (output.moose.type == MOOSEIOType::MATERIAL) + if (output.moose_type == NEML2Utils::MOOSEIOType::MATERIAL) { - auto obj_name = "__neml2(" + neml2::utils::stringify(output.neml2.name) + ")->moose(" + - output.moose.name + ")_" + name() + "__"; - if (!tensor_type_map.count(output.neml2.type)) - mooseError("NEML2 type ", output.neml2.type, " not yet mapped to MOOSE"); - auto obj_type = "NEML2ToMOOSE" + tensor_type_map.at(output.neml2.type) + "MaterialProperty"; + auto obj_name = obscureObjectName(output.name, "neml2_to_moose", "", name()); + if (!tensor_type_map.count(output.neml2_type)) + mooseError("NEML2 type ", output.neml2_type, " not yet mapped to MOOSE"); + auto obj_type = "NEML2ToMOOSE" + tensor_type_map.at(output.neml2_type) + "MaterialProperty"; auto obj_params = _factory.getValidParams(obj_type); obj_params.set("neml2_executor") = _executor_name; - obj_params.set("to_moose") = output.moose.name; - obj_params.set("from_neml2") = neml2::utils::stringify(output.neml2.name); + obj_params.set("to_moose") = output.name; + obj_params.set("from_neml2") = output.name; obj_params.set>("block") = _block; - if (_initialize_output_values.count(output.moose.name)) + if (_initialize_output_values.count(output.name)) obj_params.set("moose_material_property_init") = - _initialize_output_values[output.moose.name]; - if (_export_output_targets.count(output.moose.name)) - obj_params.set>("outputs") = - _export_output_targets[output.moose.name]; + _initialize_output_values[output.name]; + if (_export_output_targets.count(output.name)) + obj_params.set>("outputs") = _export_output_targets[output.name]; _problem->addMaterial(obj_type, obj_name, obj_params); } else paramError("moose_output_types", "Unsupported type corresponding to the moose output ", - output.moose.name); + output.name); } // NEML2ToMOOSE derivative retrievers for (const auto & deriv : _derivs) { - if (deriv.moose.type == MOOSEIOType::MATERIAL) - { - auto obj_name = "__neml2(d(" + neml2::utils::stringify(deriv.neml2.y.name) + ")/d(" + - neml2::utils::stringify(deriv.neml2.x.name) + "))->moose(" + - deriv.moose.name + ")_" + name() + "__"; - if (!deriv_type_map.count({deriv.neml2.y.type, deriv.neml2.x.type})) - mooseError("NEML2 derivative type for d(", - deriv.neml2.y.type, - ")/d(", - deriv.neml2.x.type, - ") not yet mapped to MOOSE"); - auto deriv_type = deriv_type_map.at({deriv.neml2.y.type, deriv.neml2.x.type}); - if (!tensor_type_map.count(deriv_type)) - mooseError("NEML2 type ", deriv_type, " not yet mapped to MOOSE"); - auto obj_type = "NEML2ToMOOSE" + tensor_type_map.at(deriv_type) + "MaterialProperty"; - auto obj_params = _factory.getValidParams(obj_type); - obj_params.set("neml2_executor") = _executor_name; - obj_params.set("to_moose") = deriv.moose.name; - obj_params.set("from_neml2") = neml2::utils::stringify(deriv.neml2.y.name); - obj_params.set("neml2_input_derivative") = - neml2::utils::stringify(deriv.neml2.x.name); - obj_params.set>("block") = _block; - if (_export_output_targets.count(deriv.moose.name)) - obj_params.set>("outputs") = - _export_output_targets[deriv.moose.name]; - _problem->addMaterial(obj_type, obj_name, obj_params); - } - else - paramError("moose_derivative_types", - "Unsupported type corresponding to the moose derivative ", - deriv.moose.name); + auto obj_name = obscureObjectName(deriv.name, "neml2_to_moose", "", name()); + auto y_type = _model->output_variable(deriv.y).type(); + auto x_type = _model->input_variable(deriv.x).type(); + if (!deriv_type_map.count({y_type, x_type})) + mooseError("NEML2 derivative type for ", deriv.name, " not yet mapped to MOOSE"); + auto deriv_type = deriv_type_map.at({y_type, x_type}); + if (!tensor_type_map.count(deriv_type)) + mooseError("NEML2 type ", deriv_type, " not yet mapped to MOOSE"); + auto obj_type = "NEML2ToMOOSE" + tensor_type_map.at(deriv_type) + "MaterialProperty"; + auto obj_params = _factory.getValidParams(obj_type); + obj_params.set("neml2_executor") = _executor_name; + obj_params.set("to_moose") = deriv.name; + obj_params.set("from_neml2") = deriv.y; + obj_params.set("neml2_input_derivative") = deriv.x; + obj_params.set>("block") = _block; + if (_export_output_targets.count(deriv.name)) + obj_params.set>("outputs") = _export_output_targets[deriv.name]; + _problem->addMaterial(obj_type, obj_name, obj_params); } // NEML2ToMOOSE parameter derivative retrievers for (const auto & param_deriv : _param_derivs) { - if (param_deriv.moose.type == MOOSEIOType::MATERIAL) - { - auto obj_name = "__neml2(d(" + neml2::utils::stringify(param_deriv.neml2.y.name) + ")/d(" + - param_deriv.neml2.x.name + "))->moose(" + param_deriv.moose.name + ")_" + - name() + "__"; - if (!deriv_type_map.count({param_deriv.neml2.y.type, param_deriv.neml2.x.type})) - mooseError("NEML2 derivative type for d(", - param_deriv.neml2.y.type, - ")/d(", - param_deriv.neml2.x.type, - ") not yet mapped to MOOSE"); - auto deriv_type = deriv_type_map.at({param_deriv.neml2.y.type, param_deriv.neml2.x.type}); - if (!tensor_type_map.count(deriv_type)) - mooseError("NEML2 type ", deriv_type, " not yet mapped to MOOSE"); - auto obj_type = "NEML2ToMOOSE" + tensor_type_map.at(deriv_type) + "MaterialProperty"; - auto obj_params = _factory.getValidParams(obj_type); - obj_params.set("neml2_executor") = _executor_name; - obj_params.set("to_moose") = param_deriv.moose.name; - obj_params.set("from_neml2") = - neml2::utils::stringify(param_deriv.neml2.y.name); - obj_params.set("neml2_parameter_derivative") = param_deriv.neml2.x.name; - obj_params.set>("block") = _block; - if (_export_output_targets.count(param_deriv.moose.name)) - obj_params.set>("outputs") = - _export_output_targets[param_deriv.moose.name]; - _problem->addMaterial(obj_type, obj_name, obj_params); - } - else - paramError("moose_parameter_derivative_types", - "Unsupported type corresponding to the moose parameter derivative ", - param_deriv.moose.name); + auto obj_name = obscureObjectName(param_deriv.name, "neml2_to_moose", "", name()); + auto y_type = _model->output_variable(param_deriv.y).type(); + auto x_type = _model->get_parameter(param_deriv.x).type(); + if (!deriv_type_map.count({y_type, x_type})) + mooseError("NEML2 derivative type for ", param_deriv.name, " not yet mapped to MOOSE"); + auto deriv_type = deriv_type_map.at({y_type, x_type}); + if (!tensor_type_map.count(deriv_type)) + mooseError("NEML2 type ", deriv_type, " not yet mapped to MOOSE"); + auto obj_type = "NEML2ToMOOSE" + tensor_type_map.at(deriv_type) + "MaterialProperty"; + auto obj_params = _factory.getValidParams(obj_type); + obj_params.set("neml2_executor") = _executor_name; + obj_params.set("to_moose") = param_deriv.name; + obj_params.set("from_neml2") = param_deriv.y; + obj_params.set("neml2_parameter_derivative") = param_deriv.x; + obj_params.set>("block") = _block; + if (_export_output_targets.count(param_deriv.name)) + obj_params.set>("outputs") = + _export_output_targets[param_deriv.name]; + _problem->addMaterial(obj_type, obj_name, obj_params); } } } +NEML2Utils::MOOSEIOType +NEML2Action::inferMOOSEIOType(const neml2::VariableName & name, + const neml2::TensorType & type) const +{ + // neml2::kScalar can only come from scalar variable, function, or variable + if (type == neml2::TensorType::kScalar) + { + bool is_time = _problem->isTransient() && (name == "t" || name == "time"); + bool has_scalar = _problem->hasScalarVariable(name); + bool has_func = _problem->hasFunction(name); + bool has_var = _problem->hasVariable(name); + if (int(is_time) + int(has_scalar) + int(has_func) + int(has_var) > 1) + mooseError("Trying to infer MOOSE data type for NEML2 variable ", + name, + ". The name matches multiple types (", + (is_time ? "time " : ""), + (has_scalar ? "scalar variable " : ""), + (has_func ? "function " : ""), + (has_var ? "variable " : ""), + "). To avoid ambiguity, please explicitly specify the type in the NEML2 action."); + if (is_time) + return NEML2Utils::MOOSEIOType::TIME; + if (has_scalar) + return NEML2Utils::MOOSEIOType::SCALAR; + if (has_func) + return NEML2Utils::MOOSEIOType::FUNCTION; + if (has_var) + return NEML2Utils::MOOSEIOType::VARIABLE; + // if neither function nor variable exists, let's assume it's a material property + // note that we can't explicitly check if a material property with the given name exists, + // because materials are added _after_ user objects (see Moose.C) + if (!has_func && !has_var) + return NEML2Utils::MOOSEIOType::MATERIAL; + } + + // non-scalar can only come from material properties + return NEML2Utils::MOOSEIOType::MATERIAL; +} + void NEML2Action::setupInputMappings(const neml2::Model & model) { - const auto [moose_input_types, moose_inputs, neml2_inputs] = - getInputParameterMapping( - "moose_input_types", "moose_inputs", "neml2_inputs"); + const auto & kernels = getParam>("input_kernels"); - for (auto i : index_range(moose_inputs)) + // Default mapping + for (const auto & [vname, var] : model.input_variables()) { - auto neml2_input = NEML2Utils::parseVariableName(neml2_inputs[i]); - _inputs.push_back({ - {moose_inputs[i], moose_input_types[i]}, - {neml2_input, model.input_variable(neml2_input).type()}, - }); + // user requested to skip + if (std::find(_skip_input_variables.begin(), _skip_input_variables.end(), var->base_name()) != + _skip_input_variables.end()) + continue; + + // skip if the input is directly provided by a custom MOOSEToNEML2 object + bool gathered_by_kernel = false; + for (const auto & kernel_name : kernels) + if (vname == kernel_name) + { + gathered_by_kernel = true; + break; + } + if (gathered_by_kernel) + continue; + + // skip if manage_state_advance is true and the variable is stateful (history_order > 0), + // because in that case we will gather the variable on the compute device and do not need to set + // up a gatherer for it + if (getParam("manage_state_advance") && var->history_order() > 0) + continue; + + _inputs.push_back({var->base_name(), + inferMOOSEIOType(var->base_name(), var->type()), + var->type(), + var->history_order()}); + } + + // User-specified mapping (overrides default mapping) + const auto [input_types, inputs] = + getInputParameterMapping("input_types", "inputs"); + + for (auto i : index_range(inputs)) + { + // Check if the input variable also appears in skip_input_variables + const auto itr = + std::find(_skip_input_variables.begin(), _skip_input_variables.end(), inputs[i]); + if (itr != _skip_input_variables.end()) + paramError("skip_input_variables", + "The input variable ", + inputs[i], + " is listed in skip_input_variables, but it also appears in inputs. Please " + "remove it from either list."); + // Check if the input variable exists in the NEML2 model + if (model.input_variables().count(inputs[i]) == 0) + paramError("inputs", "The neml2 input variable ", inputs[i], " does not exist."); + // Check if the input variable is already gathered by a custom MOOSEToNEML2 object + bool gathered_by_kernel = false; + for (const auto & kernel_name : kernels) + if (inputs[i] == kernel_name) + { + gathered_by_kernel = true; + break; + } + if (gathered_by_kernel) + paramError("inputs", + "The input variable ", + inputs[i], + " is listed in inputs, but it also appears in input_kernels. Please " + "remove it from either list."); + // Check if the input variable is stateful and manage_state_advance is true + if (getParam("manage_state_advance")) + if (model.input_variable(inputs[i]).history_order() > 0) + paramError( + "inputs", + "The input variable ", + inputs[i], + " is listed in inputs, but it is stateful (history_order > 0) and manage_state_advance " + "is true. Please remove it from inputs, or set manage_state_advance to false."); + + // Get the existing mapping for this neml2 input variable and override it + for (auto & input : _inputs) + if (input.name == inputs[i]) + { + input.moose_type = input_types[i]; + break; + } } } void -NEML2Action::setupParameterMappings(const neml2::Model & model) +NEML2Action::setupOutputMappings(const neml2::Model & model) { - const auto [moose_param_types, moose_params, neml2_params] = - getInputParameterMapping( - "moose_parameter_types", "moose_parameters", "neml2_parameters"); + if (!getParam("auto_output")) + return; - for (auto i : index_range(moose_params)) - _params.push_back({{moose_params[i], moose_param_types[i]}, - {neml2_params[i], model.get_parameter(neml2_params[i]).type()}}); + // Outputs + for (const auto & [name, var] : model.output_variables()) + _outputs.push_back({name, + NEML2Utils::MOOSEIOType::MATERIAL, + var->type(), + /*history_order=*/0}); } void -NEML2Action::setupOutputMappings(const neml2::Model & model) +NEML2Action::setupParameterMappings(const neml2::Model & model) { - const auto [moose_output_types, moose_outputs, neml2_outputs] = - getInputParameterMapping( - "moose_output_types", "moose_outputs", "neml2_outputs"); + // User-specified mapping + const auto [param_types, params] = getInputParameterMapping( + "parameter_types", "parameters"); - for (auto i : index_range(moose_outputs)) + for (auto i : index_range(params)) { - auto neml2_output = NEML2Utils::parseVariableName(neml2_outputs[i]); - _outputs.push_back({ - {moose_outputs[i], moose_output_types[i]}, - {neml2_output, model.output_variable(neml2_output).type()}, - }); + if (model.named_parameters().count(params[i]) == 0) + paramError("parameters", "The neml2 parameter ", params[i], " does not exist."); + const auto & param = model.get_parameter(params[i]); + _params.push_back({params[i], inferMOOSEIOType(params[i], param.type()), param.type()}); } } void NEML2Action::setupDerivativeMappings(const neml2::Model & model) { - const auto [moose_deriv_types, moose_derivs, neml2_derivs] = - getInputParameterMapping>( - "moose_derivative_types", "moose_derivatives", "neml2_derivatives"); + const auto derivs = getParam>>("derivatives"); - for (auto i : index_range(moose_derivs)) + for (auto i : index_range(derivs)) { - if (neml2_derivs[i].size() != 2) - paramError("neml2_derivatives", "The length of each pair in neml2_derivatives must be 2."); - - auto neml2_y = NEML2Utils::parseVariableName(neml2_derivs[i][0]); - auto neml2_x = NEML2Utils::parseVariableName(neml2_derivs[i][1]); - _derivs.push_back({ - {moose_derivs[i], moose_deriv_types[i]}, - {{neml2_y, model.output_variable(neml2_y).type()}, - {neml2_x, model.input_variable(neml2_x).type()}}, - }); + if (derivs[i].size() != 2) + paramError("derivatives", "The length of each pair in derivatives must be 2."); + if (model.output_variables().count(derivs[i][0]) == 0) + paramError("derivatives", "The NEML2 output variable ", derivs[i][0], " does not exist."); + if (model.input_variables().count(derivs[i][1]) == 0) + paramError("derivatives", "The NEML2 input variable ", derivs[i][1], " does not exist."); + + const auto & y = derivs[i][0]; + const auto & x = derivs[i][1]; + const auto deriv_name = derivativePropertyNameFirst(y, x); + _derivs.push_back({deriv_name, y, x}); } } void NEML2Action::setupParameterDerivativeMappings(const neml2::Model & model) { - const auto [moose_param_deriv_types, moose_param_derivs, neml2_param_derivs] = - getInputParameterMapping>( - "moose_parameter_derivative_types", - "moose_parameter_derivatives", - "neml2_parameter_derivatives"); + const auto derivs = getParam>>("parameter_derivatives"); - for (auto i : index_range(moose_param_derivs)) + for (auto i : index_range(derivs)) { - if (neml2_param_derivs[i].size() != 2) - paramError("neml2_parameter_derivatives", - "The length of each pair in neml2_parameter_derivatives must be 2."); - - auto neml2_y = NEML2Utils::parseVariableName(neml2_param_derivs[i][0]); - auto neml2_x = neml2_param_derivs[i][1]; - _param_derivs.push_back({ - {moose_param_derivs[i], moose_param_deriv_types[i]}, - {{neml2_y, model.output_variable(neml2_y).type()}, - {neml2_x, model.get_parameter(neml2_x).type()}}, - }); + if (derivs[i].size() != 2) + paramError("parameter_derivatives", + "The length of each pair in parameter_derivatives must be 2."); + if (model.output_variables().count(derivs[i][0]) == 0) + paramError( + "parameter_derivatives", "The NEML2 output variable ", derivs[i][0], " does not exist."); + if (model.named_parameters().count(derivs[i][1]) == 0) + paramError("parameter_derivatives", "The NEML2 parameter ", derivs[i][1], " does not exist."); + + const auto & y = derivs[i][0]; + const auto & x = derivs[i][1]; + const auto deriv_name = derivativePropertyNameFirst(y, x); + _param_derivs.push_back({deriv_name, y, x}); } } @@ -511,39 +548,31 @@ NEML2Action::printSummary() const << "Transfer between MOOSE and NEML2 " << std::setfill(' ') << COLOR_DEFAULT << std::endl; - // Figure out the longest name length so that we could align the arrows - const auto max_moose_name_length = getLongestMOOSEName(); + _console << "MOOSE --> NEML2" << std::endl; // List input transfer, MOOSE -> NEML2 for (const auto & input : _inputs) - { - _console << std::setw(max_moose_name_length) << std::right - << (input.neml2.name.is_old_force() || input.neml2.name.is_old_state() - ? ("(old) " + input.moose.name) - : input.moose.name) - << " --> " << input.neml2.name << std::endl; - } + _console << " - " << (input.history_order > 0 ? ("(old) " + input.name) : input.name) << " (" + << NEML2Utils::stringify(input.moose_type) << ")" << std::endl; // List parameter transfer, MOOSE -> NEML2 for (const auto & param : _params) - _console << std::setw(max_moose_name_length) << std::right << param.moose.name << " --> " - << param.neml2.name << std::endl; + _console << " - " << param.name << " (" << NEML2Utils::stringify(param.moose_type) << " --> " + << param.neml2_type << ")" << std::endl; + + _console << "MOOSE <-- NEML2" << std::endl; // List output transfer, NEML2 -> MOOSE for (const auto & output : _outputs) - _console << std::setw(max_moose_name_length) << std::right << output.moose.name << " <-- " - << output.neml2.name << std::endl; + _console << " - " << output.name << std::endl; // List derivative transfer, NEML2 -> MOOSE for (const auto & deriv : _derivs) - _console << std::setw(max_moose_name_length) << std::right << deriv.moose.name << " <-- d(" - << deriv.neml2.y.name << ")/d(" << deriv.neml2.x.name << ")" << std::endl; + _console << " - " << deriv.name << std::endl; // List parameter derivative transfer, NEML2 -> MOOSE for (const auto & param_deriv : _param_derivs) - _console << std::setw(max_moose_name_length) << std::right << param_deriv.moose.name - << " <-- d(" << param_deriv.neml2.y.name << ")/d(" << param_deriv.neml2.x.name << ")" - << std::endl; + _console << " - " << param_deriv.name << std::endl; } _console << COLOR_CYAN << std::setw(width) << std::setfill('*') << std::left @@ -559,19 +588,20 @@ NEML2Action::getLongestMOOSEName() const { std::size_t max_moose_name_length = 0; for (const auto & input : _inputs) - max_moose_name_length = - std::max(max_moose_name_length, - input.neml2.name.is_old_force() || input.neml2.name.is_old_state() - ? input.moose.name.size() + 6 - : input.moose.name.size()); // 6 is the length of "(old) " + { + auto n = input.name.size(); + if (input.history_order > 0) + n += 6; // 6 is the length of "(old) " + max_moose_name_length = std::max(max_moose_name_length, n); + } for (const auto & param : _params) - max_moose_name_length = std::max(max_moose_name_length, param.moose.name.size()); + max_moose_name_length = std::max(max_moose_name_length, param.name.size()); for (const auto & output : _outputs) - max_moose_name_length = std::max(max_moose_name_length, output.moose.name.size()); + max_moose_name_length = std::max(max_moose_name_length, output.name.size()); for (const auto & deriv : _derivs) - max_moose_name_length = std::max(max_moose_name_length, deriv.moose.name.size()); + max_moose_name_length = std::max(max_moose_name_length, deriv.name.size()); for (const auto & param_deriv : _param_derivs) - max_moose_name_length = std::max(max_moose_name_length, param_deriv.moose.name.size()); + max_moose_name_length = std::max(max_moose_name_length, param_deriv.name.size()); return max_moose_name_length; } #endif // NEML2_ENABLED diff --git a/framework/src/neml2/actions/NEML2ActionCommon.C b/framework/src/neml2/actions/NEML2ActionCommon.C index 030c376f3337..ddb02e6c004d 100644 --- a/framework/src/neml2/actions/NEML2ActionCommon.C +++ b/framework/src/neml2/actions/NEML2ActionCommon.C @@ -20,71 +20,52 @@ NEML2ActionCommon::commonParams() auto params = NEML2ModelInterface::validParams(); params += NEML2ModelExecutor::actionParams(); - MultiMooseEnum moose_types("MATERIAL VARIABLE POSTPROCESSOR"); + MultiMooseEnum moose_types("TIME SCALAR FUNCTION VARIABLE MATERIAL"); // Inputs - params.addParam("moose_input_types", - moose_types, - "Type of each MOOSE data to be used as NEML2 input variable"); - params.addParam>( - "moose_inputs", {}, "List of MOOSE data to be used as inputs of the material model."); + params.addParam( + "input_types", moose_types, "Type of each MOOSE data to be used as NEML2 input variable"); params.addParam>( - "neml2_inputs", {}, "List of NEML2 input variables corresponding to each MOOSE data."); + "inputs", {}, "List of NEML2 input variables corresponding to each MOOSE data."); params.addParam>( - "moose_input_kernels", {}, "NEML2 kernels defined in MOOSE that provides input data."); + "input_kernels", + {}, + "NEML2 kernels defined in MOOSE that provides input data. The object name must match the " + "input variable name."); // Model parameters - params.addParam("moose_parameter_types", + params.addParam("parameter_types", moose_types, "Type of each MOOSE data to be used as NEML2 model parameter"); params.addParam>( - "moose_parameters", {}, "List of MOOSE data to be used as parameters of the material model."); - params.addParam>( - "neml2_parameters", {}, "List of NEML2 model parameters corresponding to each MOOSE data."); + "parameters", {}, "List of NEML2 model parameters corresponding to each MOOSE data."); - // Outputs - params.addParam( - "moose_output_types", moose_types, "MOOSE types used to hold the NEML2 output variables"); - params.addParam>( - "moose_outputs", {}, "List of MOOSE data used to hold the output of the material model."); - params.addParam>( - "neml2_outputs", {}, "List of NEML2 output variables corresponding to each MOOSE data."); + // Output + params.addParam("auto_output", + true, + "Whether to automatically retrieve all NEML2 output variables as MOOSE " + "material properties."); // Derivatives - params.addParam("moose_derivative_types", - moose_types, - "MOOSE types used to hold the NEML2 variable derivatives"); - params.addParam>( - "moose_derivatives", - {}, - "List of MOOSE data used to hold the derivative of the material model."); params.addParam>>( - "neml2_derivatives", + "derivatives", {}, - "List of pairs of NEML2 variables to take derivatives (i.e., first in " - "the pair w.r.t. the second in the pair)."); + "List of pairs of NEML2 variables to take derivatives (i.e., first in the pair w.r.t. the " + "second in the pair)."); // Parameter derivatives - params.addParam("moose_parameter_derivative_types", - moose_types, - "MOOSE types used to hold the NEML2 parameter derivatives"); - params.addParam>( - "moose_parameter_derivatives", - {}, - "List of MOOSE data used to hold the derivative of the material model " - "w.r.t. model parameters."); params.addParam>>( - "neml2_parameter_derivatives", + "parameter_derivatives", {}, "List of pairs of NEML2 variables to take derivatives (i.e., first in the pair w.r.t. the " "second in the pair)."); // Error checking, logging, etc params.addParam>( - "skip_variables", + "skip_input_variables", {}, "List of NEML2 variables to skip when setting up the model input. If an input variable is " - "skipped, its value will stay zero. If a required input variable is not skipped, an error " + "skipped, its value will stay zero. If a required input variable is skipped, an error " "will be raised."); params.addParam("verbose", true, diff --git a/framework/src/neml2/interfaces/MOOSEToNEML2.C b/framework/src/neml2/interfaces/MOOSEToNEML2.C index 007c5b07a304..bf8efcd94124 100644 --- a/framework/src/neml2/interfaces/MOOSEToNEML2.C +++ b/framework/src/neml2/interfaces/MOOSEToNEML2.C @@ -25,59 +25,14 @@ MOOSEToNEML2::MOOSEToNEML2(const InputParameters & /*params*/) {} #else MOOSEToNEML2::MOOSEToNEML2(const InputParameters & params) - : _mode(Mode::UNDEFINED), _raw_name(params.get("to_neml2")) + : _neml2_name(params.get("to_neml2")) { NEML2Utils::assertNEML2Enabled(); } void -MOOSEToNEML2::setMode(MOOSEToNEML2::Mode m) const +MOOSEToNEML2::insertInto(std::map & map) const { - _mode = m; - - if (_mode == Mode::VARIABLE || _mode == Mode::OLD_VARIABLE) - _neml2_variable = NEML2Utils::parseVariableName(_raw_name); - else if (_mode == Mode::PARAMETER) - _neml2_parameter = _raw_name; - else - mooseError("Encountered invalid Mode in MOOSEToNEML2::setMode"); - - checkMode(); -} - -void -MOOSEToNEML2::checkMode() const -{ - if (_mode == Mode::VARIABLE) - NEML2Utils::assertVariable(_neml2_variable); - if (_mode == Mode::OLD_VARIABLE) - NEML2Utils::assertOldVariable(_neml2_variable); -} - -const neml2::VariableName & -MOOSEToNEML2::NEML2VariableName() const -{ - mooseAssert(_mode == Mode::VARIABLE || _mode == Mode::OLD_VARIABLE, - "Mode must be VARIABLE or OLD_VARIABLE when calling NEML2Variable"); - return _neml2_variable; -} - -const std::string & -MOOSEToNEML2::NEML2ParameterName() const -{ - mooseAssert(_mode == Mode::PARAMETER, "Mode must be PARAMETER when calling NEML2Parameter"); - return _neml2_parameter; -} - -void -MOOSEToNEML2::insertInto(neml2::ValueMap & input, - std::map & params) const -{ - if (_mode == Mode::VARIABLE || _mode == Mode::OLD_VARIABLE) - input[_neml2_variable] = gatheredData(); - else if (_mode == Mode::PARAMETER) - params[_neml2_parameter] = gatheredData(); - else - mooseError("Encountered invalid Mode in MOOSEToNEML2::insertInto"); + map[_neml2_name] = gatheredData(); } #endif diff --git a/framework/src/neml2/materials/NEML2ToMOOSEMaterialProperty.C b/framework/src/neml2/materials/NEML2ToMOOSEMaterialProperty.C index 0bbc15d869b6..87d6dab82996 100644 --- a/framework/src/neml2/materials/NEML2ToMOOSEMaterialProperty.C +++ b/framework/src/neml2/materials/NEML2ToMOOSEMaterialProperty.C @@ -61,17 +61,15 @@ NEML2ToMOOSEMaterialProperty::NEML2ToMOOSEMaterialProperty(const InputParamet _prop0(isParamValid("moose_material_property_init") ? &getMaterialProperty("moose_material_property_init") : nullptr), - _value( - !isParamValid("neml2_input_derivative") - ? (!isParamValid("neml2_parameter_derivative") - ? _execute_neml2_model.getOutput( - NEML2Utils::parseVariableName(getParam("from_neml2"))) - : _execute_neml2_model.getOutputParameterDerivative( - NEML2Utils::parseVariableName(getParam("from_neml2")), - getParam("neml2_parameter_derivative"))) - : _execute_neml2_model.getOutputDerivative( - NEML2Utils::parseVariableName(getParam("from_neml2")), - NEML2Utils::parseVariableName(getParam("neml2_input_derivative")))) + _value(!isParamValid("neml2_input_derivative") + ? (!isParamValid("neml2_parameter_derivative") + ? _execute_neml2_model.getOutput(getParam("from_neml2")) + : _execute_neml2_model.getOutputParameterDerivative( + getParam("from_neml2"), + getParam("neml2_parameter_derivative"))) + : _execute_neml2_model.getOutputDerivative( + getParam("from_neml2"), + getParam("neml2_input_derivative"))) #endif { NEML2Utils::assertNEML2Enabled(); @@ -96,7 +94,10 @@ NEML2ToMOOSEMaterialProperty::computeProperties() // look up start index for current element const auto i = _execute_neml2_model.getBatchIndex(_current_elem->id()); for (_qp = 0; _qp < _qrule->n_points(); ++_qp) - NEML2Utils::copyTensorToMOOSEData(_value.batch_index({neml2::Size(i + _qp)}), _prop[_qp]); + if (_value.batch_dim()) + NEML2Utils::copyTensorToMOOSEData(_value.batch_index({neml2::Size(i + _qp)}), _prop[_qp]); + else + NEML2Utils::copyTensorToMOOSEData(_value, _prop[_qp]); } #endif diff --git a/framework/src/neml2/models/LibtorchModel.C b/framework/src/neml2/models/LibtorchModel.C index 00749c4d2487..c5e93a437585 100644 --- a/framework/src/neml2/models/LibtorchModel.C +++ b/framework/src/neml2/models/LibtorchModel.C @@ -26,13 +26,13 @@ OptionSet LibtorchModel::expected_options() { auto options = Model::expected_options(); - options.set>("inputs"); - options.set>("outputs"); - options.set("outputs").doc() = "The scaled neural network output"; - options.set("file_path"); + options.add>("inputs", "The input variables for the neural network"); + options.add>("outputs", + "The (scaled) output variables for the neural network"); + options.add("file_path", "The path to the neural network file"); // No jitting :/ - options.set("jit") = false; - options.set("jit").suppressed() = true; + options.set("jit", false); + options.suppress("jit"); return options; } diff --git a/framework/src/neml2/userobjects/MOOSEMaterialPropertyToNEML2.C b/framework/src/neml2/userobjects/MOOSEMaterialPropertyToNEML2.C deleted file mode 100644 index 2bec0512135d..000000000000 --- a/framework/src/neml2/userobjects/MOOSEMaterialPropertyToNEML2.C +++ /dev/null @@ -1,51 +0,0 @@ -//* This file is part of the MOOSE framework -//* https://mooseframework.inl.gov -//* -//* All rights reserved, see COPYRIGHT for full restrictions -//* https://github.com/idaholab/moose/blob/master/COPYRIGHT -//* -//* Licensed under LGPL 2.1, please see LICENSE for details -//* https://www.gnu.org/licenses/lgpl-2.1.html - -#include "MOOSEMaterialPropertyToNEML2.h" - -#define registerMOOSEMaterialPropertyToNEML2(alias) \ - registerMooseObject("MooseApp", MOOSE##alias##MaterialPropertyToNEML2); \ - registerMooseObject("MooseApp", MOOSEOld##alias##MaterialPropertyToNEML2) - -registerMOOSEMaterialPropertyToNEML2(Real); -registerMOOSEMaterialPropertyToNEML2(RankTwoTensor); -registerMOOSEMaterialPropertyToNEML2(SymmetricRankTwoTensor); -registerMOOSEMaterialPropertyToNEML2(RealVectorValue); - -template -InputParameters -MOOSEMaterialPropertyToNEML2::validParams() -{ - auto params = MOOSEToNEML2Batched::validParams(); - params.addClassDescription( - "Gather a MOOSE material property of type " + demangle(typeid(T).name()) + - " for insertion into the specified input or model parameter of a NEML2 model."); - params.template addRequiredParam("from_moose", - "MOOSE material property to read from"); - return params; -} - -template -MOOSEMaterialPropertyToNEML2::MOOSEMaterialPropertyToNEML2(const InputParameters & params) - : MOOSEToNEML2Batched(params) -#ifdef NEML2_ENABLED - , - _mat_prop(this->template getGenericMaterialProperty("from_moose", state)) -#endif -{ -} - -#define instantiateMOOSEMaterialPropertyToNEML2(T) \ - template class MOOSEMaterialPropertyToNEML2; \ - template class MOOSEMaterialPropertyToNEML2 - -instantiateMOOSEMaterialPropertyToNEML2(Real); -instantiateMOOSEMaterialPropertyToNEML2(RankTwoTensor); -instantiateMOOSEMaterialPropertyToNEML2(SymmetricRankTwoTensor); -instantiateMOOSEMaterialPropertyToNEML2(RealVectorValue); diff --git a/framework/src/neml2/userobjects/MOOSEPostprocessorToNEML2.C b/framework/src/neml2/userobjects/MOOSEPostprocessorToNEML2.C deleted file mode 100644 index ec1c94281230..000000000000 --- a/framework/src/neml2/userobjects/MOOSEPostprocessorToNEML2.C +++ /dev/null @@ -1,57 +0,0 @@ -//* This file is part of the MOOSE framework -//* https://mooseframework.inl.gov -//* -//* All rights reserved, see COPYRIGHT for full restrictions -//* https://github.com/idaholab/moose/blob/master/COPYRIGHT -//* -//* Licensed under LGPL 2.1, please see LICENSE for details -//* https://www.gnu.org/licenses/lgpl-2.1.html - -#include "MOOSEPostprocessorToNEML2.h" - -registerMooseObject("MooseApp", MOOSEPostprocessorToNEML2); -registerMooseObject("MooseApp", MOOSEOldPostprocessorToNEML2); - -template -InputParameters -MOOSEPostprocessorToNEML2Templ::validParams() -{ - auto params = MOOSEToNEML2Unbatched::validParams(); - params.addClassDescription( - "Gather a MOOSE postprocessor value for insertion into the specified input variable or " - "model parameter of a NEML2 model."); - params.addRequiredParam("from_moose", "MOOSE postprocessor to read from"); - return params; -} - -template <> -MOOSEPostprocessorToNEML2Templ<0>::MOOSEPostprocessorToNEML2Templ(const InputParameters & params) - : MOOSEToNEML2Unbatched(params) -#ifdef NEML2_ENABLED - , - _moose_pp(getPostprocessorValue("from_moose")) -#endif -{ -} - -template <> -MOOSEPostprocessorToNEML2Templ<1>::MOOSEPostprocessorToNEML2Templ(const InputParameters & params) - : MOOSEToNEML2Unbatched(params) -#ifdef NEML2_ENABLED - , - _moose_pp(getPostprocessorValueOld("from_moose")) -#endif -{ -} - -#ifdef NEML2_ENABLED -template -neml2::Tensor -MOOSEPostprocessorToNEML2Templ::gatheredData() const -{ - return neml2::Scalar::full(_moose_pp, neml2::kFloat64); -} -#endif - -template class MOOSEPostprocessorToNEML2Templ<0>; -template class MOOSEPostprocessorToNEML2Templ<1>; diff --git a/framework/src/neml2/userobjects/MOOSEQuantityToNEML2.C b/framework/src/neml2/userobjects/MOOSEQuantityToNEML2.C new file mode 100644 index 000000000000..b2c48ec285e1 --- /dev/null +++ b/framework/src/neml2/userobjects/MOOSEQuantityToNEML2.C @@ -0,0 +1,183 @@ +//* This file is part of the MOOSE framework +//* https://mooseframework.inl.gov +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#include "MOOSEQuantityToNEML2.h" +#include "Function.h" +#include "MooseVariableScalar.h" + +#define registerMOOSEQuantityToNEML2(T) \ + registerMooseObject("MooseApp", MOOSE##T##ToNEML2); \ + registerMooseObject("MooseApp", MOOSEOld##T##ToNEML2) + +registerMOOSEQuantityToNEML2(Real); +registerMOOSEQuantityToNEML2(RankTwoTensor); +registerMOOSEQuantityToNEML2(SymmetricRankTwoTensor); +registerMOOSEQuantityToNEML2(RealVectorValue); + +template +InputParameters +MOOSEQuantityToNEML2::validParams() +{ + auto params = MOOSEToNEML2::validParams(); + params += ElementUserObject::validParams(); + + params.addClassDescription( + "Gather a MOOSE quantity of type " + demangle(typeid(T).name()) + + " for insertion into the specified input or model parameter of a NEML2 model."); + params.template addRequiredParam("from_moose", + "Name of the MOOSE quantity to read from"); + MooseEnum moose_type("TIME SCALAR FUNCTION VARIABLE MATERIAL", "MATERIAL"); + params.template addParam( + "quantity_type", moose_type, "Type of the MOOSE quantity to read from."); + + // Since we use the NEML2 model to evaluate the residual AND the Jacobian at the same time, we + // want to execute this user object only at execute_on = LINEAR (i.e. during residual evaluation). + // The NONLINEAR exec flag below is for computing Jacobian during automatic scaling. + ExecFlagEnum execute_options = MooseUtils::getDefaultExecFlagEnum(); + execute_options = {EXEC_INITIAL, EXEC_LINEAR, EXEC_NONLINEAR}; + params.set("execute_on") = execute_options; + + return params; +} + +template +MOOSEQuantityToNEML2::MOOSEQuantityToNEML2(const InputParameters & params) + : MOOSEToNEML2(params), + ElementUserObject(params) +#ifdef NEML2_ENABLED + , + _type(getParam("quantity_type").getEnum()), + _var_scalar( + _type == NEML2Utils::MOOSEIOType::SCALAR && state == 0 + ? &this->_fe_problem.getScalarVariable(_tid, getParam("from_moose")).sln() + : nullptr), + _var_scalar_old( + _type == NEML2Utils::MOOSEIOType::SCALAR && state == 1 + ? &this->_fe_problem.getScalarVariable(_tid, getParam("from_moose")) + .slnOld() + : nullptr), + _func(_type == NEML2Utils::MOOSEIOType::FUNCTION + ? &this->_fe_problem.getFunction(getParam("from_moose"), _tid) + : nullptr), + _mat_prop( + _type == NEML2Utils::MOOSEIOType::MATERIAL && state == 0 + ? &this->template getMaterialPropertyByName(getParam("from_moose")) + : nullptr), + _mat_prop_old( + _type == NEML2Utils::MOOSEIOType::MATERIAL && state == 1 + ? &this->template getMaterialPropertyOldByName(getParam("from_moose")) + : nullptr), + _var(_type == NEML2Utils::MOOSEIOType::VARIABLE && state == 0 + ? &this->_fe_problem.getStandardVariable(_tid, getParam("from_moose")) + .sln() + : nullptr), + _var_old(_type == NEML2Utils::MOOSEIOType::VARIABLE && state == 1 + ? &this->_fe_problem.getStandardVariable(_tid, getParam("from_moose")) + .slnOld() + : nullptr), + _batched(_type != NEML2Utils::MOOSEIOType::TIME && _type != NEML2Utils::MOOSEIOType::SCALAR) +#endif +{ +} + +#ifdef NEML2_ENABLED +template +void +MOOSEQuantityToNEML2::initialize() +{ + _buffer.clear(); +} + +template +void +MOOSEQuantityToNEML2::execute() +{ + if (!_batched) + return; + + for (unsigned int qp = 0; qp < _qrule->n_points(); qp++) + _buffer.emplace_back(qpData(qp)); +} + +template +void +MOOSEQuantityToNEML2::threadJoin(const UserObject & uo) +{ + if (!_batched) + return; + // append vectors + const auto & m2n = static_cast &>(uo); + _buffer.insert(_buffer.end(), m2n._buffer.begin(), m2n._buffer.end()); +} + +template +neml2::Tensor +MOOSEQuantityToNEML2::gatheredData() const +{ + if (!_batched) + { + switch (_type) + { + case NEML2Utils::MOOSEIOType::TIME: + return state == 0 ? neml2::Scalar::full(_t, neml2::kFloat64) + : neml2::Scalar::full(_t_old, neml2::kFloat64); + case NEML2Utils::MOOSEIOType::SCALAR: + return state == 0 ? neml2::Scalar::full((*_var_scalar)[0], neml2::kFloat64) + : neml2::Scalar::full((*_var_scalar_old)[0], neml2::kFloat64); + case NEML2Utils::MOOSEIOType::FUNCTION: + case NEML2Utils::MOOSEIOType::VARIABLE: + case NEML2Utils::MOOSEIOType::MATERIAL: + mooseError( + "Unbatched quantity cannot be of type MATERIAL or VARIABLE. This should never happen."); + default: + mooseError("Invalid MOOSE quantity type. This should never happen."); + } + } + + return NEML2Utils::fromBlob(_buffer); +} + +template +T +MOOSEQuantityToNEML2::qpData(unsigned int qp) const +{ + mooseAssert( + _batched, + "elemMOOSEData should only be called for batched quantities. This should never happen."); + + // non-scalar type can only be MATERIAL + if constexpr (!std::is_same_v) + return state == 0 ? (*_mat_prop)[qp] : (*_mat_prop_old)[qp]; + else + switch (_type) + { + case NEML2Utils::MOOSEIOType::TIME: + mooseError("Batched quantity cannot be of type TIME. This should never happen."); + case NEML2Utils::MOOSEIOType::SCALAR: + mooseError("Batched quantity cannot be of type SCALAR. This should never happen."); + case NEML2Utils::MOOSEIOType::FUNCTION: + return _func->value(state == 0 ? _t : _t_old, _q_point[qp]); + case NEML2Utils::MOOSEIOType::VARIABLE: + return state == 0 ? (*_var)[qp] : (*_var_old)[qp]; + case NEML2Utils::MOOSEIOType::MATERIAL: + return state == 0 ? (*_mat_prop)[qp] : (*_mat_prop_old)[qp]; + default: + mooseError("Invalid MOOSE quantity type. This should never happen."); + } +} +#endif + +#define instantiateMOOSEQuantityToNEML2(T) \ + template class MOOSEQuantityToNEML2; \ + template class MOOSEQuantityToNEML2 + +instantiateMOOSEQuantityToNEML2(Real); +instantiateMOOSEQuantityToNEML2(RankTwoTensor); +instantiateMOOSEQuantityToNEML2(SymmetricRankTwoTensor); +instantiateMOOSEQuantityToNEML2(RealVectorValue); diff --git a/framework/src/neml2/userobjects/MOOSEToNEML2Unbatched.C b/framework/src/neml2/userobjects/MOOSEToNEML2Unbatched.C deleted file mode 100644 index 37a7432f8b3a..000000000000 --- a/framework/src/neml2/userobjects/MOOSEToNEML2Unbatched.C +++ /dev/null @@ -1,31 +0,0 @@ -//* This file is part of the MOOSE framework -//* https://mooseframework.inl.gov -//* -//* All rights reserved, see COPYRIGHT for full restrictions -//* https://github.com/idaholab/moose/blob/master/COPYRIGHT -//* -//* Licensed under LGPL 2.1, please see LICENSE for details -//* https://www.gnu.org/licenses/lgpl-2.1.html - -#include "MOOSEToNEML2Unbatched.h" - -InputParameters -MOOSEToNEML2Unbatched::validParams() -{ - auto params = MOOSEToNEML2::validParams(); - params += GeneralUserObject::validParams(); - - // Since we use the NEML2 model to evaluate the residual AND the Jacobian at the same time, we - // want to execute this user object only at execute_on = LINEAR (i.e. during residual evaluation). - // The NONLINEAR exec flag below is for computing Jacobian during automatic scaling. - ExecFlagEnum execute_options = MooseUtils::getDefaultExecFlagEnum(); - execute_options = {EXEC_INITIAL, EXEC_LINEAR, EXEC_NONLINEAR}; - params.set("execute_on") = execute_options; - - return params; -} - -MOOSEToNEML2Unbatched::MOOSEToNEML2Unbatched(const InputParameters & params) - : MOOSEToNEML2(params), GeneralUserObject(params) -{ -} diff --git a/framework/src/neml2/userobjects/MOOSEVariableToNEML2.C b/framework/src/neml2/userobjects/MOOSEVariableToNEML2.C deleted file mode 100644 index b4d58a11e5c8..000000000000 --- a/framework/src/neml2/userobjects/MOOSEVariableToNEML2.C +++ /dev/null @@ -1,47 +0,0 @@ -//* This file is part of the MOOSE framework -//* https://mooseframework.inl.gov -//* -//* All rights reserved, see COPYRIGHT for full restrictions -//* https://github.com/idaholab/moose/blob/master/COPYRIGHT -//* -//* Licensed under LGPL 2.1, please see LICENSE for details -//* https://www.gnu.org/licenses/lgpl-2.1.html - -#include "MOOSEVariableToNEML2.h" - -registerMooseObject("MooseApp", MOOSEVariableToNEML2); -registerMooseObject("MooseApp", MOOSEOldVariableToNEML2); - -template -InputParameters -MOOSEVariableToNEML2Templ::validParams() -{ - auto params = MOOSEToNEML2Batched::validParams(); - params.addClassDescription("Gather a MOOSE variable for insertion into the specified input or " - "model parameter of a NEML2 model."); - params.addRequiredCoupledVar("from_moose", "MOOSE variable to read from"); - return params; -} - -template <> -MOOSEVariableToNEML2Templ<0>::MOOSEVariableToNEML2Templ(const InputParameters & params) - : MOOSEToNEML2Batched(params) -#ifdef NEML2_ENABLED - , - _moose_variable(coupledValue("from_moose")) -#endif -{ -} - -template <> -MOOSEVariableToNEML2Templ<1>::MOOSEVariableToNEML2Templ(const InputParameters & params) - : MOOSEToNEML2Batched(params) -#ifdef NEML2_ENABLED - , - _moose_variable(coupledValueOld("from_moose")) -#endif -{ -} - -template class MOOSEVariableToNEML2Templ<0>; -template class MOOSEVariableToNEML2Templ<1>; diff --git a/framework/src/neml2/userobjects/NEML2ModelExecutor.C b/framework/src/neml2/userobjects/NEML2ModelExecutor.C index 88e4c8dea384..a8af105d25b9 100644 --- a/framework/src/neml2/userobjects/NEML2ModelExecutor.C +++ b/framework/src/neml2/userobjects/NEML2ModelExecutor.C @@ -19,6 +19,7 @@ #include "neml2/tensors/functions/jacrev.h" #include "neml2/dispatchers/ValueMapLoader.h" #include "neml2/misc/string_utils.h" +#include "neml2/base/Settings.h" #endif registerMooseObject("MooseApp", NEML2ModelExecutor); @@ -27,15 +28,8 @@ InputParameters NEML2ModelExecutor::actionParams() { auto params = emptyInputParameters(); - // allow user to explicit skip required input variables - params.addParam>( - "skip_inputs", - {}, - "List of NEML2 variables to skip error checking when setting up the model input. If an " - "input variable is skipped, its value will stay zero. If a required input variable is " - "not skipped, an error will be raised."); params.addParam( - "keep_tensors_on_device", + "manage_state_advance", false, "Keep state and forces on the device and advance it to old_state and old_forces without a " "roundtrip through MOOSE materials. This is only recommended for explicit time integration " @@ -82,7 +76,7 @@ NEML2ModelExecutor::NEML2ModelExecutor(const InputParameters & params) #ifdef NEML2_ENABLED , _batch_index_generator(getUserObject("batch_index_generator")), - _keep_tensors_on_device(getParam("keep_tensors_on_device")), + _manage_state_advance(getParam("manage_state_advance")), _debug_inputs_on_failure(getParam("debug_inputs_on_failure")), _output_ready(false), _error_message("") @@ -96,10 +90,6 @@ NEML2ModelExecutor::NEML2ModelExecutor(const InputParameters & params) _depend_uo.insert(gatherer_name); for (const auto & gatherer_name : getParam>("param_gatherers")) _depend_uo.insert(gatherer_name); - - // variables to skip error checking (converting vector to set to prevent duplicate checks) - for (const auto & var_name : getParam>("skip_inputs")) - _skip_vars.insert(NEML2Utils::parseVariableName(var_name)); #endif } @@ -114,22 +104,16 @@ NEML2ModelExecutor::initialSetup() // dependencies (that's already done in the constructor). const auto & uo = getUserObjectByName(gatherer_name, /*is_dependency=*/false); - // the target neml2 variable must exist on the input axis - if (!model().input_axis().has_variable(NEML2Utils::parseVariableName(uo.NEML2Name()))) - mooseError("The MOOSEToNEML2 gatherer named '", - gatherer_name, - "' is gathering MOOSE data for a non-existent NEML2 input variable named '", + // there's no need to gather old/older variables if we're managing state advance + auto sep = model().settings().history_separator(); + auto [base_name, history_order] = neml2::parse_history(uo.NEML2Name(), sep); + if (_manage_state_advance && history_order > 0) + paramError("gatherers", + "The gatherer for history variable `", uo.NEML2Name(), - "'."); + "` is not needed when `manage_state_advance = true`."); - // tell the gatherer to gather for a model input variable - const auto varname = NEML2Utils::parseVariableName(uo.NEML2Name()); - if (varname.is_old_force() || varname.is_old_state()) - uo.setMode(MOOSEToNEML2::Mode::OLD_VARIABLE); - else - uo.setMode(MOOSEToNEML2::Mode::VARIABLE); - - addGatheredVariable(gatherer_name, uo.NEML2VariableName()); + addGatheredVariable(gatherer_name, uo.NEML2Name()); _gatherers.push_back(&uo); } @@ -139,59 +123,25 @@ NEML2ModelExecutor::initialSetup() // gather coupled user objects late to ensure they are constructed. Do not add them as // dependencies (that's already done in the constructor). const auto & uo = getUserObjectByName(gatherer_name, /*is_dependency=*/false); - - // introspect the NEML2 model to figure out if the gatherer UO is gathering for a NEML2 input - // variable or for a NEML2 model parameter - if (model().named_parameters().count(uo.NEML2Name()) != 1) - mooseError("The MOOSEToNEML2 gatherer named '", - gatherer_name, - "' is gathering MOOSE data for a non-existent NEML2 model parameter named '", - uo.NEML2Name(), - "'."); - - // tell the gatherer to gather for a model parameter - uo.setMode(MOOSEToNEML2::Mode::PARAMETER); - - addGatheredParameter(gatherer_name, uo.NEML2ParameterName()); - _gatherers.push_back(&uo); + addGatheredParameter(gatherer_name, uo.NEML2Name()); + _param_gatherers.push_back(&uo); } // iterate over set of required inputs and error out if we find one that is not provided - std::vector required_inputs = model().input_axis().variable_names(); - for (const auto & input : required_inputs) + for (const auto & [iname, ivar] : model().input_variables()) { - if (_skip_vars.count(input)) - continue; - // skip input state variables because they are "initial guesses" to the nonlinear system - if (input.is_state() || - (_keep_tensors_on_device && (input.is_old_state() || input.is_old_force()))) + // if tensors are kept on device, we are not going to gather old values from moose + if (_manage_state_advance && ivar->history_order() > 0) continue; - if (!_gathered_variable_names.count(input)) - paramError("gatherers", "The required model input `", input, "` is not gathered"); + if (!_gathered_variable_names.count(iname)) + paramError("gatherers", "The required model input `", iname, "` is not gathered"); } - // If a variable is stateful, then it'd better been retrieved by someone! In theory that's not - // sufficient for stateful data management, but that's the best we can do here without being - // overly restrictive. - for (const auto & input : required_inputs) - if (!_keep_tensors_on_device && input.is_old_state() && - !_retrieved_outputs.count(input.current())) - mooseError( - "The NEML2 model requires a stateful input variable `", - input, - "`, but its state counterpart on the output axis has not been retrieved by any object. " - "Therefore, there is no way to properly propagate the corresponding stateful data in " - "time. The common solution to this problem is to add a NEML2ToMOOSE retriever such as " - "those called `NEML2To*MOOSEMaterialProperty`."); - - // check if the model has state/old_state - for (const auto & [vname, var] : model().input_variables()) - { - if (vname.is_state()) - _has_state = true; - if (vname.is_old_state()) - _has_old_state = true; - } + // keep track of stateful variables if manage_state_advance is true + if (_manage_state_advance) + for (const auto & [iname, ivar] : model().input_variables()) + if (ivar->history_order() > 0) + _state_vars[iname] = neml2::Tensor(); } std::size_t @@ -246,8 +196,8 @@ NEML2ModelExecutor::meshChanged() return; _output_ready = false; - if (_keep_tensors_on_device) - mooseError("The mesh changed while `keep_tensors_on_device = true` for NEML2 model executor '", + if (_manage_state_advance) + mooseError("The mesh changed while `manage_state_advance = true` for NEML2 model executor '", name(), "'. This mode requires a fixed mesh because state history is cached on the device."); } @@ -260,8 +210,8 @@ NEML2ModelExecutor::execute() if (_current_execute_flag == EXEC_TIMESTEP_END) { - if (_keep_tensors_on_device && _fe_problem.solverSystemConverged(/*sys_num=*/0)) - advanceDeviceCaches(); + if (_manage_state_advance && _fe_problem.solverSystemConverged(/*sys_num=*/0)) + advanceState(); return; } @@ -273,7 +223,6 @@ NEML2ModelExecutor::execute() if (_t_step > 0) { - applyPredictor(); auto success = solve(); if (success) extractOutputs(); @@ -286,37 +235,14 @@ NEML2ModelExecutor::fillInputs() try { for (const auto & uo : _gatherers) - uo->insertInto(_in, _model_params); - - if (_keep_tensors_on_device && _t_step > 0) - { - for (const auto & [name, val] : _device_state_cache) - if (val.defined() && model().input_axis().has_variable(name.old())) - _in[name.old()] = val; - for (const auto & [name, val] : _device_forces_cache) - if (val.defined() && model().input_axis().has_variable(name.old())) - _in[name.old()] = val; - } - - // Initialize missing inputs that are allowed to be absent - if (_keep_tensors_on_device || !_skip_vars.empty()) - { - const auto options = neml2::default_tensor_options().dtype(neml2::kFloat64).device(device()); - const auto shape = neml2::TensorShape{neml2::Size(_batch_index_generator.getBatchIndex())}; - - for (const auto & [vname, var] : model().input_variables()) - { - const auto it = _in.find(vname); - if (it != _in.end() && it->second.defined()) - continue; - - if (!_skip_vars.count(vname) && !vname.is_state() && - !(_keep_tensors_on_device && (vname.is_old_state() || vname.is_old_force()))) - continue; + uo->insertInto(_in); + for (const auto & uo : _param_gatherers) + uo->insertInto(_model_params); - _in[vname] = var->zeros(options).dynamic_expand({shape}); - } - } + if (_manage_state_advance && _t_step > 0) + for (const auto & [name, val] : _state_vars) + if (val.defined()) + _in[name] = val; // Send input variables and parameters to device for (auto & [var, val] : _in) @@ -341,36 +267,6 @@ NEML2ModelExecutor::fillInputs() } } -void -NEML2ModelExecutor::applyPredictor() -{ - try - { - if (!_has_state || !_has_old_state) - return; - - // Set trial state variables (i.e., initial guesses). - // Right now we hard-code to use the old state as the trial state. - // TODO: implement other predictors - const auto & input_state = model().input_axis().subaxis(neml2::STATE); - const auto & input_old_state = model().input_axis().subaxis(neml2::OLD_STATE); - for (const auto & var : input_state.variable_names()) - if (input_old_state.has_variable(var)) - { - const auto old_name = var.prepend(neml2::OLD_STATE); - const auto it = _in.find(old_name); - if (it != _in.end() && it->second.defined()) - _in[var.prepend(neml2::STATE)] = it->second; - } - } - catch (std::exception & e) - { - mooseError("An error occurred while applying predictor for the NEML2 model. Error message:\n", - e.what(), - NEML2Utils::NEML2_help_message); - } -} - void NEML2ModelExecutor::expandInputs() { @@ -387,20 +283,26 @@ NEML2ModelExecutor::expandInputs() } void -NEML2ModelExecutor::advanceDeviceCaches() +NEML2ModelExecutor::advanceState() { - if (!_keep_tensors_on_device || _t_step == 0) + if (!_manage_state_advance || _t_step == 0) return; - _device_state_cache.clear(); - for (const auto & [name, val] : _out) - if (name.is_state() && val.defined()) - _device_state_cache[name] = val; - - _device_forces_cache.clear(); - for (const auto & [name, val] : _in) - if (name.is_force() && !name.is_old_force() && val.defined()) - _device_forces_cache[name] = val; + for (const auto & [name, val] : _state_vars) + { + auto sep = model().settings().history_separator(); + auto [base_name, order] = neml2::parse_history(name, sep); + mooseAssert(order > 0, "Invalid history order"); + // cache value from the current step + // favor output over input + auto curr_name = order == 1 ? base_name : base_name + sep + std::to_string(order - 1); + if (_out.count(curr_name)) + _state_vars[name] = _out.at(curr_name); + else if (_in.count(curr_name)) + _state_vars[name] = _in.at(curr_name); + else + mooseError("Failed to find cached value for history variable: ", name); + } } bool @@ -424,7 +326,7 @@ NEML2ModelExecutor::solve() } else std::tie(_out, _dout_din) = model().value_and_dvalue(_in); - if (!_keep_tensors_on_device) + if (!_manage_state_advance) _in.clear(); // Restore the default dtype @@ -439,22 +341,22 @@ NEML2ModelExecutor::solve() auto shape_to_string = [](const neml2::TensorShapeRef & shape) -> std::string { std::ostringstream os; - os << "["; + os << "("; for (std::size_t i = 0; i < shape.size(); ++i) { if (i) os << ", "; os << shape[i]; } - os << "]"; + os << ")"; return os.str(); }; std::ostringstream os; - os << "\nNEML2 input debug (input map + expected shapes):\n"; - for (const auto & var : model().input_axis().variable_names()) + os << "\nNEML2 input variables:\n"; + for (const auto & [var, val] : model().input_variables()) { - os << " - " << neml2::utils::stringify(var) << ": "; + os << " - " << var << ": "; const auto it = _in.find(var); if (it == _in.end()) os << "missing\n"; @@ -470,8 +372,7 @@ NEML2ModelExecutor::solve() const auto & base_sizes = v.base_sizes(); expected.insert(expected.end(), base_sizes.begin(), base_sizes.end()); - os << "device=" << neml2::utils::stringify(val.device()) - << " dtype=" << neml2::utils::stringify(val.scalar_type()) + os << "device=" << val.device() << " dtype=" << val.scalar_type() << " sizes=" << shape_to_string(val.sizes()) << " batch=" << shape_to_string(val.batch_sizes().concrete()) << " expected_base=" << shape_to_string(expected); @@ -494,25 +395,21 @@ NEML2ModelExecutor::solve() } } - if (_keep_tensors_on_device && model().input_axis().has_subaxis(neml2::OLD_STATE) && - model().output_axis().has_subaxis(neml2::STATE)) + if (_manage_state_advance) { - os << "NEML2 cached outputs (state for old_state inputs):\n"; - const auto & input_old_state = model().input_axis().subaxis(neml2::OLD_STATE); - for (const auto & var : input_old_state.variable_names()) + os << "NEML2 stateful variables:\n"; + for (const auto & [var, cached_val] : _state_vars) { - const auto state_var = var.prepend(neml2::STATE); - os << " - " << neml2::utils::stringify(state_var) << ": "; - const auto it = _out.find(state_var); - if (it == _out.end()) + os << " - " << var << ": "; + const auto it_out = _out.find(var); + const auto it_in = _in.find(var); + if (it_out == _out.end() || it_in == _in.end()) os << "missing\n"; - else if (!it->second.defined()) - os << "undefined\n"; else { + const auto it = it_out != _out.end() ? it_out : it_in; const auto & val = it->second; - os << "device=" << neml2::utils::stringify(val.device()) - << " dtype=" << neml2::utils::stringify(val.scalar_type()) + os << "device=" << val.device() << " dtype=" << val.scalar_type() << " sizes=" << shape_to_string(val.sizes()) << " batch=" << shape_to_string(val.batch_sizes().concrete()); @@ -563,7 +460,7 @@ NEML2ModelExecutor::extractOutputs() .to(output_device()); // clear output unless we need it for on-device state advance - if (!_keep_tensors_on_device) + if (!_manage_state_advance) _out.clear(); // retrieve derivatives @@ -629,7 +526,7 @@ NEML2ModelExecutor::getOutput(const neml2::VariableName & output_name) const { checkExecutionStage(); - if (!model().output_axis().has_variable(output_name)) + if (!model().output_variables().count(output_name)) mooseError("Trying to retrieve a non-existent NEML2 output variable '", output_name, "'."); return _retrieved_outputs[output_name]; @@ -641,14 +538,14 @@ NEML2ModelExecutor::getOutputDerivative(const neml2::VariableName & output_name, { checkExecutionStage(); - if (!model().output_axis().has_variable(output_name)) + if (!model().output_variables().count(output_name)) mooseError("Trying to retrieve the derivative of NEML2 output variable '", output_name, "' with respect to NEML2 input variable '", input_name, "', but the NEML2 output variable does not exist."); - if (!model().input_axis().has_variable(input_name)) + if (!model().input_variables().count(input_name)) mooseError("Trying to retrieve the derivative of NEML2 output variable '", output_name, "' with respect to NEML2 input variable '", @@ -664,7 +561,7 @@ NEML2ModelExecutor::getOutputParameterDerivative(const neml2::VariableName & out { checkExecutionStage(); - if (!model().output_axis().has_variable(output_name)) + if (!model().output_variables().count(output_name)) mooseError("Trying to retrieve the derivative of NEML2 output variable '", output_name, "' with respect to NEML2 model parameter '", diff --git a/framework/src/neml2/userobjects/NEML2PreKernel.C b/framework/src/neml2/userobjects/NEML2PreKernel.C index a5d3a254dec0..afb41b169965 100644 --- a/framework/src/neml2/userobjects/NEML2PreKernel.C +++ b/framework/src/neml2/userobjects/NEML2PreKernel.C @@ -28,6 +28,8 @@ NEML2PreKernel::validParams() NEML2PreKernel::NEML2PreKernel(const InputParameters & parameters) : NEML2Kernel(parameters), MOOSEToNEML2(parameters) { + if (name() != NEML2Name()) + paramError("to_neml2", "NEML2PreKernel name must match to_neml2."); } #endif diff --git a/framework/src/neml2/utils/NEML2Utils.C b/framework/src/neml2/utils/NEML2Utils.C index b982d644de4f..6a8f61825179 100644 --- a/framework/src/neml2/utils/NEML2Utils.C +++ b/framework/src/neml2/utils/NEML2Utils.C @@ -14,6 +14,26 @@ namespace NEML2Utils { #ifdef NEML2_ENABLED +std::string +stringify(MOOSEIOType type) +{ + switch (type) + { + case NEML2Utils::MOOSEIOType::TIME: + return "TIME"; + case NEML2Utils::MOOSEIOType::SCALAR: + return "SCALAR"; + case NEML2Utils::MOOSEIOType::FUNCTION: + return "FUNCTION"; + case NEML2Utils::MOOSEIOType::VARIABLE: + return "VARIABLE"; + case NEML2Utils::MOOSEIOType::MATERIAL: + return "MATERIAL"; + default: + mooseError("Unknown MOOSE IO type."); + } +} + std::shared_ptr getModel(neml2::Factory & factory, const std::string & name, neml2::Dtype dtype) { @@ -24,32 +44,6 @@ getModel(neml2::Factory & factory, const std::string & name, neml2::Dtype dtype) neml2::set_default_dtype(prev_dtype); return model; } - -void -assertVariable(const neml2::VariableName & v) -{ - if (v.empty()) - mooseError("Empty NEML2 variable"); - - if (!v.is_force() && !v.is_state()) - mooseError("The NEML2 variable '", v, "' is on the wrong subaxis."); -} - -void -assertOldVariable(const neml2::VariableName & v) -{ - if (v.empty()) - mooseError("Empty NEML2 variable"); - - if (!v.is_old_force() && !v.is_old_state()) - mooseError("The NEML2 variable '", v, "' is on the wrong subaxis."); -} - -neml2::VariableName -parseVariableName(const std::string & s) -{ - return neml2::utils::parse(s); -} #endif // NEML2_ENABLED static const std::string missing_neml2 = "The `NEML2` library is required but not enabled. Refer " diff --git a/modules/combined/test/tests/optimization/invOpt_elasticity_modular/elasticity.i b/modules/combined/test/tests/optimization/invOpt_elasticity_modular/elasticity.i index c40702f52d9a..9d6ac9e62269 100644 --- a/modules/combined/test/tests/optimization/invOpt_elasticity_modular/elasticity.i +++ b/modules/combined/test/tests/optimization/invOpt_elasticity_modular/elasticity.i @@ -3,12 +3,14 @@ type = LinearIsotropicElasticity coefficients = '5.0 0.3' coefficient_types = 'YOUNGS_MODULUS POISSONS_RATIO' - strain = 'forces/E' + strain = 'adjoint_strain' + stress = 'adjoint_stress' [] [forward_elasticity_model] type = LinearIsotropicElasticity coefficients = '5.0 0.3' coefficient_types = 'YOUNGS_MODULUS POISSONS_RATIO' - strain = 'forces/E' + strain = 'forward_strain' + stress = 'forward_stress' [] [] diff --git a/modules/combined/test/tests/optimization/invOpt_elasticity_modular/forward.i b/modules/combined/test/tests/optimization/invOpt_elasticity_modular/forward.i index a1e9bd54cd39..76d98e81116e 100644 --- a/modules/combined/test/tests/optimization/invOpt_elasticity_modular/forward.i +++ b/modules/combined/test/tests/optimization/invOpt_elasticity_modular/forward.i @@ -46,22 +46,9 @@ device = 'cpu' [all] model = 'forward_elasticity_model' - - moose_input_types = 'MATERIAL' - moose_inputs = 'neml2_strain' - neml2_inputs = 'forces/E' - - moose_parameter_types = 'MATERIAL' - moose_parameters = 'E_material' - neml2_parameters = 'E' - - moose_output_types = 'MATERIAL' - moose_outputs = 'neml2_stress' - neml2_outputs = 'state/S' - - moose_derivative_types = 'MATERIAL' - moose_derivatives = 'neml2_jacobian' - neml2_derivatives = 'state/S forces/E' + parameter_types = 'MATERIAL' + parameters = 'E' + derivatives = 'forward_stress forward_strain' [] [] @@ -96,17 +83,12 @@ [convert_strain] type = RankTwoTensorToSymmetricRankTwoTensor from = 'mechanical_strain' - to = 'neml2_strain' + to = 'forward_strain' [] [stress] type = ComputeLagrangianObjectiveCustomSymmetricStress - custom_small_stress = 'neml2_stress' - custom_small_jacobian = 'neml2_jacobian' - [] - [E_material] - type = GenericFunctionMaterial - prop_names = 'E_material' - prop_values = 'E' + custom_small_stress = 'forward_stress' + custom_small_jacobian = 'dforward_stress/dforward_strain' [] [] diff --git a/modules/combined/test/tests/optimization/invOpt_elasticity_modular/grad.i b/modules/combined/test/tests/optimization/invOpt_elasticity_modular/grad.i index 2f9b40927c5d..7f4ddc49400f 100644 --- a/modules/combined/test/tests/optimization/invOpt_elasticity_modular/grad.i +++ b/modules/combined/test/tests/optimization/invOpt_elasticity_modular/grad.i @@ -70,41 +70,15 @@ device = 'cpu' [forward] model = 'forward_elasticity_model' - - moose_input_types = 'MATERIAL' - moose_inputs = 'forward_strain' - neml2_inputs = 'forces/E' - - moose_parameter_types = 'MATERIAL' - moose_parameters = 'E_material' - neml2_parameters = 'E' - - moose_output_types = 'MATERIAL' - moose_outputs = 'forward_stress' - neml2_outputs = 'state/S' - - moose_parameter_derivative_types = 'MATERIAL' - moose_parameter_derivatives = 'forward_dstress_dE' - neml2_parameter_derivatives = 'state/S E' + parameter_types = 'MATERIAL' + parameters = 'E' + parameter_derivatives = 'forward_stress E' [] [adjoint] model = 'adjoint_elasticity_model' - - moose_input_types = 'MATERIAL' - moose_inputs = 'adjoint_strain' - neml2_inputs = 'forces/E' - - moose_parameter_types = 'MATERIAL' - moose_parameters = 'E_material' - neml2_parameters = 'E' - - moose_output_types = 'MATERIAL' - moose_outputs = 'adjoint_stress' - neml2_outputs = 'state/S' - - moose_derivative_types = 'MATERIAL' - moose_derivatives = 'adjoint_jacobian' - neml2_derivatives = 'state/S forces/E' + parameter_types = 'MATERIAL' + parameters = 'E' + derivatives = 'adjoint_stress adjoint_strain' [] [] @@ -124,12 +98,6 @@ [] [Materials] - [E_material] - type = GenericFunctionMaterial - prop_names = 'E_material' - prop_values = 'E' - [] - # forward [forward_strain] type = ComputeLagrangianStrain @@ -151,7 +119,7 @@ [adjoint_stress] type = ComputeLagrangianObjectiveCustomSymmetricStress custom_small_stress = 'adjoint_stress' - custom_small_jacobian = 'adjoint_jacobian' + custom_small_jacobian = 'dadjoint_stress/dadjoint_strain' base_name = 'adjoint' [] [] @@ -183,7 +151,7 @@ [VectorPostprocessors] [grad_youngs_modulus] type = AdjointStrainSymmetricStressGradInnerProduct - stress_derivative_name = 'forward_dstress_dE' + stress_derivative_name = 'dforward_stress/dE' adjoint_strain_name = 'adjoint_mechanical_strain' variable = dummy function = E diff --git a/modules/doc/content/getting_started/installation/install_libtorch.md b/modules/doc/content/getting_started/installation/install_libtorch.md index 0a793dd2463d..c78dcbd86f2c 100644 --- a/modules/doc/content/getting_started/installation/install_libtorch.md +++ b/modules/doc/content/getting_started/installation/install_libtorch.md @@ -1,210 +1,54 @@ -# Libtorch (Pytorch C++ API) +# Libtorch (PyTorch C++ API) -The way one enables LibTorch [!cite](paszke2019pytorch) capabilities in MOOSE depends on -the operating system (Linux or Mac) and if we use HPC or just a local workstation. +MOOSE can be linked against [libtorch](https://pytorch.org/cppdocs/) [!cite](paszke2019pytorch) to enable hardware acceleration. The libtorch source is provided as a git submodule under `framework/contrib/pytorch`, and a setup script is provided to build and install it with the configuration MOOSE expects. -!alert! note title=Compatibility +## Prerequisites -Before trying to install MOOSE with libtorch make sure to check out the -[compatibility matrix](https://github.com/pytorch/pytorch/blob/main/RELEASE.md#release-compatibility-matrix) -which will tell you if the required packages are compatible with the ones required by MOOSE. -Furthermore, we do not support `libtorch` versions below v1.4. +The libtorch build depends on [PETSc](https://petsc.org) so that BLAS and LAPACK are consistent between the two libraries. PETSc must therefore be installed before libtorch. The script looks for PETSc at `${PETSC_DIR}` (defined if you are using conda, and otherwise defaults to `/petsc/arch-moose`) and aborts if it cannot be found. -!alert-end! - -## Mac workstations - -For Mac workstations, the user has two distinct paths for enabling libtorch within MOOSE. -Both paths rely on conda for installing the moose environment, therefore we recommend the -users follow [Conda MOOSE Environment](installation/conda.md) instructions before starting -this process. - -!alert! note title=GPU Support on Macs - -For ARM Mac workstations, both installation procedures will give access -to the Metal Performance Shader (MPS) capabilities (GPU acceleration). - -!alert-end! - -### Using packages distributed through conda - -1. Create and activate a new MOOSE environment with pytorch included: - - ```bash - conda create -n moose-torch moose-dev pytorch=2.1 -c pytorch - conda activate moose-torch - ``` - - This will provide the headers and libraries needed to use libtorch. - -2. Configure MOOSE to use libtorch. The user needs to link to the conda-based libtorch libraries - using the following command within the root directory of `moose`: - - ```bash - ./configure --with-libtorch=${CONDA_PREFIX}/lib/python3.11/site-packages/torch - ``` - - !alert! note title=How to get the pytorch directory - - The python version can be different depending on the distribution, so make sure you double-check if the directory you point to actually exists! - An easy way to find if the library exists within the conda package is running the following command in the terminal: - - ```bash - find ${CONDA_PREFIX} -type d -name torch - ``` - - Alternatively, you can use python to get the same directory: - - ```bash - python -c "import torch; print(torch.__path__[0])" - ``` - - !alert-end! - -3. Once moose has been configured to work with libtorch, we need to recompile MOOSE. - For testing purposes, we can do the following: - - ```bash - cd test - make -j 8 - ./run_tests --re=libtorch - ``` - - If you see tests passing with green colors, the installation was successful. - -### Using pre-compiled packages from the official website - -1. Create and activate a MOOSE environment without pytorch: - - ```bash - conda create -n moose moose-dev - conda activate moose - ``` - -2. Pull the precompiled libraries using the setup script provided in MOOSE. From the root - directory of `moose` this is done by executing the following command: - - ``` - ./scripts/setup_libtorch.sh --version=2.1 - ``` - - !alert! note title=Version limitations for ARM Workstations - - The official distribution system does not include packages for ARM architectures up until version 2.2. If the user want to use this path on ARM machines, the version parameter to the script needs - to be altered. - - !alert-end! +A working compiler stack and CMake are also required. The [MOOSE conda environment](installation/conda.md) satisfies both. -3. Configure MOOSE to use libtorch within the root directory of `moose`: +## Installation - ```bash - ./configure --with-libtorch - ``` - - In this case, the path is not added explicitly considering that the libtorch packages will be - pulled to the default location. - -4. Once moose has been configured to work with libtorch, we need to recompile MOOSE. - For testing purposes, we can do the following: - - ```bash - cd test - make -j 8 - ./run_tests --re=libtorch - ``` - - If you see tests passing with green colors, the installation was successful. - -## Linux Workstations - -For linux, due to the official conda distribution of pytorch is using pre-CXX11 ABI, while the -conda compiler stack of MOOSE relies on this ABI, we don't support conda-based installations yet. - -!alert! note title=Main limitation on Linux machines - -It is important to emphasize that -linking MOOSE with libtorch on +Linux machines+ is not supported if the compiler stack has been built -using a `libc` version below 2.29 (for `libtorch v 2.1+`) or 2.27 (for `libtorch v 1.8-2.1`) -or 2.23 (for `libtorch v1.4-1.8`). To check your currently used libc version on +Linux machine+, use the following command: +To build and install libtorch, run ```bash -ldd --version +cd ~/projects/moose +./scripts/update_and_rebuild_libtorch.sh ``` -This can be a problem when using the moose conda environment with new versions of libtorch. - -!alert-end! - -### Using pre-compiled packages from the official website - -1. Create and activate a MOOSE environment without pytorch: - - ```bash - conda create -n moose moose-dev - conda activate moose - ``` - -2. Pull the precompiled libraries using the setup script provided in MOOSE. From the root - directory of `moose` this is done by executing the following command: - - ``` - ./scripts/setup_libtorch.sh --version=2.1 - ``` +!alert tip +The setup script uses sensible defaults that work out-of-the-box. The script is also extensively customizable. Use the `--help` argument to print out a detailed help message. -3. Configure MOOSE to use libtorch within the root directory of `moose`: +The most commonly used options and environment variables are: - ```bash - ./configure --with-libtorch - ``` +- `--fast` — skip the update, clean, and configure steps (re-build only). +- `--skip-submodule-update` — skip the submodule update step. +- `LIBTORCH_DIR` — installation directory. Defaults to `/framework/contrib/pytorch/installed`. +- `LIBTORCH_SRC_DIR` — use a custom libtorch source tree instead of the bundled submodule. Setting this implies `--skip-submodule-update`. +- `LIBTORCH_JOBS` — number of parallel build jobs. Defaults to `MOOSE_JOBS`, or 1 if unset. +- `PETSC_DIR` — path to the PETSc installation. -4. Once moose has been configured to work with libtorch, we need to recompile MOOSE. - For testing purposes, we can do the following: - - ```bash - cd test - make -j 8 - ./run_tests --re=libtorch - ``` - - If you see tests passing with green colors, the installation was successful. - -### Manually installing packages - -When encountering GLIBC-related compatibility issues on Linux machines the user has two options: - -1. [Rebuilding Petsc and libMesh manually](gcc_install_moose.md) using compatible compilers (most newer systems - like Ubuntu come with compatible compilers). - -2. Building libtorch from source. The user can find instructions on how to install libtorch - from source on the [official website](https://github.com/pytorch/pytorch/blob/master/docs/libtorch.rst). - - -!alert! note title=GPU Support on Linux Workstations +!alert! note title=GPU support +CUDA is enabled automatically when a CUDA toolkit is detected on the system. For Intel GPU (XPU) support, export `USE_XPU=1` before invoking the script. General CMake environment variables are also respected, so other backends can be toggled by passing additional `-D...` arguments through to the configure step. +!alert-end! -For linux workstations, we recommend [manually building the dependencies of MOOSE](gcc_install_moose.md) -using suitable system compilers. At the time these instruction are written, only `cuda`-based -acceleration is tested. -The following packages need to be also installed to enable this feature: +Building libtorch is resource-intensive: expect a multi-gigabyte build directory and a long compile time on the first build. Subsequent rebuilds can be sped up with `--fast`. -- [A sutiable Nvidia driver](https://www.nvidia.com/en-us/drivers/) -- [Cuda toolkit](https://developer.nvidia.com/cuda-toolkit) - only strictly required if - building libtorch from source. +## Configuring MOOSE with libtorch -The supported versions can be determined using the [compatibility matrix](https://github.com/pytorch/pytorch/blob/main/RELEASE.md#release-compatibility-matrix). -Once the dependencies of MOOSE are installed, we can use the setup script to fetch -the correct libtorch package from the official ditribution: +Once libtorch has been installed, configure MOOSE with -``` -./scripts/setup_libtorch.sh --version=2.1 --libtorch-distribution=cuda +```bash +./configure --with-libtorch ``` -The configuration and build parts of the process are the same as discussed before. +If libtorch was installed to a non-default location, pass that path explicitly: -!alert-end! +```bash +./configure --with-libtorch=/path/to/libtorch +``` ## HPC systems -On non-INL HPC systems, one can follow the manual installation process discussed above. -On INL machines, containers are provided with readily compiled dependencies, including libtorch. -For more information on containers, see the [instuctions](inl_hpc_install_moose.md). -In this case, the `moose-dev` module already contains `libtorch`. +On INL HPC systems, libtorch is already provided through the `moose-dev` module/container and does not need to be built manually. See the [INL HPC installation instructions](inl_hpc_install_moose.md) for more information. On other HPC systems, follow the same procedure as for a workstation, taking care to load a compatible compiler stack and CMake before invoking the script. diff --git a/modules/solid_mechanics/include/materials/lagrangian/ComputeLagrangianStrainBase.h b/modules/solid_mechanics/include/materials/lagrangian/ComputeLagrangianStrainBase.h index 87d2d506c6a3..484c348099a5 100644 --- a/modules/solid_mechanics/include/materials/lagrangian/ComputeLagrangianStrainBase.h +++ b/modules/solid_mechanics/include/materials/lagrangian/ComputeLagrangianStrainBase.h @@ -88,8 +88,8 @@ class ComputeLagrangianStrainBase : public Material, public G /// Strain increment MaterialProperty & _strain_increment; - /// Spatial velocity gradient increment - MaterialProperty & _spatial_velocity_increment; + /// Deformation gradient increment + MaterialProperty & _deformation_gradient_increment; /// Vorticity increment MaterialProperty & _vorticity_increment; diff --git a/modules/solid_mechanics/include/neml2/R2IncrementToRate.h b/modules/solid_mechanics/include/neml2/R2IncrementToRate.h new file mode 100644 index 000000000000..022f06d6f145 --- /dev/null +++ b/modules/solid_mechanics/include/neml2/R2IncrementToRate.h @@ -0,0 +1,43 @@ +//* This file is part of the MOOSE framework +//* https://mooseframework.inl.gov +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#pragma once + +#ifdef NEML2_ENABLED + +#include "neml2/models/Model.h" + +namespace neml2 +{ +class R2; + +/// Get the rate of a rank two tensor given its increment +class R2IncrementToRate : public Model +{ +public: + static OptionSet expected_options(); + + R2IncrementToRate(const OptionSet & options); + +protected: + void set_value(bool out, bool dout_din, bool d2out_din2) override; + + /// Increment of the rank two tensor + const Variable & _delta; + + /// Time + const Variable & _t; + const Variable & _t_n; + + /// Rate + Variable & _rate; +}; +} // namespace neml2 + +#endif // NEML2_ENABLED diff --git a/modules/solid_mechanics/src/materials/lagrangian/ComputeLagrangianStrainBase.C b/modules/solid_mechanics/src/materials/lagrangian/ComputeLagrangianStrainBase.C index e26309d410d2..4ead1cfca9ac 100644 --- a/modules/solid_mechanics/src/materials/lagrangian/ComputeLagrangianStrainBase.C +++ b/modules/solid_mechanics/src/materials/lagrangian/ComputeLagrangianStrainBase.C @@ -51,8 +51,8 @@ ComputeLagrangianStrainBase::ComputeLagrangianStrainBase(const InputParameter _mechanical_strain(declareProperty(_base_name + "mechanical_strain")), _mechanical_strain_old(getMaterialPropertyOld(_base_name + "mechanical_strain")), _strain_increment(declareProperty(_base_name + "strain_increment")), - _spatial_velocity_increment( - declareProperty(_base_name + "spatial_velocity_increment")), + _deformation_gradient_increment( + declareProperty(_base_name + "spatial_deformation_gradient_increment")), _vorticity_increment(declareProperty(_base_name + "vorticity_increment")), _F_ust(declareProperty(_base_name + "unstabilized_deformation_gradient")), _F_avg(declareProperty(_base_name + "average_deformation_gradient")), @@ -151,7 +151,7 @@ ComputeLagrangianStrainBase::computeQpIncrementalStrains(const RankTwoTensor _mechanical_strain[_qp] = _mechanical_strain_old[_qp] + _strain_increment[_qp]; // Yes, this does make sense to do it here - _spatial_velocity_increment[_qp] = _vorticity_increment[_qp] + _strain_increment[_qp]; + _deformation_gradient_increment[_qp] = _vorticity_increment[_qp] + _strain_increment[_qp]; // Faked rotation increment for ComputeStressBase materials _rotation_increment[_qp] = RankTwoTensor::Identity(); diff --git a/modules/solid_mechanics/src/neml2/LAROMANCE6DInterpolation.C b/modules/solid_mechanics/src/neml2/LAROMANCE6DInterpolation.C index 53bc041d9131..3b2ceee8bd09 100644 --- a/modules/solid_mechanics/src/neml2/LAROMANCE6DInterpolation.C +++ b/modules/solid_mechanics/src/neml2/LAROMANCE6DInterpolation.C @@ -33,23 +33,27 @@ LAROMANCE6DInterpolation::expected_options() options.doc() = "Multilinear interpolation over six dimensions (von_mises_stress, temperature, " "equivalent_plastic_strain, cell_dislocation_density, wall_dislocation_density, env_factor)"; - // Model inputs - options.set("equivalent_plastic_strain"); - options.set("von_mises_stress"); - options.set("cell_dislocation_density"); - options.set("wall_dislocation_density"); + // Model inputs + options.add_input("equivalent_plastic_strain", "The equivalent plastic strain"); + options.add_input("von_mises_stress", "The von Mises stress"); + options.add_input("cell_dislocation_density", "The cell dislocation density"); + options.add_input("wall_dislocation_density", "The wall dislocation density"); + options.add_input("temperature", "The temperature"); + options.add_input("env_factor", "The environment factor"); - options.set("temperature"); - options.set("env_factor"); // Model Outputs - options.set_output("output_rate"); + options.add_output("output_rate", "The output rate"); + // JSON - options.set("model_file_name"); - options.set("model_file_variable_name"); + options.add("model_file_name", "The name of the model file"); + options.add("model_file_variable_name", + "The name of the variable in the model file"); + // jit does not currently work with this - options.set("jit") = false; - options.set("jit").suppressed() = true; + options.set("jit", false); + options.suppress("jit"); + return options; } diff --git a/modules/solid_mechanics/src/neml2/NEML2StressDivergence.C b/modules/solid_mechanics/src/neml2/NEML2StressDivergence.C index 62f0c439eba8..5b7820744ee9 100644 --- a/modules/solid_mechanics/src/neml2/NEML2StressDivergence.C +++ b/modules/solid_mechanics/src/neml2/NEML2StressDivergence.C @@ -39,8 +39,7 @@ NEML2StressDivergence::NEML2StressDivergence(const InputParameters & parameters) : NEML2PostKernel(parameters), _residual(dynamic_cast *>(&_sys.system().add_vector( getParam("residual"), false, libMesh::ParallelType::GHOSTED))), - _stress( - _constitutive.getOutput(NEML2Utils::parseVariableName(getParam("stress")))), + _stress(_constitutive.getOutput(getParam("stress"))), _disp_vars(getParam>("displacements")), _ndisp(_disp_vars.size()) { diff --git a/modules/solid_mechanics/src/neml2/R2IncrementToRate.C b/modules/solid_mechanics/src/neml2/R2IncrementToRate.C new file mode 100644 index 000000000000..b822dbf74ceb --- /dev/null +++ b/modules/solid_mechanics/src/neml2/R2IncrementToRate.C @@ -0,0 +1,56 @@ +//* This file is part of the MOOSE framework +//* https://mooseframework.inl.gov +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#include "R2IncrementToRate.h" + +#ifdef NEML2_ENABLED + +#include "neml2/tensors/R2.h" +#include "neml2/tensors/functions/imap.h" + +namespace neml2 +{ +register_NEML2_object(R2IncrementToRate); + +OptionSet +R2IncrementToRate::expected_options() +{ + OptionSet options = Model::expected_options(); + options.doc() = "Compute the rate of a rank two tensor given its increment and the time step."; + options.add_input("increment", "Increment of the rank two tensor"); + options.add_input("time", "t", "Current time"); + options.add_output("rate", "Rate of the rank two tensor"); + return options; +} + +R2IncrementToRate::R2IncrementToRate(const OptionSet & options) + : Model(options), + _delta(declare_input_variable("increment")), + _t(declare_input_variable("t")), + _t_n(declare_input_variable(history_name(_t.name(), 1))), + _rate(declare_output_variable("rate")) +{ +} + +void +R2IncrementToRate::set_value(bool out, bool dout_din, bool /*d2out_din2*/) +{ + if (out) + _rate = _delta / (_t - _t_n); + + if (dout_din) + { + _rate.d(_delta) = 1.0 / (_t - _t_n) * imap_v(); + _rate.d(_t) = -_delta / (_t - _t_n) / (_t - _t_n); + _rate.d(_t_n) = _delta / (_t - _t_n) / (_t - _t_n); + } +} +} // namespace neml2 + +#endif // NEML2_ENABLED diff --git a/modules/solid_mechanics/test/tests/neml2/crystal_plasticity/approx_kinematics.i b/modules/solid_mechanics/test/tests/neml2/crystal_plasticity/approx_kinematics.i index 2f1e1d6929fc..528bfc2e447e 100644 --- a/modules/solid_mechanics/test/tests/neml2/crystal_plasticity/approx_kinematics.i +++ b/modules/solid_mechanics/test/tests/neml2/crystal_plasticity/approx_kinematics.i @@ -34,37 +34,17 @@ N = 2 model = 'model' verbose = true device = 'cpu' - - moose_input_types = 'MATERIAL POSTPROCESSOR POSTPROCESSOR MATERIAL MATERIAL MATERIAL' - moose_inputs = ' spatial_velocity_increment time time elastic_strain orientation slip_hardening' - neml2_inputs = ' forces/spatial_velocity_increment forces/t old_forces/t old_state/elastic_strain old_state/orientation old_state/internal/slip_hardening' - - moose_output_types = 'MATERIAL MATERIAL MATERIAL MATERIAL' - moose_outputs = ' neml2_cauchy_stress elastic_strain orientation slip_hardening' - neml2_outputs = ' state/internal/full_cauchy_stress state/elastic_strain state/orientation state/internal/slip_hardening' - - moose_derivative_types = 'MATERIAL' - moose_derivatives = ' neml2_cauchy_jacobian' - neml2_derivatives = ' state/internal/full_cauchy_stress forces/spatial_velocity_increment' - - initialize_outputs = ' orientation' + derivatives = 'neml2_stress spatial_deformation_gradient_increment' + initialize_outputs = 'orientation' initialize_output_values = 'initial_orientation' [] [] -[Postprocessors] - [time] - type = TimePostprocessor - execute_on = 'INITIAL TIMESTEP_BEGIN' - outputs = 'none' - [] -[] - [Materials] [copy] type = ComputeLagrangianCauchyCustomStress - custom_cauchy_stress = 'neml2_cauchy_stress' - custom_cauchy_jacobian = 'neml2_cauchy_jacobian' + custom_cauchy_stress = 'neml2_stress' + custom_cauchy_jacobian = 'dneml2_stress/dspatial_deformation_gradient_increment' large_kinematics = true [] [initial_orientation] diff --git a/modules/solid_mechanics/test/tests/neml2/crystal_plasticity/approx_kinematics_neml2.i b/modules/solid_mechanics/test/tests/neml2/crystal_plasticity/approx_kinematics_neml2.i index 865ba2fbe5d2..a0adc0dd4b8b 100644 --- a/modules/solid_mechanics/test/tests/neml2/crystal_plasticity/approx_kinematics_neml2.i +++ b/modules/solid_mechanics/test/tests/neml2/crystal_plasticity/approx_kinematics_neml2.i @@ -25,31 +25,29 @@ [Models] [spatial_velocity_gradient] type = R2IncrementToRate - variable = 'forces/spatial_velocity_increment' - time = 'forces/t' - rate = 'forces/spatial_velocity_gradient' + increment = 'spatial_deformation_gradient_increment' + rate = 'spatial_velocity_gradient' [] [split_to_deformation_rate] - type = R2toSR2 - input = 'forces/spatial_velocity_gradient' - output = 'forces/deformation_rate' + type = R2ToSR2 + input = 'spatial_velocity_gradient' + output = 'deformation_rate' [] [split_to_vorticity] - type = R2toWR2 - input = 'forces/spatial_velocity_gradient' - output = 'forces/vorticity' + type = R2ToWR2 + input = 'spatial_velocity_gradient' + output = 'vorticity' [] [euler_rodrigues] type = RotationMatrix - from = 'state/orientation' - to = 'state/orientation_matrix' + from = 'orientation' + to = 'orientation_matrix' [] [elasticity] type = LinearIsotropicElasticity coefficient_types = 'YOUNGS_MODULUS POISSONS_RATIO' coefficients = '1e5 0.25' - strain = 'state/elastic_strain' - stress = 'state/internal/cauchy_stress' + strain = 'elastic_strain' [] [resolved_shear] type = ResolvedShear @@ -85,15 +83,15 @@ [] [integrate_slip_hardening] type = ScalarBackwardEulerTimeIntegration - variable = 'state/internal/slip_hardening' + variable = 'slip_hardening' [] [integrate_elastic_strain] type = SR2BackwardEulerTimeIntegration - variable = 'state/elastic_strain' + variable = 'elastic_strain' [] [integrate_orientation] type = WR2ImplicitExponentialTimeIntegration - variable = 'state/orientation' + variable = 'orientation' [] [implicit_rate] type = ComposedModel @@ -108,6 +106,7 @@ [eq_sys] type = NonlinearSystem model = 'implicit_rate' + unknowns = 'elastic_strain slip_hardening orientation' [] [] @@ -123,19 +122,26 @@ [] [Models] + [predictor] + type = ConstantExtrapolationPredictor + unknowns_SR2 = 'elastic_strain' + unknowns_Rot = 'orientation' + unknowns_Scalar = 'slip_hardening' + [] [model_without_stress] type = ImplicitUpdate equation_system = 'eq_sys' solver = 'newton' + predictor = 'predictor' [] [full_stress] - type = SR2toR2 - input = 'state/internal/cauchy_stress' - output = 'state/internal/full_cauchy_stress' + type = SR2ToR2 + input = 'stress' + output = 'neml2_stress' [] [model] type = ComposedModel models = 'model_without_stress elasticity full_stress' - additional_outputs = 'state/elastic_strain' + additional_outputs = 'elastic_strain' [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/crystal_plasticity/exact_kinematics.i b/modules/solid_mechanics/test/tests/neml2/crystal_plasticity/exact_kinematics.i index dfac72ff522f..40133297962b 100644 --- a/modules/solid_mechanics/test/tests/neml2/crystal_plasticity/exact_kinematics.i +++ b/modules/solid_mechanics/test/tests/neml2/crystal_plasticity/exact_kinematics.i @@ -34,42 +34,22 @@ N = 2 model = 'model' verbose = true device = 'cpu' - - moose_input_types = 'MATERIAL MATERIAL POSTPROCESSOR POSTPROCESSOR MATERIAL MATERIAL' - moose_inputs = ' deformation_gradient initial_orientation time time plastic_defgrad crss' - neml2_inputs = ' forces/F forces/r forces/t old_forces/t old_state/Fp old_state/tauc' - - moose_output_types = 'MATERIAL MATERIAL MATERIAL' - moose_outputs = ' neml2_pk2_stress plastic_defgrad crss' - neml2_outputs = ' state/full_S state/Fp state/tauc' - - moose_derivative_types = 'MATERIAL' - moose_derivatives = ' neml2_pk2_jacobian' - neml2_derivatives = ' state/full_S forces/F' - - initialize_outputs = ' plastic_defgrad' + derivatives = 'neml2_stress deformation_gradient' + initialize_outputs = 'plastic_deformation_gradient' initialize_output_values = 'initial_plastic_defgrad' [] [] -[Postprocessors] - [time] - type = TimePostprocessor - execute_on = 'INITIAL TIMESTEP_BEGIN' - outputs = 'none' - [] -[] - [Materials] [copy] type = ComputeLagrangianStressCustomPK2 - custom_pk2_stress = 'neml2_pk2_stress' - custom_pk2_jacobian = 'neml2_pk2_jacobian' + custom_pk2_stress = 'neml2_stress' + custom_pk2_jacobian = 'dneml2_stress/ddeformation_gradient' large_kinematics = true [] [initial_orientation] type = GenericConstantRealVectorValue - vector_name = 'initial_orientation' + vector_name = 'orientation' vector_values = '-0.54412095 -0.34931944 0.12600655' [] [initial_plastic_defgrad] diff --git a/modules/solid_mechanics/test/tests/neml2/crystal_plasticity/exact_kinematics_neml2.i b/modules/solid_mechanics/test/tests/neml2/crystal_plasticity/exact_kinematics_neml2.i index 4220818eb210..d8132e91d8b2 100644 --- a/modules/solid_mechanics/test/tests/neml2/crystal_plasticity/exact_kinematics_neml2.i +++ b/modules/solid_mechanics/test/tests/neml2/crystal_plasticity/exact_kinematics_neml2.i @@ -26,43 +26,37 @@ # Orientation remains constant as we work with the reference configuration [euler_rodrigues] type = RotationMatrix - from = 'forces/r' - to = 'forces/R' + from = 'orientation' + to = 'orientation_matrix' [] # Hardening (this is just a very simple hardening model) [slip_strength] type = SingleSlipStrengthMap constant_strength = 50.0 - slip_hardening = 'state/tauc' - slip_strengths = 'state/tauc_i' [] [voce_hardening] type = VoceSingleSlipHardeningRule initial_slope = 500.0 saturated_hardening = 50.0 - slip_hardening_rate = 'state/tauc_rate' - slip_hardening = 'state/tauc' - sum_slip_rates = 'state/gamma_rate' [] # Elasticity: St. Venant-Kirchhoff with Green-Lagrange strain [mult_decomp] type = R2Multiplication - A = 'forces/F' - B = 'state/Fp' - to = 'state/Fe' + A = 'deformation_gradient' + B = 'plastic_deformation_gradient' + to = 'elastic_deformation_gradient' invert_B = true [] [gl_strain] type = GreenLagrangeStrain - deformation_gradient = 'state/Fe' - strain = 'state/E' + deformation_gradient = 'elastic_deformation_gradient' + strain = 'elastic_strain' [] [svk] type = LinearIsotropicElasticity coefficients = '1e5 0.25' coefficient_types = 'YOUNGS_MODULUS POISSONS_RATIO' - strain = 'state/E' - stress = 'state/S' + strain = 'elastic_strain' [] [elasticity] type = ComposedModel @@ -71,43 +65,32 @@ # CP flow rule [resolved_shear] type = ResolvedShear - resolved_shears = 'state/tau_i' - stress = 'state/S' - orientation = 'forces/R' [] [slip_rule] type = PowerLawSlipRule n = 2.0 gamma0 = 2.0e-1 - slip_rates = 'state/gamma_rate_i' - resolved_shears = 'state/tau_i' - slip_strengths = 'state/tauc_i' [] [sum_slip_rates] type = SumSlipRates - slip_rates = 'state/gamma_rate_i' - sum_slip_rates = 'state/gamma_rate' [] [plastic_velgrad] type = PlasticSpatialVelocityGradient - plastic_spatial_velocity_gradient = 'state/Lp' - slip_rates = 'state/gamma_rate_i' - orientation = 'forces/R' [] [plastic_defgrad_rate] type = R2Multiplication - A = 'state/Lp' - B = 'state/Fp' - to = 'state/Fp_rate' + A = 'plastic_spatial_velocity_gradient' + B = 'plastic_deformation_gradient' + to = 'plastic_deformation_gradient_rate' [] # Definition of residuals [integrate_slip_hardening] type = ScalarBackwardEulerTimeIntegration - variable = 'state/tauc' + variable = 'slip_hardening' [] [integrate_plastic_defgrad] type = R2BackwardEulerTimeIntegration - variable = 'state/Fp' + variable = 'plastic_deformation_gradient' [] # The implicit model that we solve for [implicit_rate] @@ -123,6 +106,7 @@ [eq_sys] type = NonlinearSystem model = 'implicit_rate' + unknowns = 'slip_hardening plastic_deformation_gradient' [] [] @@ -138,20 +122,26 @@ [] [Models] + [predictor] + type = ConstantExtrapolationPredictor + unknowns_R2 = 'plastic_deformation_gradient' + unknowns_Scalar = 'slip_hardening' + [] [model_without_stress] type = ImplicitUpdate equation_system = 'eq_sys' solver = 'newton' + predictor = 'predictor' [] # Convert PK2 stress to a full second order tensor [full_stress] - type = SR2toR2 - input = 'state/S' - output = 'state/full_S' + type = SR2ToR2 + input = 'stress' + output = 'neml2_stress' [] [model] type = ComposedModel models = 'model_without_stress elasticity full_stress' - additional_outputs = 'state/Fp' + additional_outputs = 'plastic_deformation_gradient' [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/elasticity/elasticity.i b/modules/solid_mechanics/test/tests/neml2/elasticity/elasticity.i index 00f112e9622a..973afa1923b6 100644 --- a/modules/solid_mechanics/test/tests/neml2/elasticity/elasticity.i +++ b/modules/solid_mechanics/test/tests/neml2/elasticity/elasticity.i @@ -34,18 +34,7 @@ N = 2 model = 'model' verbose = true device = 'cpu' - - moose_input_types = 'MATERIAL' - moose_inputs = 'neml2_strain' - neml2_inputs = 'forces/E' - - moose_output_types = 'MATERIAL' - moose_outputs = 'neml2_stress' - neml2_outputs = 'state/S' - - moose_derivative_types = 'MATERIAL' - moose_derivatives = 'neml2_jacobian' - neml2_derivatives = 'state/S forces/E' + derivatives = 'neml2_stress neml2_strain' [] [] @@ -58,7 +47,7 @@ N = 2 [stress] type = ComputeLagrangianObjectiveCustomSymmetricStress custom_small_stress = 'neml2_stress' - custom_small_jacobian = 'neml2_jacobian' + custom_small_jacobian = 'dneml2_stress/dneml2_strain' [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/elasticity/elasticity_neml2.i b/modules/solid_mechanics/test/tests/neml2/elasticity/elasticity_neml2.i index f5e9f15b7013..6391e711f098 100644 --- a/modules/solid_mechanics/test/tests/neml2/elasticity/elasticity_neml2.i +++ b/modules/solid_mechanics/test/tests/neml2/elasticity/elasticity_neml2.i @@ -3,6 +3,7 @@ type = LinearIsotropicElasticity coefficients = '1 0.3' coefficient_types = 'YOUNGS_MODULUS POISSONS_RATIO' - strain = 'forces/E' + strain = 'neml2_strain' + stress = 'neml2_stress' [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/explicit_dynamics/neml2.i b/modules/solid_mechanics/test/tests/neml2/explicit_dynamics/neml2.i index 9a09f6a3a3bd..591ae1d397b2 100644 --- a/modules/solid_mechanics/test/tests/neml2/explicit_dynamics/neml2.i +++ b/modules/solid_mechanics/test/tests/neml2/explicit_dynamics/neml2.i @@ -6,7 +6,8 @@ executor_name = 'neml2' model = 'model' verbose = true - moose_input_kernels = 'strain' + input_kernels = 'neml2_strain' + auto_output = false [] [] @@ -18,18 +19,18 @@ type = NEML2FEInterpolation assembly = 'assembly' [] - [strain] + [neml2_strain] type = NEML2SmallStrain assembly = 'assembly' fe = 'fe' - to_neml2 = 'forces/E' + to_neml2 = 'neml2_strain' [] [residual] type = NEML2StressDivergence assembly = 'assembly' fe = 'fe' executor = 'neml2' - stress = 'state/S' + stress = 'neml2_stress' residual = 'NONTIME' [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/explicit_dynamics/neml2_adaptivity.i b/modules/solid_mechanics/test/tests/neml2/explicit_dynamics/neml2_adaptivity.i index 87b735e89293..283b9ad190a1 100644 --- a/modules/solid_mechanics/test/tests/neml2/explicit_dynamics/neml2_adaptivity.i +++ b/modules/solid_mechanics/test/tests/neml2/explicit_dynamics/neml2_adaptivity.i @@ -6,7 +6,8 @@ executor_name = 'neml2' model = 'model' verbose = true - moose_input_kernels = 'strain' + input_kernels = 'neml2_strain' + auto_output = false [] [] @@ -18,18 +19,18 @@ type = NEML2FEInterpolation assembly = 'assembly' [] - [strain] + [neml2_strain] type = NEML2SmallStrain assembly = 'assembly' fe = 'fe' - to_neml2 = 'forces/E' + to_neml2 = 'neml2_strain' [] [residual] type = NEML2StressDivergence assembly = 'assembly' fe = 'fe' executor = 'neml2' - stress = 'state/S' + stress = 'neml2_stress' residual = 'NONTIME' [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/laromance/gold/laromance_return_mapping_out.csv b/modules/solid_mechanics/test/tests/neml2/laromance/gold/laromance_return_mapping_out.csv index f570da8516be..ff09a968956e 100644 --- a/modules/solid_mechanics/test/tests/neml2/laromance/gold/laromance_return_mapping_out.csv +++ b/modules/solid_mechanics/test/tests/neml2/laromance/gold/laromance_return_mapping_out.csv @@ -1,12 +1,12 @@ -time,eff_inelastic_strain,eff_inelastic_strain_rate,rhoi_dd,rhoi_rate,rhom_dd,rhom_rate,vm_stress -0,0,0,0,0,0,0,0 -50,4.5382799070052e-05,9.0765529237887e-07,8084990278496.3,1699805569.9255,157612228433.57,1152244568.6714,1.8250120749944e-08 -100,9.080227972258e-05,9.0839152589507e-07,8169444445112,1689083332.3153,215141021273.68,1150575856.8021,1.8250120749944e-08 -150,0.00013656290531911,9.152069649021e-07,8249078284307.3,1592676783.9051,277533498042.67,1247849535.3798,8.9602849375927 -200,0.00018285982388521,9.2596539240892e-07,8318056771221.3,1379569738.281,344844345441.22,1346216947.9711,201.16915782104 -250,0.00022978120017675,9.3848614047889e-07,8391385663879.3,1466577853.1594,413111994517.42,1365352981.5239,191.96534939462 -300,0.00027731550819005,9.5076338339971e-07,8469303577692.3,1558358276.2596,482613762662.35,1390035362.8986,182.64131205355 -350,0.00032545219120436,9.6282232196636e-07,8552084365489.7,1655615755.9472,553654836344.77,1420821473.6485,173.1991165392 -400,0.00037418043699035,9.7466047426176e-07,8640035006435.4,1759012818.9156,626576929238.03,1458441857.8652,163.64088371195 -450,0.00042348834913579,9.8625749434492e-07,8733495794009.5,1869215751.4822,701766932506.41,1503800065.3675,153.96894709881 -500,0.00046930528109519,9.1633820013346e-07,8798533890027.3,1300761920.3547,772488647691.05,1414434303.6928,144.981779676 +time,eff_inelastic_strain,rhoi_dd,rhom_dd,vm_stress +0,0,0,0,0 +50,4.5496906028936e-05,8084187502695.6,157948301938.23,1.8250120749944e-08 +100,9.0915959189835e-05,8168642066269.5,215476713890.19,1.8250120749944e-08 +150,0.00013674442698179,8247659636397.6,277790844373.99,8.9735674676767 +200,0.00018310223520928,8316172641461,344400120884.03,201.15841573873 +250,0.00023002630928264,8389517770048.1,412682723429.64,191.95407813203 +300,0.00027756452791649,8467451766416.1,482196322313.52,182.6292737077 +350,0.00032570596949926,8550248549559.6,553246175710.56,173.18614478185 +400,0.0003744395920655,8638215168403.1,626174049473.27,163.62685727847 +450,0.00042375333768599,8731691988496.9,701366865953.69,153.95377640676 +500,0.00046957171307809,8796729665740.5,772077330270.76,144.96632584908 diff --git a/modules/solid_mechanics/test/tests/neml2/laromance/laromance_interpolate.i b/modules/solid_mechanics/test/tests/neml2/laromance/laromance_interpolate.i index 24c1637bc428..54d7c48ea167 100644 --- a/modules/solid_mechanics/test/tests/neml2/laromance/laromance_interpolate.i +++ b/modules/solid_mechanics/test/tests/neml2/laromance/laromance_interpolate.i @@ -76,7 +76,7 @@ sample_file = "models/sampled_combinations.csv" [Materials] [in_materials] type = GenericFunctionMaterial - prop_names = 'vmStress temperature epStrain celldd walldd env' + prop_names = 'von_mises_stress temperature equivalent_plastic_strain cell_dislocation_density wall_dislocation_density env_factor' prop_values = 'vmStress_fcn temperature_fcn epStrain_fcn celldd_fcn walldd_fcn env_fcn' [] [] @@ -87,14 +87,6 @@ sample_file = "models/sampled_combinations.csv" model = 'combined_model' verbose = true device = 'cpu' - - moose_input_types = 'MATERIAL MATERIAL MATERIAL MATERIAL MATERIAL MATERIAL' - moose_inputs = 'epStrain vmStress temperature celldd walldd env' - neml2_inputs = 'state/ep state/s forces/T forces/cell_dd forces/wall_dd forces/env_fac' - - moose_output_types = 'MATERIAL MATERIAL MATERIAL' - moose_outputs = 'ep_rate cell_rate wall_rate' - neml2_outputs = 'state/ep_rate state/cell_rate state/wall_rate' [] [] @@ -102,7 +94,7 @@ sample_file = "models/sampled_combinations.csv" type = Transient nl_abs_tol = 1e-1 # Nothing is really being solved here, so loose tolerances are okay dt = 1 - dtmin=1 + dtmin = 1 end_time = 40 timestep_tolerance = 1e-3 [] @@ -110,15 +102,15 @@ sample_file = "models/sampled_combinations.csv" [Postprocessors] [cell_rate_pp] type = ElementAverageMaterialProperty - mat_prop = cell_rate + mat_prop = cell_dislocation_density_rate [] [wall_rate_pp] type = ElementAverageMaterialProperty - mat_prop = wall_rate + mat_prop = wall_dislocation_density_rate [] [creep_rate_pp] type = ElementAverageMaterialProperty - mat_prop = ep_rate + mat_prop = equivalent_plastic_strain_rate [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/laromance/laromance_return_mapping.i b/modules/solid_mechanics/test/tests/neml2/laromance/laromance_return_mapping.i index e201bc3e5ffa..eaa3061cf8e1 100644 --- a/modules/solid_mechanics/test/tests/neml2/laromance/laromance_return_mapping.i +++ b/modules/solid_mechanics/test/tests/neml2/laromance/laromance_return_mapping.i @@ -64,7 +64,7 @@ [Materials] [init_dd] type = GenericConstantMaterial - prop_names = 'T init_cell_dd init_wall_dd init_envFac' + prop_names = 'temperature init_cell_dd init_wall_dd env_factor' prop_values = '750 1e11 8e12 2e15' [] [] @@ -75,21 +75,9 @@ model = 'model' verbose = true device = 'cpu' - - moose_input_types = 'MATERIAL MATERIAL MATERIAL MATERIAL MATERIAL MATERIAL MATERIAL POSTPROCESSOR POSTPROCESSOR' - moose_inputs = 'T neml2_strain inelastic_strain eff_inelastic_strain cell_dd wall_dd init_envFac time time' - neml2_inputs = 'forces/T forces/E old_state/Ep old_state/ep old_state/cell_dd old_state/wall_dd forces/env_fac forces/t old_forces/t' - - moose_output_types = 'Material MATERIAL MATERIAL MATERIAL MATERIAL MATERIAL MATERIAL MATERIAL MATERIAL' - moose_outputs = 'neml2_stress inelastic_strain eff_inelastic_strain eff_inelastic_strain_rate vonmises_stress cell_rate wall_rate cell_dd wall_dd' - neml2_outputs = 'state/S state/Ep state/ep state/ep_rate state/s state/cell_rate state/wall_rate state/cell_dd state/wall_dd' - - initialize_outputs = 'wall_dd cell_dd init_envFac' - initialize_output_values = 'init_wall_dd init_cell_dd init_envFac' - - moose_derivative_types = 'MATERIAL' - moose_derivatives = 'neml2_jacobian' - neml2_derivatives = 'state/S forces/E' + initialize_outputs = 'wall_dislocation_density cell_dislocation_density' + initialize_output_values = 'init_wall_dd init_cell_dd' + derivatives = 'neml2_stress neml2_strain' [] [] @@ -102,7 +90,7 @@ [stress] type = ComputeLagrangianObjectiveCustomSymmetricStress custom_small_stress = 'neml2_stress' - custom_small_jacobian = 'neml2_jacobian' + custom_small_jacobian = 'dneml2_stress/dneml2_strain' [] [] @@ -121,38 +109,21 @@ [] [Postprocessors] - [time] - type = TimePostprocessor - execute_on = 'INITIAL TIMESTEP_BEGIN' - outputs = 'none' - [] [eff_inelastic_strain] type = ElementAverageMaterialProperty - mat_prop = eff_inelastic_strain - [] - [eff_inelastic_strain_rate] - type = ElementAverageMaterialProperty - mat_prop = eff_inelastic_strain_rate - [] - [rhom_rate] - type = ElementAverageMaterialProperty - mat_prop = cell_rate - [] - [rhoi_rate] - type = ElementAverageMaterialProperty - mat_prop = wall_rate + mat_prop = equivalent_plastic_strain [] [rhom_dd] type = ElementAverageMaterialProperty - mat_prop = cell_dd + mat_prop = cell_dislocation_density [] [rhoi_dd] type = ElementAverageMaterialProperty - mat_prop = wall_dd + mat_prop = wall_dislocation_density [] [vm_stress] type = ElementAverageMaterialProperty - mat_prop = vonmises_stress + mat_prop = von_mises_stress [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/laromance/models/laromance_matl_interp.i b/modules/solid_mechanics/test/tests/neml2/laromance/models/laromance_matl_interp.i index 8524c1139068..62eb480c3867 100644 --- a/modules/solid_mechanics/test/tests/neml2/laromance/models/laromance_matl_interp.i +++ b/modules/solid_mechanics/test/tests/neml2/laromance/models/laromance_matl_interp.i @@ -3,40 +3,19 @@ type = LAROMANCE6DInterpolation model_file_name = 'models/random_value_6d_grid.json' model_file_variable_name = 'out_ep' - output_rate = 'state/ep_rate' - # grid nodes - von_mises_stress = 'state/s' - temperature = 'forces/T' - equivalent_plastic_strain = 'state/ep' - cell_dislocation_density = 'forces/cell_dd' - wall_dislocation_density = 'forces/wall_dd' - env_factor = 'forces/env_fac' + output_rate = 'equivalent_plastic_strain_rate' [] [rom_cell] type = LAROMANCE6DInterpolation model_file_name = 'models/random_value_6d_grid.json' model_file_variable_name = 'out_cell' - output_rate = 'state/cell_rate' - # grid nodes - von_mises_stress = 'state/s' - temperature = 'forces/T' - equivalent_plastic_strain = 'state/ep' - cell_dislocation_density = 'forces/cell_dd' - wall_dislocation_density = 'forces/wall_dd' - env_factor = 'forces/env_fac' + output_rate = 'cell_dislocation_density_rate' [] [rom_wall] type = LAROMANCE6DInterpolation model_file_name = 'models/random_value_6d_grid.json' model_file_variable_name = 'out_wall' - output_rate = 'state/wall_rate' - # grid nodes - von_mises_stress = 'state/s' - temperature = 'forces/T' - equivalent_plastic_strain = 'state/ep' - cell_dislocation_density = 'forces/cell_dd' - wall_dislocation_density = 'forces/wall_dd' - env_factor = 'forces/env_fac' + output_rate = 'wall_dislocation_density_rate' [] [combined_model] type = ComposedModel diff --git a/modules/solid_mechanics/test/tests/neml2/laromance/models/laromance_matl_interp_bad.i b/modules/solid_mechanics/test/tests/neml2/laromance/models/laromance_matl_interp_bad.i index c14fd1598274..1c8c49e633e0 100644 --- a/modules/solid_mechanics/test/tests/neml2/laromance/models/laromance_matl_interp_bad.i +++ b/modules/solid_mechanics/test/tests/neml2/laromance/models/laromance_matl_interp_bad.i @@ -3,40 +3,19 @@ type = LAROMANCE6DInterpolation model_file_name = 'models/random_value_6d_grid_bad.json' model_file_variable_name = 'out_ep' - output_rate = 'state/ep_rate' - # grid nodes - von_mises_stress = 'state/s' - temperature = 'forces/T' - equivalent_plastic_strain = 'state/ep' - cell_dislocation_density = 'forces/cell_dd' - wall_dislocation_density = 'forces/wall_dd' - env_factor = 'forces/env_fac' + output_rate = 'equivalent_plastic_strain_rate' [] [rom_cell] type = LAROMANCE6DInterpolation model_file_name = 'models/random_value_6d_grid.json' model_file_variable_name = 'out_cell' - output_rate = 'state/cell_rate' - # grid nodes - von_mises_stress = 'state/s' - temperature = 'forces/T' - equivalent_plastic_strain = 'state/ep' - cell_dislocation_density = 'forces/cell_dd' - wall_dislocation_density = 'forces/wall_dd' - env_factor = 'forces/env_fac' + output_rate = 'cell_dislocation_density_rate' [] [rom_wall] type = LAROMANCE6DInterpolation model_file_name = 'models/random_value_6d_grid.json' model_file_variable_name = 'out_wall' - output_rate = 'state/wall_rate' - # grid nodes - von_mises_stress = 'state/s' - temperature = 'forces/T' - equivalent_plastic_strain = 'state/ep' - cell_dislocation_density = 'forces/cell_dd' - wall_dislocation_density = 'forces/wall_dd' - env_factor = 'forces/env_fac' + output_rate = 'wall_dislocation_density_rate' [] [combined_model] type = ComposedModel diff --git a/modules/solid_mechanics/test/tests/neml2/laromance/models/laromance_matl_radial_return.i b/modules/solid_mechanics/test/tests/neml2/laromance/models/laromance_matl_radial_return.i index 665ddee7876e..14cb3b31baa5 100644 --- a/modules/solid_mechanics/test/tests/neml2/laromance/models/laromance_matl_radial_return.i +++ b/modules/solid_mechanics/test/tests/neml2/laromance/models/laromance_matl_radial_return.i @@ -6,21 +6,20 @@ ##################################################################################### [trial_elastic_strain] type = SR2LinearCombination - to_var = 'state/Ee' - from_var = 'forces/E old_state/Ep' - coefficients = '1 -1' + from = 'neml2_strain plastic_strain~1' + to = 'elastic_strain' + weights = '1 -1' [] [cauchy_stress] type = LinearIsotropicElasticity coefficient_types = 'YOUNGS_MODULUS POISSONS_RATIO' #MPa coefficients = '170e3 0.3' - strain = 'state/Ee' - stress = 'state/S' + strain = 'elastic_strain' + stress = 'neml2_stress' [] [flow_direction] type = AssociativeJ2FlowDirection - mandel_stress = 'state/S' - flow_direction = 'forces/N' + mandel_stress = 'neml2_stress' [] [trial_state] type = ComposedModel @@ -32,17 +31,15 @@ ##################################################################################### [ep_rate] type = ScalarVariableRate - variable = 'state/ep' + variable = 'equivalent_plastic_strain' [] [plastic_strain_rate] type = AssociativePlasticFlow - flow_direction = 'forces/N' - flow_rate = 'state/ep_rate' - plastic_strain_rate = 'state/Ep_rate' + flow_rate = 'equivalent_plastic_strain_rate' [] [plastic_strain] type = SR2ForwardEulerTimeIntegration - variable = 'state/Ep' + variable = 'plastic_strain' [] [plastic_update] type = ComposedModel @@ -50,9 +47,9 @@ [] [elastic_strain] type = SR2LinearCombination - to_var = 'state/Ee' - from_var = 'forces/E state/Ep' - coefficients = '1 -1' + from = 'neml2_strain plastic_strain' + to = 'elastic_strain' + weights = '1 -1' [] [stress_update] type = ComposedModel @@ -65,30 +62,22 @@ [vonmises] type = SR2Invariant invariant_type = 'VONMISES' - tensor = 'state/S' - invariant = 'state/s' + tensor = 'neml2_stress' + invariant = 'von_mises_stress' [] [rom_ep] type = LAROMANCE6DInterpolation model_file_name = 'models/random_value_6d_grid.json' model_file_variable_name = 'out_ep' - output_rate = 'state/ep_rate' - # grid nodes - von_mises_stress = 'state/s' - equivalent_plastic_strain = 'state/ep' - cell_dislocation_density = 'old_state/cell_dd' - wall_dislocation_density = 'old_state/wall_dd' - temperature = 'forces/T' - env_factor = 'forces/env_fac' + output_rate = 'equivalent_plastic_strain_rate' [] [integrate_ep] type = ScalarBackwardEulerTimeIntegration - variable = 'state/ep' + variable = 'equivalent_plastic_strain' [] [rate] type = ComposedModel - models = "plastic_update stress_update vonmises rom_ep - integrate_ep" + models = 'plastic_update stress_update vonmises rom_ep integrate_ep' [] [] @@ -96,6 +85,7 @@ [eq_sys] type = NonlinearSystem model = 'rate' + unknowns = 'equivalent_plastic_strain' [] [] @@ -112,10 +102,15 @@ [] [Models] + [predictor] + type = ConstantExtrapolationPredictor + unknowns_Scalar = 'equivalent_plastic_strain' + [] [radial_return] type = ImplicitUpdate equation_system = 'eq_sys' solver = 'newton' + predictor = 'predictor' [] ##################################################################################### # Extra materials that evolve dislocation densities @@ -124,37 +119,21 @@ type = LAROMANCE6DInterpolation model_file_name = 'models/random_value_6d_grid.json' model_file_variable_name = 'out_cell' - output_rate = 'state/cell_rate' - # grid nodes - von_mises_stress = 'state/s' - equivalent_plastic_strain = 'state/ep' - cell_dislocation_density = 'old_state/cell_dd' - wall_dislocation_density = 'old_state/wall_dd' - temperature = 'forces/T' - env_factor = 'forces/env_fac' + output_rate = 'cell_dislocation_density_rate' [] [rom_wall] type = LAROMANCE6DInterpolation model_file_name = 'models/random_value_6d_grid.json' model_file_variable_name = 'out_wall' - output_rate = 'state/wall_rate' - # grid nodes - von_mises_stress = 'state/s' - equivalent_plastic_strain = 'state/ep' - cell_dislocation_density = 'old_state/cell_dd' - wall_dislocation_density = 'old_state/wall_dd' - temperature = 'forces/T' - env_factor = 'forces/env_fac' + output_rate = 'wall_dislocation_density_rate' [] [cell_dd] type = ScalarForwardEulerTimeIntegration - variable = 'state/cell_dd' - rate = 'state/cell_rate' + variable = 'cell_dislocation_density' [] [wall_dd] type = ScalarForwardEulerTimeIntegration - variable = 'state/wall_dd' - rate = 'state/wall_rate' + variable = 'wall_dislocation_density' [] ##################################################################################### @@ -164,6 +143,6 @@ type = ComposedModel models = 'trial_state radial_return plastic_update stress_update vonmises rom_ep rom_cell rom_wall cell_dd wall_dd' priority = 'trial_state radial_return plastic_update stress_update vonmises rom_ep rom_cell rom_wall cell_dd wall_dd' - additional_outputs = 'state/s state/ep state/S state/Ep state/ep_rate state/cell_rate state/wall_rate state/cell_dd state/wall_dd' + additional_outputs = 'von_mises_stress equivalent_plastic_strain neml2_stress plastic_strain cell_dislocation_density wall_dislocation_density' [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/plasticity/isoharden.i b/modules/solid_mechanics/test/tests/neml2/plasticity/isoharden.i index 7b177e31e761..b0c9fc0e053f 100644 --- a/modules/solid_mechanics/test/tests/neml2/plasticity/isoharden.i +++ b/modules/solid_mechanics/test/tests/neml2/plasticity/isoharden.i @@ -34,26 +34,7 @@ N = 2 model = 'model' verbose = true device = 'cpu' - - moose_input_types = 'MATERIAL POSTPROCESSOR POSTPROCESSOR MATERIAL MATERIAL' - moose_inputs = ' neml2_strain time time plastic_strain equivalent_plastic_strain' - neml2_inputs = ' forces/E forces/t old_forces/t old_state/internal/Ep old_state/internal/ep' - - moose_output_types = 'MATERIAL MATERIAL MATERIAL' - moose_outputs = ' neml2_stress plastic_strain equivalent_plastic_strain' - neml2_outputs = ' state/S state/internal/Ep state/internal/ep' - - moose_derivative_types = 'MATERIAL' - moose_derivatives = 'neml2_jacobian' - neml2_derivatives = 'state/S forces/E' - [] -[] - -[Postprocessors] - [time] - type = TimePostprocessor - execute_on = 'INITIAL TIMESTEP_BEGIN' - outputs = 'none' + derivatives = 'neml2_stress neml2_strain' [] [] @@ -66,7 +47,7 @@ N = 2 [stress] type = ComputeLagrangianObjectiveCustomSymmetricStress custom_small_stress = 'neml2_stress' - custom_small_jacobian = 'neml2_jacobian' + custom_small_jacobian = 'dneml2_stress/dneml2_strain' [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/plasticity/isoharden_neml2.i b/modules/solid_mechanics/test/tests/neml2/plasticity/isoharden_neml2.i index 514c77b69c2b..ee603d03cc9e 100644 --- a/modules/solid_mechanics/test/tests/neml2/plasticity/isoharden_neml2.i +++ b/modules/solid_mechanics/test/tests/neml2/plasticity/isoharden_neml2.i @@ -6,28 +6,31 @@ [] [elastic_strain] type = SR2LinearCombination - from_var = 'forces/E state/internal/Ep' - to_var = 'state/internal/Ee' - coefficients = '1 -1' + from = 'neml2_strain plastic_strain' + to = 'elastic_strain' + weights = '1 -1' [] [elasticity] type = LinearIsotropicElasticity coefficients = '1e5 0.3' coefficient_types = 'YOUNGS_MODULUS POISSONS_RATIO' + strain = 'elastic_strain' + stress = 'neml2_stress' [] [mandel_stress] type = IsotropicMandelStress + cauchy_stress = 'neml2_stress' [] [vonmises] type = SR2Invariant invariant_type = 'VONMISES' - tensor = 'state/internal/M' - invariant = 'state/internal/s' + tensor = 'mandel_stress' + invariant = 'effective_stress' [] [yield] type = YieldFunction yield_stress = 5 - isotropic_hardening = 'state/internal/k' + isotropic_hardening = 'isotropic_hardening' [] [flow] type = ComposedModel @@ -36,9 +39,9 @@ [normality] type = Normality model = 'flow' - function = 'state/internal/fp' - from = 'state/internal/M state/internal/k' - to = 'state/internal/NM state/internal/Nk' + function = 'yield_function' + from = 'mandel_stress isotropic_hardening' + to = 'flow_direction isotropic_hardening_direction' [] [eprate] type = AssociativeIsotropicPlasticHardening @@ -48,14 +51,17 @@ [] [integrate_ep] type = ScalarBackwardEulerTimeIntegration - variable = 'state/internal/ep' + variable = 'equivalent_plastic_strain' [] [integrate_Ep] type = SR2BackwardEulerTimeIntegration - variable = 'state/internal/Ep' + variable = 'plastic_strain' [] [consistency] - type = RateIndependentPlasticFlowConstraint + type = FBComplementarity + a = 'yield_function' + a_inequality = 'LE' + b = 'flow_rate' [] [surface] type = ComposedModel @@ -70,6 +76,8 @@ [eq_sys] type = NonlinearSystem model = 'surface' + unknowns = 'plastic_strain equivalent_plastic_strain flow_rate' + residuals = 'plastic_strain_residual equivalent_plastic_strain_residual complementarity' [] [] @@ -84,14 +92,20 @@ [] [Models] + [predictor] + type = ConstantExtrapolationPredictor + unknowns_SR2 = 'plastic_strain' + unknowns_Scalar = 'equivalent_plastic_strain flow_rate' + [] [return_map] type = ImplicitUpdate equation_system = 'eq_sys' solver = 'newton' + predictor = 'predictor' [] [model] type = ComposedModel models = 'return_map elastic_strain elasticity' - additional_outputs = 'state/internal/Ep state/internal/ep' + additional_outputs = 'plastic_strain equivalent_plastic_strain' [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/plasticity/isokinharden.i b/modules/solid_mechanics/test/tests/neml2/plasticity/isokinharden.i index f2b8cef4cc7f..e91367620ad7 100644 --- a/modules/solid_mechanics/test/tests/neml2/plasticity/isokinharden.i +++ b/modules/solid_mechanics/test/tests/neml2/plasticity/isokinharden.i @@ -34,26 +34,7 @@ N = 2 model = 'model' verbose = true device = 'cpu' - - moose_input_types = 'MATERIAL POSTPROCESSOR POSTPROCESSOR MATERIAL MATERIAL MATERIAL' - moose_inputs = ' neml2_strain time time plastic_strain equivalent_plastic_strain kinematic_plastic_strain' - neml2_inputs = ' forces/E forces/t old_forces/t old_state/internal/Ep old_state/internal/ep old_state/internal/Kp' - - moose_output_types = 'MATERIAL MATERIAL MATERIAL MATERIAL' - moose_outputs = ' neml2_stress plastic_strain equivalent_plastic_strain kinematic_plastic_strain' - neml2_outputs = ' state/S state/internal/Ep state/internal/ep state/internal/Kp' - - moose_derivative_types = 'MATERIAL' - moose_derivatives = 'neml2_jacobian' - neml2_derivatives = 'state/S forces/E' - [] -[] - -[Postprocessors] - [time] - type = TimePostprocessor - execute_on = 'INITIAL TIMESTEP_BEGIN' - outputs = 'none' + derivatives = 'neml2_stress neml2_strain' [] [] @@ -66,7 +47,7 @@ N = 2 [stress] type = ComputeLagrangianObjectiveCustomSymmetricStress custom_small_stress = 'neml2_stress' - custom_small_jacobian = 'neml2_jacobian' + custom_small_jacobian = 'dneml2_stress/dneml2_strain' [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/plasticity/isokinharden_neml2.i b/modules/solid_mechanics/test/tests/neml2/plasticity/isokinharden_neml2.i index c186c4e7b3a7..8cbd1ec3a371 100644 --- a/modules/solid_mechanics/test/tests/neml2/plasticity/isokinharden_neml2.i +++ b/modules/solid_mechanics/test/tests/neml2/plasticity/isokinharden_neml2.i @@ -10,34 +10,37 @@ [] [elastic_strain] type = SR2LinearCombination - from_var = 'forces/E state/internal/Ep' - to_var = 'state/internal/Ee' - coefficients = '1 -1' + from = 'neml2_strain plastic_strain' + to = 'elastic_strain' + weights = '1 -1' [] [elasticity] type = LinearIsotropicElasticity coefficients = '1e5 0.3' coefficient_types = 'YOUNGS_MODULUS POISSONS_RATIO' + strain = 'elastic_strain' + stress = 'neml2_stress' [] [mandel_stress] type = IsotropicMandelStress + cauchy_stress = 'neml2_stress' [] [overstress] type = SR2LinearCombination - to_var = 'state/internal/O' - from_var = 'state/internal/M state/internal/X' - coefficients = '1 -1' + to = 'over_stress' + from = 'mandel_stress back_stress' + weights = '1 -1' [] [vonmises] type = SR2Invariant invariant_type = 'VONMISES' - tensor = 'state/internal/O' - invariant = 'state/internal/s' + tensor = 'over_stress' + invariant = 'effective_stress' [] [yield] type = YieldFunction yield_stress = 5 - isotropic_hardening = 'state/internal/k' + isotropic_hardening = 'isotropic_hardening' [] [flow] type = ComposedModel @@ -46,9 +49,9 @@ [normality] type = Normality model = 'flow' - function = 'state/internal/fp' - from = 'state/internal/M state/internal/X state/internal/k' - to = 'state/internal/NM state/internal/NX state/internal/Nk' + function = 'yield_function' + from = 'mandel_stress back_stress isotropic_hardening' + to = 'flow_direction kinematic_hardening_direction isotropic_hardening_direction' [] [eprate] type = AssociativeIsotropicPlasticHardening @@ -61,18 +64,21 @@ [] [integrate_ep] type = ScalarBackwardEulerTimeIntegration - variable = 'state/internal/ep' + variable = 'equivalent_plastic_strain' [] [integrate_Kp] type = SR2BackwardEulerTimeIntegration - variable = 'state/internal/Kp' + variable = 'kinematic_plastic_strain' [] [integrate_Ep] type = SR2BackwardEulerTimeIntegration - variable = 'state/internal/Ep' + variable = 'plastic_strain' [] [consistency] - type = RateIndependentPlasticFlowConstraint + type = FBComplementarity + a = 'yield_function' + a_inequality = 'LE' + b = 'flow_rate' [] [surface] type = ComposedModel @@ -87,6 +93,8 @@ [eq_sys] type = NonlinearSystem model = 'surface' + unknowns = 'plastic_strain kinematic_plastic_strain equivalent_plastic_strain flow_rate' + residuals = 'plastic_strain_residual kinematic_plastic_strain_residual equivalent_plastic_strain_residual complementarity' [] [] @@ -101,14 +109,20 @@ [] [Models] + [predictor] + type = ConstantExtrapolationPredictor + unknowns_SR2 = 'plastic_strain kinematic_plastic_strain' + unknowns_Scalar = 'equivalent_plastic_strain flow_rate' + [] [return_map] type = ImplicitUpdate equation_system = 'eq_sys' solver = 'newton' + predictor = 'predictor' [] [model] type = ComposedModel models = 'return_map elastic_strain elasticity' - additional_outputs = 'state/internal/Ep state/internal/Kp state/internal/ep' + additional_outputs = 'plastic_strain kinematic_plastic_strain equivalent_plastic_strain' [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/plasticity/kinharden.i b/modules/solid_mechanics/test/tests/neml2/plasticity/kinharden.i index 41d7116629c0..5f784540f726 100644 --- a/modules/solid_mechanics/test/tests/neml2/plasticity/kinharden.i +++ b/modules/solid_mechanics/test/tests/neml2/plasticity/kinharden.i @@ -34,26 +34,7 @@ N = 2 model = 'model' verbose = true device = 'cpu' - - moose_input_types = 'MATERIAL POSTPROCESSOR POSTPROCESSOR MATERIAL MATERIAL' - moose_inputs = ' neml2_strain time time plastic_strain kinematic_plastic_strain' - neml2_inputs = ' forces/E forces/t old_forces/t old_state/internal/Ep old_state/internal/Kp' - - moose_output_types = 'MATERIAL MATERIAL MATERIAL' - moose_outputs = ' neml2_stress plastic_strain kinematic_plastic_strain' - neml2_outputs = ' state/S state/internal/Ep state/internal/Kp' - - moose_derivative_types = 'MATERIAL' - moose_derivatives = 'neml2_jacobian' - neml2_derivatives = 'state/S forces/E' - [] -[] - -[Postprocessors] - [time] - type = TimePostprocessor - execute_on = 'INITIAL TIMESTEP_BEGIN' - outputs = 'none' + derivatives = 'neml2_stress neml2_strain' [] [] @@ -66,7 +47,7 @@ N = 2 [stress] type = ComputeLagrangianObjectiveCustomSymmetricStress custom_small_stress = 'neml2_stress' - custom_small_jacobian = 'neml2_jacobian' + custom_small_jacobian = 'dneml2_stress/dneml2_strain' [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/plasticity/kinharden_neml2.i b/modules/solid_mechanics/test/tests/neml2/plasticity/kinharden_neml2.i index bc963627c167..9ba4d1e5b331 100644 --- a/modules/solid_mechanics/test/tests/neml2/plasticity/kinharden_neml2.i +++ b/modules/solid_mechanics/test/tests/neml2/plasticity/kinharden_neml2.i @@ -5,29 +5,32 @@ [] [elastic_strain] type = SR2LinearCombination - from_var = 'forces/E state/internal/Ep' - to_var = 'state/internal/Ee' - coefficients = '1 -1' + from = 'neml2_strain plastic_strain' + to = 'elastic_strain' + weights = '1 -1' [] [elasticity] type = LinearIsotropicElasticity coefficients = '1e5 0.3' coefficient_types = 'YOUNGS_MODULUS POISSONS_RATIO' + strain = 'elastic_strain' + stress = 'neml2_stress' [] [mandel_stress] type = IsotropicMandelStress + cauchy_stress = 'neml2_stress' [] [overstress] type = SR2LinearCombination - to_var = 'state/internal/O' - from_var = 'state/internal/M state/internal/X' - coefficients = '1 -1' + to = 'over_stress' + from = 'mandel_stress back_stress' + weights = '1 -1' [] [vonmises] type = SR2Invariant invariant_type = 'VONMISES' - tensor = 'state/internal/O' - invariant = 'state/internal/s' + tensor = 'over_stress' + invariant = 'effective_stress' [] [yield] type = YieldFunction @@ -40,9 +43,9 @@ [normality] type = Normality model = 'flow' - function = 'state/internal/fp' - from = 'state/internal/M state/internal/X' - to = 'state/internal/NM state/internal/NX' + function = 'yield_function' + from = 'mandel_stress back_stress' + to = 'flow_direction kinematic_hardening_direction' [] [Kprate] type = AssociativeKinematicPlasticHardening @@ -52,14 +55,17 @@ [] [integrate_Kp] type = SR2BackwardEulerTimeIntegration - variable = 'state/internal/Kp' + variable = 'kinematic_plastic_strain' [] [integrate_Ep] type = SR2BackwardEulerTimeIntegration - variable = 'state/internal/Ep' + variable = 'plastic_strain' [] [consistency] - type = RateIndependentPlasticFlowConstraint + type = FBComplementarity + a = 'yield_function' + a_inequality = 'LE' + b = 'flow_rate' [] [surface] type = ComposedModel @@ -74,6 +80,8 @@ [eq_sys] type = NonlinearSystem model = 'surface' + unknowns = 'plastic_strain kinematic_plastic_strain flow_rate' + residuals = 'plastic_strain_residual kinematic_plastic_strain_residual complementarity' [] [] @@ -88,14 +96,20 @@ [] [Models] + [predictor] + type = ConstantExtrapolationPredictor + unknowns_SR2 = 'plastic_strain kinematic_plastic_strain' + unknowns_Scalar = 'flow_rate' + [] [return_map] type = ImplicitUpdate equation_system = 'eq_sys' solver = 'newton' + predictor = 'predictor' [] [model] type = ComposedModel models = 'return_map elastic_strain elasticity' - additional_outputs = 'state/internal/Ep state/internal/Kp' + additional_outputs = 'plastic_strain kinematic_plastic_strain' [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/plasticity/perfect.i b/modules/solid_mechanics/test/tests/neml2/plasticity/perfect.i index 8b2c8ee6e22e..a584d55950ed 100644 --- a/modules/solid_mechanics/test/tests/neml2/plasticity/perfect.i +++ b/modules/solid_mechanics/test/tests/neml2/plasticity/perfect.i @@ -34,26 +34,7 @@ N = 2 model = 'model' verbose = true device = 'cpu' - - moose_input_types = 'MATERIAL POSTPROCESSOR POSTPROCESSOR MATERIAL' - moose_inputs = ' neml2_strain time time plastic_strain' - neml2_inputs = ' forces/E forces/t old_forces/t old_state/internal/Ep' - - moose_output_types = 'MATERIAL MATERIAL' - moose_outputs = ' neml2_stress plastic_strain' - neml2_outputs = ' state/S state/internal/Ep' - - moose_derivative_types = 'MATERIAL' - moose_derivatives = 'neml2_jacobian' - neml2_derivatives = 'state/S forces/E' - [] -[] - -[Postprocessors] - [time] - type = TimePostprocessor - execute_on = 'INITIAL TIMESTEP_BEGIN' - outputs = 'none' + derivatives = 'neml2_stress neml2_strain' [] [] @@ -66,7 +47,7 @@ N = 2 [stress] type = ComputeLagrangianObjectiveCustomSymmetricStress custom_small_stress = 'neml2_stress' - custom_small_jacobian = 'neml2_jacobian' + custom_small_jacobian = 'dneml2_stress/dneml2_strain' [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/plasticity/perfect_neml2.i b/modules/solid_mechanics/test/tests/neml2/plasticity/perfect_neml2.i index 225c6695fb8b..2cee2a4b0b96 100644 --- a/modules/solid_mechanics/test/tests/neml2/plasticity/perfect_neml2.i +++ b/modules/solid_mechanics/test/tests/neml2/plasticity/perfect_neml2.i @@ -1,23 +1,26 @@ [Models] [elastic_strain] type = SR2LinearCombination - from_var = 'forces/E state/internal/Ep' - to_var = 'state/internal/Ee' - coefficients = '1 -1' + from = 'neml2_strain plastic_strain' + to = 'elastic_strain' + weights = '1 -1' [] [elasticity] type = LinearIsotropicElasticity coefficients = '1e5 0.3' coefficient_types = 'YOUNGS_MODULUS POISSONS_RATIO' + strain = 'elastic_strain' + stress = 'neml2_stress' [] [mandel_stress] type = IsotropicMandelStress + cauchy_stress = 'neml2_stress' [] [vonmises] type = SR2Invariant invariant_type = 'VONMISES' - tensor = 'state/internal/M' - invariant = 'state/internal/s' + tensor = 'mandel_stress' + invariant = 'effective_stress' [] [yield] type = YieldFunction @@ -30,19 +33,22 @@ [normality] type = Normality model = 'flow' - function = 'state/internal/fp' - from = 'state/internal/M' - to = 'state/internal/NM' + function = 'yield_function' + from = 'mandel_stress' + to = 'flow_direction' [] [Eprate] type = AssociativePlasticFlow [] [integrate_Ep] type = SR2BackwardEulerTimeIntegration - variable = 'state/internal/Ep' + variable = 'plastic_strain' [] [consistency] - type = RateIndependentPlasticFlowConstraint + type = FBComplementarity + a = 'yield_function' + a_inequality = 'LE' + b = 'flow_rate' [] [surface] type = ComposedModel @@ -57,6 +63,8 @@ [eq_sys] type = NonlinearSystem model = 'surface' + unknowns = 'plastic_strain flow_rate' + residuals = 'plastic_strain_residual complementarity' [] [] @@ -71,14 +79,20 @@ [] [Models] + [predictor] + type = ConstantExtrapolationPredictor + unknowns_SR2 = 'plastic_strain' + unknowns_Scalar = 'flow_rate' + [] [return_map] type = ImplicitUpdate equation_system = 'eq_sys' solver = 'newton' + predictor = 'predictor' [] [model] type = ComposedModel models = 'return_map elastic_strain elasticity' - additional_outputs = 'state/internal/Ep' + additional_outputs = 'plastic_strain' [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/plasticity/tests b/modules/solid_mechanics/test/tests/neml2/plasticity/tests index 4b8c5b559c2d..833e56259886 100644 --- a/modules/solid_mechanics/test/tests/neml2/plasticity/tests +++ b/modules/solid_mechanics/test/tests/neml2/plasticity/tests @@ -11,15 +11,6 @@ capabilities = 'neml2' valgrind = heavy [] - [perfect_keep_tensors_on_device] - detail = 'perfect plasticity with tensors kept on the compute device, ' - type = Exodiff - input = 'perfect.i' - exodiff = 'perfect_out.e' - capabilities = 'neml2' - valgrind = heavy - cli_args = "NEML2/all/keep_tensors_on_device=true NEML2/all/moose_input_types='MATERIAL POSTPROCESSOR' NEML2/all/moose_inputs='neml2_strain time' NEML2/all/neml2_inputs='forces/E forces/t'" - [] [isoharden] detail = 'isotropic hardening, ' type = Exodiff @@ -45,4 +36,14 @@ valgrind = heavy [] [] + [manage_state_advance] + requirement = 'The system shall be capable of managing the state advance for the NEML2 constitutive update on device.' + type = Exodiff + input = 'perfect.i' + cli_args = "NEML2/all/manage_state_advance=true" + exodiff = 'perfect_out.e' + issues = '#27493' + capabilities = 'neml2' + valgrind = heavy + [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/solve_failure/gold/moose_out.e b/modules/solid_mechanics/test/tests/neml2/solve_failure/gold/moose_out.e index baff32ca7c63..38379ff48a93 100644 Binary files a/modules/solid_mechanics/test/tests/neml2/solve_failure/gold/moose_out.e and b/modules/solid_mechanics/test/tests/neml2/solve_failure/gold/moose_out.e differ diff --git a/modules/solid_mechanics/test/tests/neml2/solve_failure/moose.i b/modules/solid_mechanics/test/tests/neml2/solve_failure/moose.i index 6bde9ae56653..e01c8d60e8e3 100644 --- a/modules/solid_mechanics/test/tests/neml2/solve_failure/moose.i +++ b/modules/solid_mechanics/test/tests/neml2/solve_failure/moose.i @@ -28,12 +28,6 @@ N = 2 [] [] -[AuxVariables] - [temp] - initial_condition = 1200 - [] -[] - [BCs] [xfix] type = DirichletBC @@ -70,15 +64,7 @@ N = 2 model = 'model' verbose = true device = 'cpu' - moose_input_types = 'MATERIAL MATERIAL POSTPROCESSOR POSTPROCESSOR MATERIAL MATERIAL MATERIAL' - moose_inputs = ' neml2_strain neml2_strain time time neml2_stress equivalent_plastic_strain back_stress' - neml2_inputs = ' forces/E old_forces/E forces/t old_forces/t old_state/S old_state/internal/ep old_state/internal/X' - moose_output_types = 'MATERIAL MATERIAL MATERIAL' - moose_outputs = ' neml2_stress equivalent_plastic_strain back_stress' - neml2_outputs = ' state/S state/internal/ep state/internal/X' - moose_derivative_types = 'MATERIAL' - moose_derivatives = 'neml2_jacobian' - neml2_derivatives = 'state/S forces/E' + derivatives = 'neml2_stress neml2_strain' [] [] @@ -91,7 +77,7 @@ N = 2 [stress] type = ComputeLagrangianObjectiveCustomSymmetricStress custom_small_stress = 'neml2_stress' - custom_small_jacobian = 'neml2_jacobian' + custom_small_jacobian = 'dneml2_stress/dneml2_strain' [] [] @@ -103,14 +89,6 @@ N = 2 [] [] -[Postprocessors] - [time] - type = TimePostprocessor - execute_on = 'INITIAL TIMESTEP_BEGIN' - outputs = 'none' - [] -[] - [Executioner] type = Transient solve_type = NEWTON diff --git a/modules/solid_mechanics/test/tests/neml2/solve_failure/neml2.i b/modules/solid_mechanics/test/tests/neml2/solve_failure/neml2.i index 5ca5e0c0fc5d..aa354f42fbde 100644 --- a/modules/solid_mechanics/test/tests/neml2/solve_failure/neml2.i +++ b/modules/solid_mechanics/test/tests/neml2/solve_failure/neml2.i @@ -5,23 +5,24 @@ [] [mandel_stress] type = IsotropicMandelStress + cauchy_stress = 'neml2_stress' [] [overstress] type = SR2LinearCombination - to_var = 'state/internal/O' - from_var = 'state/internal/M state/internal/X' - coefficients = '1 -1' + to = 'over_stress' + from = 'mandel_stress back_stress' + weights = '1 -1' [] [vonmises] type = SR2Invariant invariant_type = 'VONMISES' - tensor = 'state/internal/O' - invariant = 'state/internal/s' + tensor = 'over_stress' + invariant = 'effective_stress' [] [yield] type = YieldFunction yield_stress = 5 - isotropic_hardening = 'state/internal/k' + isotropic_hardening = 'isotropic_hardening' [] [flow] type = ComposedModel @@ -30,12 +31,9 @@ [normality] type = Normality model = 'flow' - function = 'state/internal/fp' - from = 'state/internal/M state/internal/k' - to = 'state/internal/NM state/internal/Nk' - [] - [consistency] - type = RateIndependentPlasticFlowConstraint + function = 'yield_function' + from = 'mandel_stress isotropic_hardening' + to = 'flow_direction isotropic_hardening_direction' [] [eprate] type = AssociativeIsotropicPlasticHardening @@ -48,40 +46,47 @@ [Eprate] type = AssociativePlasticFlow [] - [Erate] + [strain_rate] type = SR2VariableRate - variable = 'forces/E' - rate = 'forces/E_rate' + variable = 'neml2_strain' [] - [Eerate] + [elastic_strain_rate] type = SR2LinearCombination - from_var = 'forces/E_rate state/internal/Ep_rate' - to_var = 'state/internal/Ee_rate' - coefficients = '1 -1' + from = 'neml2_strain_rate plastic_strain_rate' + to = 'elastic_strain_rate' + weights = '1 -1' [] [elasticity] type = LinearIsotropicElasticity coefficients = '1e5 0.3' coefficient_types = 'YOUNGS_MODULUS POISSONS_RATIO' + strain = 'elastic_strain' + stress = 'neml2_stress' rate_form = true [] [integrate_ep] type = ScalarBackwardEulerTimeIntegration - variable = 'state/internal/ep' + variable = 'equivalent_plastic_strain' [] [integrate_X] type = SR2BackwardEulerTimeIntegration - variable = 'state/internal/X' + variable = 'back_stress' [] [integrate_S] type = SR2BackwardEulerTimeIntegration - variable = 'state/S' + variable = 'neml2_stress' + [] + [consistency] + type = FBComplementarity + a = 'yield_function' + a_inequality = 'LE' + b = 'flow_rate' [] [surface] type = ComposedModel models = 'isoharden mandel_stress overstress vonmises yield normality eprate Xrate Eprate - Erate Eerate elasticity + strain_rate elastic_strain_rate elasticity consistency integrate_ep integrate_X integrate_S' [] [] @@ -90,6 +95,8 @@ [eq_sys] type = NonlinearSystem model = 'surface' + unknowns = 'equivalent_plastic_strain back_stress neml2_stress flow_rate' + residuals = 'equivalent_plastic_strain_residual back_stress_residual neml2_stress_residual complementarity' [] [] @@ -104,9 +111,15 @@ [] [Models] + [predictor] + type = ConstantExtrapolationPredictor + unknowns_Scalar = 'equivalent_plastic_strain flow_rate' + unknowns_SR2 = 'back_stress neml2_stress' + [] [model] type = ImplicitUpdate equation_system = 'eq_sys' solver = 'newton' + predictor = 'predictor' [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/viscoplasticity/chaboche.i b/modules/solid_mechanics/test/tests/neml2/viscoplasticity/chaboche.i index 3ebb12fde243..d7994bac558c 100644 --- a/modules/solid_mechanics/test/tests/neml2/viscoplasticity/chaboche.i +++ b/modules/solid_mechanics/test/tests/neml2/viscoplasticity/chaboche.i @@ -34,26 +34,7 @@ N = 2 model = 'model' verbose = true device = 'cpu' - - moose_input_types = 'MATERIAL MATERIAL POSTPROCESSOR POSTPROCESSOR MATERIAL MATERIAL MATERIAL MATERIAL' - moose_inputs = ' neml2_strain neml2_strain time time neml2_stress equivalent_plastic_strain back_stress_1 back_stress_2' - neml2_inputs = ' forces/E old_forces/E forces/t old_forces/t old_state/S old_state/internal/ep old_state/internal/X1 old_state/internal/X2' - - moose_output_types = 'MATERIAL MATERIAL MATERIAL MATERIAL' - moose_outputs = ' neml2_stress equivalent_plastic_strain back_stress_1 back_stress_2' - neml2_outputs = ' state/S state/internal/ep state/internal/X1 state/internal/X2' - - moose_derivative_types = 'MATERIAL' - moose_derivatives = 'neml2_jacobian' - neml2_derivatives = 'state/S forces/E' - [] -[] - -[Postprocessors] - [time] - type = TimePostprocessor - execute_on = 'INITIAL TIMESTEP_BEGIN' - outputs = 'none' + derivatives = 'neml2_stress neml2_strain' [] [] @@ -66,7 +47,7 @@ N = 2 [stress] type = ComputeLagrangianObjectiveCustomSymmetricStress custom_small_stress = 'neml2_stress' - custom_small_jacobian = 'neml2_jacobian' + custom_small_jacobian = 'dneml2_stress/dneml2_strain' [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/viscoplasticity/chaboche_neml2.i b/modules/solid_mechanics/test/tests/neml2/viscoplasticity/chaboche_neml2.i index d744da677b8f..4f27909e49f7 100644 --- a/modules/solid_mechanics/test/tests/neml2/viscoplasticity/chaboche_neml2.i +++ b/modules/solid_mechanics/test/tests/neml2/viscoplasticity/chaboche_neml2.i @@ -6,28 +6,30 @@ [] [kinharden] type = SR2LinearCombination - from_var = 'state/internal/X1 state/internal/X2' - to_var = 'state/internal/X' + from = 'X1 X2' + to = 'back_stress' + weights = '1 1' [] [mandel_stress] type = IsotropicMandelStress + cauchy_stress = 'neml2_stress' [] [overstress] type = SR2LinearCombination - to_var = 'state/internal/O' - from_var = 'state/internal/M state/internal/X' - coefficients = '1 -1' + to = 'overstress' + from = 'mandel_stress back_stress' + weights = '1 -1' [] [vonmises] type = SR2Invariant invariant_type = 'VONMISES' - tensor = 'state/internal/O' - invariant = 'state/internal/s' + tensor = 'overstress' + invariant = 'effective_stress' [] [yield] type = YieldFunction yield_stress = 5 - isotropic_hardening = 'state/internal/k' + isotropic_hardening = 'isotropic_hardening' [] [flow] type = ComposedModel @@ -36,9 +38,9 @@ [normality] type = Normality model = 'flow' - function = 'state/internal/fp' - from = 'state/internal/M state/internal/k' - to = 'state/internal/NM state/internal/Nk' + function = 'yield_function' + from = 'mandel_stress isotropic_hardening' + to = 'flow_direction isotropic_hardening_direction' [] [flow_rate] type = PerzynaPlasticFlowRate @@ -50,7 +52,7 @@ [] [X1rate] type = ChabochePlasticHardening - back_stress = 'state/internal/X1' + back_stress = 'X1' C = 10000 g = 100 A = 1e-8 @@ -58,7 +60,7 @@ [] [X2rate] type = ChabochePlasticHardening - back_stress = 'state/internal/X2' + back_stress = 'X2' C = 1000 g = 9 A = 1e-10 @@ -69,35 +71,37 @@ [] [Erate] type = SR2VariableRate - variable = 'forces/E' + variable = 'neml2_strain' [] [Eerate] type = SR2LinearCombination - from_var = 'forces/E_rate state/internal/Ep_rate' - to_var = 'state/internal/Ee_rate' - coefficients = '1 -1' + from = 'neml2_strain_rate plastic_strain_rate' + to = 'elastic_strain_rate' + weights = '1 -1' [] [elasticity] type = LinearIsotropicElasticity coefficients = '1e5 0.3' coefficient_types = 'YOUNGS_MODULUS POISSONS_RATIO' rate_form = true + strain = 'elastic_strain' + stress = 'neml2_stress' [] [integrate_ep] type = ScalarBackwardEulerTimeIntegration - variable = 'state/internal/ep' + variable = 'equivalent_plastic_strain' [] [integrate_X1] type = SR2BackwardEulerTimeIntegration - variable = 'state/internal/X1' + variable = 'X1' [] [integrate_X2] type = SR2BackwardEulerTimeIntegration - variable = 'state/internal/X2' + variable = 'X2' [] [integrate_stress] type = SR2BackwardEulerTimeIntegration - variable = 'state/S' + variable = 'neml2_stress' [] [implicit_rate] type = ComposedModel @@ -109,6 +113,7 @@ [eq_sys] type = NonlinearSystem model = 'implicit_rate' + unknowns = 'neml2_stress equivalent_plastic_strain X1 X2' [] [] @@ -123,9 +128,15 @@ [] [Models] + [predictor] + type = ConstantExtrapolationPredictor + unknowns_SR2 = 'neml2_stress X1 X2' + unknowns_Scalar = 'equivalent_plastic_strain' + [] [model] type = ImplicitUpdate equation_system = 'eq_sys' solver = 'newton' + predictor = 'predictor' [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/viscoplasticity/isoharden.i b/modules/solid_mechanics/test/tests/neml2/viscoplasticity/isoharden.i index fd908d1f7953..b0c9fc0e053f 100644 --- a/modules/solid_mechanics/test/tests/neml2/viscoplasticity/isoharden.i +++ b/modules/solid_mechanics/test/tests/neml2/viscoplasticity/isoharden.i @@ -34,26 +34,7 @@ N = 2 model = 'model' verbose = true device = 'cpu' - - moose_input_types = 'MATERIAL MATERIAL POSTPROCESSOR POSTPROCESSOR MATERIAL MATERIAL' - moose_inputs = ' neml2_strain neml2_strain time time neml2_stress equivalent_plastic_strain' - neml2_inputs = ' forces/E old_forces/E forces/t old_forces/t old_state/S old_state/internal/ep' - - moose_output_types = 'MATERIAL MATERIAL' - moose_outputs = ' neml2_stress equivalent_plastic_strain' - neml2_outputs = ' state/S state/internal/ep' - - moose_derivative_types = 'MATERIAL' - moose_derivatives = 'neml2_jacobian' - neml2_derivatives = 'state/S forces/E' - [] -[] - -[Postprocessors] - [time] - type = TimePostprocessor - execute_on = 'INITIAL TIMESTEP_BEGIN' - outputs = 'none' + derivatives = 'neml2_stress neml2_strain' [] [] @@ -66,7 +47,7 @@ N = 2 [stress] type = ComputeLagrangianObjectiveCustomSymmetricStress custom_small_stress = 'neml2_stress' - custom_small_jacobian = 'neml2_jacobian' + custom_small_jacobian = 'dneml2_stress/dneml2_strain' [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/viscoplasticity/isoharden_neml2.i b/modules/solid_mechanics/test/tests/neml2/viscoplasticity/isoharden_neml2.i index 339e22f6e0b6..1775f2375946 100644 --- a/modules/solid_mechanics/test/tests/neml2/viscoplasticity/isoharden_neml2.i +++ b/modules/solid_mechanics/test/tests/neml2/viscoplasticity/isoharden_neml2.i @@ -1,18 +1,13 @@ -[Solvers] - [newton] - type = Newton - [] -[] - [Models] [mandel_stress] type = IsotropicMandelStress + cauchy_stress = 'neml2_stress' [] [vonmises] type = SR2Invariant invariant_type = 'VONMISES' - tensor = 'state/internal/M' - invariant = 'state/internal/s' + tensor = 'mandel_stress' + invariant = 'effective_stress' [] [isoharden] type = LinearIsotropicHardening @@ -21,7 +16,7 @@ [yield] type = YieldFunction yield_stress = 5 - isotropic_hardening = 'state/internal/k' + isotropic_hardening = 'isotropic_hardening' [] [flow] type = ComposedModel @@ -30,9 +25,9 @@ [normality] type = Normality model = 'flow' - function = 'state/internal/fp' - from = 'state/internal/M state/internal/k' - to = 'state/internal/NM state/internal/Nk' + function = 'yield_function' + from = 'mandel_stress isotropic_hardening' + to = 'flow_direction isotropic_hardening_direction' [] [flow_rate] type = PerzynaPlasticFlowRate @@ -47,27 +42,29 @@ [] [Erate] type = SR2VariableRate - variable = 'forces/E' + variable = 'neml2_strain' [] [Eerate] type = SR2LinearCombination - from_var = 'forces/E_rate state/internal/Ep_rate' - to_var = 'state/internal/Ee_rate' - coefficients = '1 -1' + from = 'neml2_strain_rate plastic_strain_rate' + to = 'elastic_strain_rate' + weights = '1 -1' [] [elasticity] type = LinearIsotropicElasticity coefficients = '1e5 0.3' coefficient_types = 'YOUNGS_MODULUS POISSONS_RATIO' rate_form = true + strain = 'elastic_strain' + stress = 'neml2_stress' [] [integrate_stress] type = SR2BackwardEulerTimeIntegration - variable = 'state/S' + variable = 'neml2_stress' [] [integrate_ep] type = ScalarBackwardEulerTimeIntegration - variable = 'state/internal/ep' + variable = 'equivalent_plastic_strain' [] [implicit_rate] type = ComposedModel @@ -79,6 +76,7 @@ [eq_sys] type = NonlinearSystem model = 'implicit_rate' + unknowns = 'neml2_stress equivalent_plastic_strain' [] [] @@ -93,9 +91,15 @@ [] [Models] + [predictor] + type = ConstantExtrapolationPredictor + unknowns_SR2 = 'neml2_stress' + unknowns_Scalar = 'equivalent_plastic_strain' + [] [model] type = ImplicitUpdate equation_system = 'eq_sys' solver = 'newton' + predictor = 'predictor' [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/viscoplasticity/isokinharden.i b/modules/solid_mechanics/test/tests/neml2/viscoplasticity/isokinharden.i index 04b15833a3d9..e91367620ad7 100644 --- a/modules/solid_mechanics/test/tests/neml2/viscoplasticity/isokinharden.i +++ b/modules/solid_mechanics/test/tests/neml2/viscoplasticity/isokinharden.i @@ -34,26 +34,7 @@ N = 2 model = 'model' verbose = true device = 'cpu' - - moose_input_types = 'MATERIAL MATERIAL POSTPROCESSOR POSTPROCESSOR MATERIAL MATERIAL MATERIAL' - moose_inputs = ' neml2_strain neml2_strain time time neml2_stress equivalent_plastic_strain kinematic_plastic_strain' - neml2_inputs = ' forces/E old_forces/E forces/t old_forces/t old_state/S old_state/internal/ep old_state/internal/Kp' - - moose_output_types = 'MATERIAL MATERIAL MATERIAL' - moose_outputs = ' neml2_stress equivalent_plastic_strain kinematic_plastic_strain' - neml2_outputs = ' state/S state/internal/ep state/internal/Kp' - - moose_derivative_types = 'MATERIAL' - moose_derivatives = 'neml2_jacobian' - neml2_derivatives = 'state/S forces/E' - [] -[] - -[Postprocessors] - [time] - type = TimePostprocessor - execute_on = 'INITIAL TIMESTEP_BEGIN' - outputs = 'none' + derivatives = 'neml2_stress neml2_strain' [] [] @@ -66,7 +47,7 @@ N = 2 [stress] type = ComputeLagrangianObjectiveCustomSymmetricStress custom_small_stress = 'neml2_stress' - custom_small_jacobian = 'neml2_jacobian' + custom_small_jacobian = 'dneml2_stress/dneml2_strain' [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/viscoplasticity/isokinharden_neml2.i b/modules/solid_mechanics/test/tests/neml2/viscoplasticity/isokinharden_neml2.i index 95f6366cb9f9..485509577f73 100644 --- a/modules/solid_mechanics/test/tests/neml2/viscoplasticity/isokinharden_neml2.i +++ b/modules/solid_mechanics/test/tests/neml2/viscoplasticity/isokinharden_neml2.i @@ -9,23 +9,24 @@ [] [mandel_stress] type = IsotropicMandelStress + cauchy_stress = 'neml2_stress' [] [overstress] type = SR2LinearCombination - to_var = 'state/internal/O' - from_var = 'state/internal/M state/internal/X' - coefficients = '1 -1' + to = 'over_stress' + from = 'mandel_stress back_stress' + weights = '1 -1' [] [vonmises] type = SR2Invariant invariant_type = 'VONMISES' - tensor = 'state/internal/O' - invariant = 'state/internal/s' + tensor = 'over_stress' + invariant = 'effective_stress' [] [yield] type = YieldFunction yield_stress = 5 - isotropic_hardening = 'state/internal/k' + isotropic_hardening = 'isotropic_hardening' [] [flow] type = ComposedModel @@ -34,9 +35,9 @@ [normality] type = Normality model = 'flow' - function = 'state/internal/fp' - from = 'state/internal/M state/internal/k state/internal/X' - to = 'state/internal/NM state/internal/Nk state/internal/NX' + function = 'yield_function' + from = 'mandel_stress isotropic_hardening back_stress' + to = 'flow_direction isotropic_hardening_direction kinematic_hardening_direction' [] [flow_rate] type = PerzynaPlasticFlowRate @@ -54,31 +55,33 @@ [] [Erate] type = SR2VariableRate - variable = 'forces/E' + variable = 'neml2_strain' [] [Eerate] type = SR2LinearCombination - from_var = 'forces/E_rate state/internal/Ep_rate' - to_var = 'state/internal/Ee_rate' - coefficients = '1 -1' + from = 'neml2_strain_rate plastic_strain_rate' + to = 'elastic_strain_rate' + weights = '1 -1' [] [elasticity] type = LinearIsotropicElasticity coefficients = '1e5 0.3' coefficient_types = 'YOUNGS_MODULUS POISSONS_RATIO' rate_form = true + strain = 'elastic_strain' + stress = 'neml2_stress' [] [integrate_ep] type = ScalarBackwardEulerTimeIntegration - variable = 'state/internal/ep' + variable = 'equivalent_plastic_strain' [] [integrate_Kp] type = SR2BackwardEulerTimeIntegration - variable = 'state/internal/Kp' + variable = 'kinematic_plastic_strain' [] [integrate_stress] type = SR2BackwardEulerTimeIntegration - variable = 'state/S' + variable = 'neml2_stress' [] [implicit_rate] type = ComposedModel @@ -90,6 +93,7 @@ [eq_sys] type = NonlinearSystem model = 'implicit_rate' + unknowns = 'neml2_stress equivalent_plastic_strain kinematic_plastic_strain' [] [] @@ -104,9 +108,15 @@ [] [Models] + [predictor] + type = ConstantExtrapolationPredictor + unknowns_SR2 = 'neml2_stress kinematic_plastic_strain' + unknowns_Scalar = 'equivalent_plastic_strain' + [] [model] type = ImplicitUpdate equation_system = 'eq_sys' solver = 'newton' + predictor = 'predictor' [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/viscoplasticity/kinharden.i b/modules/solid_mechanics/test/tests/neml2/viscoplasticity/kinharden.i index 6a262aaa3e30..5f784540f726 100644 --- a/modules/solid_mechanics/test/tests/neml2/viscoplasticity/kinharden.i +++ b/modules/solid_mechanics/test/tests/neml2/viscoplasticity/kinharden.i @@ -34,26 +34,7 @@ N = 2 model = 'model' verbose = true device = 'cpu' - - moose_input_types = 'MATERIAL MATERIAL POSTPROCESSOR POSTPROCESSOR MATERIAL MATERIAL' - moose_inputs = ' neml2_strain neml2_strain time time neml2_stress kinematic_plastic_strain' - neml2_inputs = ' forces/E old_forces/E forces/t old_forces/t old_state/S old_state/internal/Kp' - - moose_output_types = 'MATERIAL MATERIAL' - moose_outputs = ' neml2_stress kinematic_plastic_strain' - neml2_outputs = ' state/S state/internal/Kp' - - moose_derivative_types = 'MATERIAL' - moose_derivatives = 'neml2_jacobian' - neml2_derivatives = 'state/S forces/E' - [] -[] - -[Postprocessors] - [time] - type = TimePostprocessor - execute_on = 'INITIAL TIMESTEP_BEGIN' - outputs = 'none' + derivatives = 'neml2_stress neml2_strain' [] [] @@ -66,7 +47,7 @@ N = 2 [stress] type = ComputeLagrangianObjectiveCustomSymmetricStress custom_small_stress = 'neml2_stress' - custom_small_jacobian = 'neml2_jacobian' + custom_small_jacobian = 'dneml2_stress/dneml2_strain' [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/viscoplasticity/kinharden_neml2.i b/modules/solid_mechanics/test/tests/neml2/viscoplasticity/kinharden_neml2.i index 6544805f3916..e107837506f4 100644 --- a/modules/solid_mechanics/test/tests/neml2/viscoplasticity/kinharden_neml2.i +++ b/modules/solid_mechanics/test/tests/neml2/viscoplasticity/kinharden_neml2.i @@ -5,18 +5,19 @@ [] [mandel_stress] type = IsotropicMandelStress + cauchy_stress = 'neml2_stress' [] [overstress] type = SR2LinearCombination - to_var = 'state/internal/O' - from_var = 'state/internal/M state/internal/X' - coefficients = '1 -1' + to = 'over_stress' + from = 'mandel_stress back_stress' + weights = '1 -1' [] [vonmises] type = SR2Invariant invariant_type = 'VONMISES' - tensor = 'state/internal/O' - invariant = 'state/internal/s' + tensor = 'over_stress' + invariant = 'effective_stress' [] [yield] type = YieldFunction @@ -29,9 +30,9 @@ [normality] type = Normality model = 'flow' - function = 'state/internal/fp' - from = 'state/internal/M state/internal/X' - to = 'state/internal/NM state/internal/NX' + function = 'yield_function' + from = 'mandel_stress back_stress' + to = 'flow_direction kinematic_hardening_direction' [] [flow_rate] type = PerzynaPlasticFlowRate @@ -46,27 +47,29 @@ [] [Erate] type = SR2VariableRate - variable = 'forces/E' + variable = 'neml2_strain' [] [Eerate] type = SR2LinearCombination - from_var = 'forces/E_rate state/internal/Ep_rate' - to_var = 'state/internal/Ee_rate' - coefficients = '1 -1' + from = 'neml2_strain_rate plastic_strain_rate' + to = 'elastic_strain_rate' + weights = '1 -1' [] [elasticity] type = LinearIsotropicElasticity coefficients = '1e5 0.3' coefficient_types = 'YOUNGS_MODULUS POISSONS_RATIO' rate_form = true + strain = 'elastic_strain' + stress = 'neml2_stress' [] [integrate_Kp] type = SR2BackwardEulerTimeIntegration - variable = 'state/internal/Kp' + variable = 'kinematic_plastic_strain' [] [integrate_stress] type = SR2BackwardEulerTimeIntegration - variable = 'state/S' + variable = 'neml2_stress' [] [implicit_rate] type = ComposedModel @@ -78,6 +81,7 @@ [eq_sys] type = NonlinearSystem model = 'implicit_rate' + unknowns = 'neml2_stress kinematic_plastic_strain' [] [] @@ -92,9 +96,14 @@ [] [Models] + [predictor] + type = ConstantExtrapolationPredictor + unknowns_SR2 = 'neml2_stress kinematic_plastic_strain' + [] [model] type = ImplicitUpdate equation_system = 'eq_sys' solver = 'newton' + predictor = 'predictor' [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/viscoplasticity/perfect.i b/modules/solid_mechanics/test/tests/neml2/viscoplasticity/perfect.i index f2a828fbce08..a584d55950ed 100644 --- a/modules/solid_mechanics/test/tests/neml2/viscoplasticity/perfect.i +++ b/modules/solid_mechanics/test/tests/neml2/viscoplasticity/perfect.i @@ -34,26 +34,7 @@ N = 2 model = 'model' verbose = true device = 'cpu' - - moose_input_types = 'MATERIAL MATERIAL POSTPROCESSOR POSTPROCESSOR MATERIAL' - moose_inputs = ' neml2_strain neml2_strain time time neml2_stress' - neml2_inputs = ' forces/E old_forces/E forces/t old_forces/t old_state/S' - - moose_output_types = 'MATERIAL' - moose_outputs = ' neml2_stress' - neml2_outputs = ' state/S' - - moose_derivative_types = 'MATERIAL' - moose_derivatives = 'neml2_jacobian' - neml2_derivatives = 'state/S forces/E' - [] -[] - -[Postprocessors] - [time] - type = TimePostprocessor - execute_on = 'INITIAL TIMESTEP_BEGIN' - outputs = 'none' + derivatives = 'neml2_stress neml2_strain' [] [] @@ -66,7 +47,7 @@ N = 2 [stress] type = ComputeLagrangianObjectiveCustomSymmetricStress custom_small_stress = 'neml2_stress' - custom_small_jacobian = 'neml2_jacobian' + custom_small_jacobian = 'dneml2_stress/dneml2_strain' [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/viscoplasticity/perfect_neml2.i b/modules/solid_mechanics/test/tests/neml2/viscoplasticity/perfect_neml2.i index 1acec7004e76..0b4fe097a770 100644 --- a/modules/solid_mechanics/test/tests/neml2/viscoplasticity/perfect_neml2.i +++ b/modules/solid_mechanics/test/tests/neml2/viscoplasticity/perfect_neml2.i @@ -1,12 +1,13 @@ [Models] [mandel_stress] type = IsotropicMandelStress + cauchy_stress = 'neml2_stress' [] [vonmises] type = SR2Invariant invariant_type = 'VONMISES' - tensor = 'state/internal/M' - invariant = 'state/internal/s' + tensor = 'mandel_stress' + invariant = 'effective_stress' [] [yield] type = YieldFunction @@ -19,9 +20,9 @@ [normality] type = Normality model = 'flow' - function = 'state/internal/fp' - from = 'state/internal/M' - to = 'state/internal/NM' + function = 'yield_function' + from = 'mandel_stress' + to = 'flow_direction' [] [flow_rate] type = PerzynaPlasticFlowRate @@ -33,23 +34,25 @@ [] [Erate] type = SR2VariableRate - variable = 'forces/E' + variable = 'neml2_strain' [] [Eerate] type = SR2LinearCombination - from_var = 'forces/E_rate state/internal/Ep_rate' - to_var = 'state/internal/Ee_rate' - coefficients = '1 -1' + from = 'neml2_strain_rate plastic_strain_rate' + to = 'elastic_strain_rate' + weights = '1 -1' [] [elasticity] type = LinearIsotropicElasticity coefficients = '1e5 0.3' coefficient_types = 'YOUNGS_MODULUS POISSONS_RATIO' rate_form = true + strain = 'elastic_strain' + stress = 'neml2_stress' [] [integrate_stress] type = SR2BackwardEulerTimeIntegration - variable = 'state/S' + variable = 'neml2_stress' [] [implicit_rate] type = ComposedModel @@ -61,6 +64,7 @@ [eq_sys] type = NonlinearSystem model = 'implicit_rate' + unknowns = 'neml2_stress' [] [] @@ -75,9 +79,14 @@ [] [Models] + [predictor] + type = ConstantExtrapolationPredictor + unknowns_SR2 = 'neml2_stress' + [] [model] type = ImplicitUpdate equation_system = 'eq_sys' solver = 'newton' + predictor = 'predictor' [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/viscoplasticity/radial_return.i b/modules/solid_mechanics/test/tests/neml2/viscoplasticity/radial_return.i index 256f0887c7f2..d4e965a56a4d 100644 --- a/modules/solid_mechanics/test/tests/neml2/viscoplasticity/radial_return.i +++ b/modules/solid_mechanics/test/tests/neml2/viscoplasticity/radial_return.i @@ -34,26 +34,7 @@ N = 2 model = 'model' verbose = true device = 'cpu' - - moose_input_types = 'MATERIAL POSTPROCESSOR POSTPROCESSOR MATERIAL MATERIAL' - moose_inputs = ' neml2_strain time time plastic_strain consistency' - neml2_inputs = ' forces/E forces/t old_forces/t old_state/internal/Ep old_state/internal/gamma' - - moose_output_types = 'MATERIAL MATERIAL MATERIAL' - moose_outputs = ' neml2_stress plastic_strain consistency' - neml2_outputs = ' state/S state/internal/Ep state/internal/gamma' - - moose_derivative_types = 'MATERIAL' - moose_derivatives = 'neml2_jacobian' - neml2_derivatives = 'state/S forces/E' - [] -[] - -[Postprocessors] - [time] - type = TimePostprocessor - execute_on = 'INITIAL TIMESTEP_BEGIN' - outputs = 'none' + derivatives = 'neml2_stress neml2_strain' [] [] @@ -66,7 +47,7 @@ N = 2 [stress] type = ComputeLagrangianObjectiveCustomSymmetricStress custom_small_stress = 'neml2_stress' - custom_small_jacobian = 'neml2_jacobian' + custom_small_jacobian = 'dneml2_stress/dneml2_strain' [] [] diff --git a/modules/solid_mechanics/test/tests/neml2/viscoplasticity/radial_return_neml2.i b/modules/solid_mechanics/test/tests/neml2/viscoplasticity/radial_return_neml2.i index 7fb2b622e4ca..20ed20cd90bb 100644 --- a/modules/solid_mechanics/test/tests/neml2/viscoplasticity/radial_return_neml2.i +++ b/modules/solid_mechanics/test/tests/neml2/viscoplasticity/radial_return_neml2.i @@ -5,108 +5,83 @@ ############################################################################### [trial_elastic_strain] type = SR2LinearCombination - from_var = 'forces/E old_state/internal/Ep' - to_var = 'forces/Ee_trial' - coefficients = '1 -1' + from = 'neml2_strain plastic_strain~1' + to = 'elastic_strain' + weights = '1 -1' [] - [trial_cauchy_stress] + [elasticity] type = LinearIsotropicElasticity coefficients = '1e5 0.3' coefficient_types = 'YOUNGS_MODULUS POISSONS_RATIO' - strain = 'forces/Ee_trial' - stress = 'forces/S_trial' + strain = 'elastic_strain' + stress = 'neml2_stress' [] - [trial_mandel_stress] + [mandel_stress] type = IsotropicMandelStress - cauchy_stress = 'forces/S_trial' - mandel_stress = 'forces/M_trial' + cauchy_stress = 'neml2_stress' [] - [trial_vonmises] + [vonmises] type = SR2Invariant invariant_type = 'VONMISES' - tensor = 'forces/M_trial' - invariant = 'forces/s_trial' + tensor = 'mandel_stress' + invariant = 'effective_stress' [] - [trial_yield] + [yield] type = YieldFunction yield_stress = 100 - yield_function = 'forces/fp_trial' - effective_stress = 'forces/s_trial' [] - [trial_flow] + [flow] type = ComposedModel - models = 'trial_vonmises trial_yield' + models = 'vonmises yield' [] - [trial_normality] + [normality] type = Normality - model = 'trial_flow' - function = 'forces/fp_trial' - from = 'forces/M_trial' - to = 'forces/NM' + model = 'flow' + function = 'yield_function' + from = 'mandel_stress' + to = 'flow_direction' [] [trial_state] type = ComposedModel - models = 'trial_elastic_strain trial_cauchy_stress trial_mandel_stress trial_normality' + models = 'trial_elastic_strain elasticity mandel_stress normality' [] ############################################################################### # The actual radial return: # Since the flow directions are invariant, we only need to integrate # the consistency parameter. ############################################################################### - [trial_flow_rate] - type = ScalarVariableRate - variable = 'state/internal/gamma' - [] [plastic_strain_rate] type = AssociativePlasticFlow - flow_direction = 'forces/NM' + flow_rate = 'gamma_rate' [] [plastic_strain] type = SR2ForwardEulerTimeIntegration - variable = 'state/internal/Ep' + variable = 'plastic_strain' [] [elastic_strain] type = SR2LinearCombination - from_var = 'forces/E state/internal/Ep' - to_var = 'state/internal/Ee' - coefficients = '1 -1' - [] - [cauchy_stress] - type = LinearIsotropicElasticity - coefficients = '1e5 0.3' - coefficient_types = 'YOUNGS_MODULUS POISSONS_RATIO' - [] - [mandel_stress] - type = IsotropicMandelStress - [] - [vonmises] - type = SR2Invariant - invariant_type = 'VONMISES' - tensor = 'state/internal/M' - invariant = 'state/internal/s' - [] - [yield] - type = YieldFunction - yield_stress = 100 + from = 'neml2_strain plastic_strain' + to = 'elastic_strain' + weights = '1 -1' [] [surface] type = ComposedModel - models = "trial_flow_rate - plastic_strain_rate plastic_strain elastic_strain cauchy_stress mandel_stress - vonmises yield" + models = 'plastic_strain_rate plastic_strain elastic_strain elasticity mandel_stress vonmises yield' [] [flow_rate] type = PerzynaPlasticFlowRate reference_stress = 1 exponent = 2 [] - [integrate_gamma] - type = ScalarBackwardEulerTimeIntegration - variable = 'state/internal/gamma' + [gamma_residual] + type = ScalarLinearCombination + from = 'gamma_rate flow_rate' + to = 'gamma_residual' + weights = '1 -1' [] [implicit_rate] type = ComposedModel - models = 'surface flow_rate integrate_gamma' + models = 'surface flow_rate gamma_residual' [] [] @@ -114,6 +89,8 @@ [eq_sys] type = NonlinearSystem model = 'implicit_rate' + unknowns = 'gamma_rate' + residuals = 'gamma_residual' [] [] @@ -128,20 +105,24 @@ [] [Models] + [predictor] + type = ConstantExtrapolationPredictor + unknowns_Scalar = 'gamma_rate' + [] [return_map] type = ImplicitUpdate equation_system = 'eq_sys' solver = 'newton' + predictor = 'predictor' [] [model0] type = ComposedModel - models = "trial_state return_map trial_flow_rate - plastic_strain_rate plastic_strain" - additional_outputs = 'state/internal/gamma' + models = 'trial_state return_map plastic_strain_rate plastic_strain' + additional_outputs = 'gamma_rate' [] [model] type = ComposedModel - models = 'model0 elastic_strain cauchy_stress' - additional_outputs = 'state/internal/Ep' + models = 'model0 elastic_strain elasticity' + additional_outputs = 'plastic_strain' [] [] diff --git a/scripts/configure_libtorch.sh b/scripts/configure_libtorch.sh new file mode 100644 index 000000000000..cc5d20789d3a --- /dev/null +++ b/scripts/configure_libtorch.sh @@ -0,0 +1,125 @@ +#!/usr/bin/env bash +#* This file is part of the MOOSE framework +#* https://www.mooseframework.org +#* +#* All rights reserved, see COPYRIGHT for full restrictions +#* https://github.com/idaholab/moose/blob/master/COPYRIGHT +#* +#* Licensed under LGPL 2.1, please see LICENSE for details +#* https://www.gnu.org/licenses/lgpl-2.1.html + +function get_variable() +{ + if [ -z "${!1}" ]; then + >&2 echo "ERROR: Missing required variable $1" + fi + echo "${!1}" +} + +function underlying_compiler() { + local c="$1" + + if "$c" --showme:command >/dev/null 2>&1; then + "$c" --showme:command + elif "$c" -show >/dev/null 2>&1; then + "$c" -show | awk '{print $1}' + elif "$c" -compile-info >/dev/null 2>&1; then + "$c" -compile-info | awk '{print $1}' + else + echo "$c" + fi +} + +# Configure libtorch with the default MOOSE configuration options +# +# Separated so that it can be used across all libtorch build scripts: +# - scripts/update_and_rebuild_libtorch.sh +# +# Arguments: +# 1. Path to the libtorch source directory +# 2. Path to the libtorch build directory +# 3. Path to the libtorch installation directory +# +# Remaining arguments will be appended to the cmake command verbatim +function configure_libtorch() +{ + ARGS=() + if which ninja &> /dev/null; then + ARGS+=("-GNinja") + fi + ARGS+=("${@:4}") + # Documenting the flag choices: + # -DCMAKE_INCLUDE_PATH and -DCMAKE_LIBRARY_PATH are needed to find the PETSc installation, + # which is needed to make sure BLAS and LAPACK are compatible with PETSc and vice versa. + # -DBUILD_PYTHON=OFF, -DBUILD_TEST=OFF, -DBUILD_BINARY=OFF, and -DBUILD_LITE_INTERPRETER=OFF + # are needed to avoid building unnecessary targets that we don't need. + # -DBUILD_FUNCTORCH=OFF, -DUSE_GLOO=OFF, -DUSE_NCCL=OFF, -DUSE_XCCL=OFF, and -DUSE_TENSORPIPE=OFF + # are needed to avoid building distributed training support, which we don't need. + # -DUSE_MPI=OFF and -DUSE_DISTRIBUTED=OFF are needed to avoid building MPI support, which we don't need. + # -DUSE_MAGMA=ON is needed to enable MAGMA support, which we want for GPU support on linear algebra operations on large matrices. + # -DUSE_MKLDNN=OFF, -DUSE_NNPACK=OFF, -DUSE_XNNPACK=OFF, and -DUSE_PYTORCH_QNNPACK=OFF are + # needed to avoid building support for various CPU acceleration libraries that we don't need. + # -DUSE_KINETO=OFF: we don't need Kineto because we don't use PyTorch's profiler + # -DUSE_FBGEMM=OFF: we don't need FBGEMM because we don't use quantization + # -DUSE_NUMPY=OFF: we don't need NumPy support because we don't use PyTorch's C++ API for Python bindings + # -DUSE_ITT=OFF: we don't need ITT support because we don't use PyTorch's profiler + # -DUSE_VALGRIND=OFF: we don't need Valgrind support because we don't use PyTorch's C++ API for Python bindings + # and we don't use PyTorch's profiler + # -DUSE_OBSERVERS=OFF: we don't need observers support because we don't use PyTorch's profiler + cmake \ + -DCMAKE_C_COMPILER="$(underlying_compiler "${CC:-cc}")" \ + -DCMAKE_CXX_COMPILER="$(underlying_compiler "${CXX:-c++}")" \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX="$3" \ + -DBUILD_PYTHON=OFF \ + -DBUILD_TEST=OFF \ + -DBUILD_BINARY=OFF \ + -DBUILD_LITE_INTERPRETER=OFF \ + -DBUILD_FUNCTORCH=OFF \ + -DUSE_GLOO=OFF \ + -DUSE_NCCL=OFF \ + -DUSE_XCCL=OFF \ + -DUSE_TENSORPIPE=OFF \ + -DCMAKE_INCLUDE_PATH="$(get_variable PETSC_DIR)/include" \ + -DCMAKE_LIBRARY_PATH="$(get_variable PETSC_DIR)/lib" \ + -DUSE_BLAS=ON \ + -DBLAS=OpenBLAS \ + -DUSE_LAPACK=ON \ + -DUSE_MPI=OFF \ + -DUSE_DISTRIBUTED=OFF \ + -DUSE_MAGMA=ON \ + -DUSE_MKLDNN=OFF \ + -DUSE_NNPACK=OFF \ + -DUSE_XNNPACK=OFF \ + -DUSE_PYTORCH_QNNPACK=OFF \ + -DBUILD_TEST=OFF \ + -DUSE_KINETO=OFF \ + -DUSE_FBGEMM=OFF \ + -DUSE_NUMPY=OFF \ + -DUSE_ITT=OFF \ + -DUSE_VALGRIND=OFF \ + -DUSE_OBSERVERS=OFF \ + -B "$2" \ + -S "$1" \ + "${ARGS[@]}" +} + +# Build libtorch assuming that the project has already been configured +# +# Arguments: +# 1. Path to the libtorch build directory +# 2. Number of jobs to use when building libtorch +function build_libtorch() +{ + cmake --build "$1" --parallel "$2" --target all +} + +# Install libtorch +# +# Arguments: +# 1. Path to the libtorch build directory +# 2. Install prefix +function install_libtorch() +{ + cmake --install "$1" --prefix "$2" +} diff --git a/scripts/configure_neml2.sh b/scripts/configure_neml2.sh index acd19676a5b0..f8ba3677c41d 100644 --- a/scripts/configure_neml2.sh +++ b/scripts/configure_neml2.sh @@ -19,7 +19,7 @@ function get_variable() # Configure NEML2 with the default MOOSE configuration options # # Separated so that it can be used across all NEML2 build scripts: -# - scripts/update_and_rebuild_wasp.sh +# - scripts/update_and_rebuild_neml2.sh # # Arguments: # 1. Path to the NEML2 source directory @@ -43,7 +43,7 @@ function configure_neml2() -DNEML2_JSON=OFF \ -DNEML2_CONTRIB_PREFIX="$2/contrib" \ -Dtorch_ROOT="$(get_variable LIBTORCH_DIR)" \ - -Dwasp_ROOT="$(get_variable WASP_DIR)" \ + -Dtorch_SEARCH_SITE_PACKAGES=OFF \ -G "Unix Makefiles" \ -B "$2" \ -S "$1" \ diff --git a/scripts/tests/versioner_hashes.yaml b/scripts/tests/versioner_hashes.yaml index d3a73b016bf9..ae43b1c2b74d 100644 --- a/scripts/tests/versioner_hashes.yaml +++ b/scripts/tests/versioner_hashes.yaml @@ -1764,3 +1764,37 @@ d41b47a41b7edac3875e308fb77df6069de32269: # 32404 wasp: full_version: 2025.09.19_02960f1_5 hash: 9ce59ea +45c4fccd0981fdb6e9b6c3705ae934db4e2a3fc7: #32871 + build: + full_version: 2026.04.21 + hash: ae2c988 + libmesh: + full_version: 2026.04.13_0185b8b_0 + hash: b73472f + libmesh-vtk: + full_version: 9.6.1_0 + hash: de4f8ad + moose-dev: + full_version: 2026.05.06 + hash: b9fd13d + mpi: + full_version: 2026.04.21 + hash: f6f315e + petsc: + full_version: 3.24.6_0 + hash: 2fee174 + pprof: + full_version: 2026.03.01_a15ffb7 + hash: '4869696' + pyhit: + full_version: 2026.04.21 + hash: 1528d6d + seacas: + full_version: 2025.10.14_3 + hash: 2115cf6 + tools: + full_version: 2026.04.21 + hash: eef89ae + wasp: + full_version: 2025.09.19_02960f1_6 + hash: 4b8a7ec diff --git a/scripts/update_and_rebuild_libtorch.sh b/scripts/update_and_rebuild_libtorch.sh new file mode 100755 index 000000000000..fe29abcf05b9 --- /dev/null +++ b/scripts/update_and_rebuild_libtorch.sh @@ -0,0 +1,190 @@ +#!/usr/bin/env bash +#* This file is part of the MOOSE framework +#* https://www.mooseframework.org +#* +#* All rights reserved, see COPYRIGHT for full restrictions +#* https://github.com/idaholab/moose/blob/master/COPYRIGHT +#* +#* Licensed under LGPL 2.1, please see LICENSE for details +#* https://www.gnu.org/licenses/lgpl-2.1.html + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +MOOSE_DIR="$( cd "$( dirname "${SCRIPT_DIR}" )" && pwd )" + +# Display the help message if requested +if [[ "$#" -eq 1 ]] && [[ "$1" == "--help" ]]; then + SCRIPT_NAME=$(basename "$0") + echo "Usage: ${SCRIPT_NAME} --help" + echo "Usage: ${SCRIPT_NAME} [--fast|--skip-submodule-update] [ADDITIONAL_CONFIGURE_ARG ...]" + echo + echo "This script makes libtorch available to the MOOSE framework. The script " + echo "performs the following steps:" + echo " 1. Update the libtorch submodule" + echo " 2. Clean and recreate the build directory" + echo " 3. Configure libtorch" + echo " 4. Build libtorch" + echo " 5. Install libtorch" + echo + echo + echo "Influential environment variables:" + echo " MOOSE_DIR The path to the MOOSE directory. Default to the parent directory of this script." + echo " PETSC_DIR The path to the PETSc installation directory. Default to env:PETSC_DIR or " + echo " /petsc/arch-moose." + echo " LIBTORCH_SRC_DIR The path to the libtorch source directory if a custom libtorch should be used. If set, " + echo " --skip-submodule-update will be assumed." + echo " LIBTORCH_DIR The path to the libtorch installation directory. Default to " + echo " /framework/contrib/libtorch/installed." + echo " LIBTORCH_JOBS The number of jobs to use when building libtorch. Default to . " + echo " If unset, default to 1." + echo + echo "For Intel GPU support, please explicitly `export USE_XPU=1` before running the script." + echo + echo "General environment variables supported by CMake are also respected." + echo + echo "Command-line arguments:" + echo " --help Display this message and exit" + echo " --fast Skip the update, clean, and configure steps (steps 1-3)" + echo " --skip-submodule-update Skip the update step (step 1)" + echo " ADDITIONAL_CONFIGURE_ARG Additional argument(s) to pass to the libtorch cmake configure command" + exit 0 +fi + +# Handle cliargs +FAST=false +SKIP_SUBMODULE_UPDATE=false +for ARG in "$@" ; do + if [[ "${ARG}" == "--fast" ]]; then + FAST=true + elif [[ "${ARG}" == "--skip-submodule-update" ]]; then + SKIP_SUBMODULE_UPDATE=true + else + EXTRA_ARGS+=("$ARG") + fi +done + +# Handle environment variables +if [[ -n "$LIBTORCH_SRC_DIR" ]]; then + SKIP_SUBMODULE_UPDATE=true +else + LIBTORCH_SRC_DIR=${MOOSE_DIR}/framework/contrib/pytorch +fi +LIBTORCH_DIR=${LIBTORCH_DIR:-${LIBTORCH_SRC_DIR}/installed} + +if [[ -z "$LIBTORCH_JOBS" ]]; then + if [[ -n "$MOOSE_JOBS" ]]; then + LIBTORCH_JOBS=$MOOSE_JOBS + else + LIBTORCH_JOBS=1 + fi +fi + +# Dependency: petsc +export PETSC_DIR=${PETSC_DIR:-${MOOSE_DIR}/petsc/arch-moose} + +# Print out the configuration summary if requested +SCRIPT_NAME=$(basename "$0") +echo "****************************************************************************************************" +echo "${SCRIPT_NAME} summary:" +echo " MOOSE_DIR: ${MOOSE_DIR}" +echo " PETSC_DIR: ${PETSC_DIR}" +echo " LIBTORCH_DIR: ${LIBTORCH_DIR}" +echo " LIBTORCH_SRC_DIR: ${LIBTORCH_SRC_DIR}" +echo " LIBTORCH_JOBS: ${LIBTORCH_JOBS}" +echo " FAST: ${FAST}" +echo " SKIP_SUBMODULE_UPDATE: ${SKIP_SUBMODULE_UPDATE}" +echo " ADDITIONAL_CONFIGURE_ARGS: ${EXTRA_ARGS[*]}" +echo "****************************************************************************************************" + + +# Check that dependencies are available +if [[ ! -d "${PETSC_DIR}" ]]; then + echo "Error: The PETSc directory (${PETSC_DIR}) does not exist. Please see --help for more information." + exit 1 +fi + +# Step 1: Update the LIBTORCH submodule +if [[ "$SKIP_SUBMODULE_UPDATE" != true ]] && [[ "$FAST" != true ]]; then + cd "$MOOSE_DIR" || exit + git submodule update --init --checkout --recursive "${LIBTORCH_SRC_DIR}" + if [[ $? -ne 0 ]] ; then + echo "Error: Failed to update the libtorch submodule with command" + echo " git submodule update --init --checkout --recursive ${LIBTORCH_SRC_DIR}" + exit 1 + fi +fi + +# Build and install directories +LIBTORCH_BUILD_DIR=${LIBTORCH_SRC_DIR}/build + +# If we are going fast, the build directory must already exist +if [[ "${FAST}" == true ]] && [[ ! -d "${LIBTORCH_BUILD_DIR}" ]] ; then + echo "Error: A build directory (${LIBTORCH_BUILD_DIR}) must exist to use the --fast option" + exit 1 +fi + +# Step 2: Clean and recreate the build directory +if [[ "${FAST}" != true ]] ; then + rm -rf "${LIBTORCH_BUILD_DIR}" + mkdir -p "${LIBTORCH_BUILD_DIR}" +fi + +# Step 3: Configure +# shellcheck disable=SC1091 +source "$SCRIPT_DIR/configure_libtorch.sh" +if [[ "${FAST}" != true ]] ; then + echo + echo "****************************************************************************************************" + echo "Configuring libtorch" + echo "****************************************************************************************************" + echo + configure_libtorch "${LIBTORCH_SRC_DIR}" \ + "${LIBTORCH_BUILD_DIR}" \ + "${LIBTORCH_DIR}" \ + "${EXTRA_ARGS[@]}" + # shellcheck disable=SC2181 + if [[ $? -ne 0 ]] ; then + echo "Error: Failed to configure libtorch" + exit 1 + fi +fi + +# Step 4: Build +echo +echo "****************************************************************************************************" +echo "Compiling libtorch" +echo "****************************************************************************************************" +echo +build_libtorch "${LIBTORCH_BUILD_DIR}" "${LIBTORCH_JOBS}" +# shellcheck disable=SC2181 +if [[ $? -ne 0 ]] ; then + echo "Error: Failed to build libtorch" + exit 1 +fi + +# Step 5: Install +echo +echo "****************************************************************************************************" +echo "Installing libtorch" +echo "****************************************************************************************************" +echo +install_libtorch "${LIBTORCH_BUILD_DIR}" "${LIBTORCH_DIR}" +# shellcheck disable=SC2181 +if [[ $? -ne 0 ]] ; then + echo "Error: Failed to install libtorch" + exit 1 +fi + +# shellcheck disable=SC2181 +if [[ $? -eq 0 ]]; then + echo + echo "****************************************************************************************************" + echo "libtorch has been successfully installed. " + echo + echo "To configure MOOSE with libtorch, run the following commands:" + echo + echo " cd ${MOOSE_DIR}" + echo " ./configure --with-libtorch=${LIBTORCH_DIR}" + echo + echo "Append other configure options as needed. See configure --help for more information." + echo "****************************************************************************************************" +fi diff --git a/scripts/update_and_rebuild_neml2.sh b/scripts/update_and_rebuild_neml2.sh index 54d66c364bfa..34ac6c0c5e06 100755 --- a/scripts/update_and_rebuild_neml2.sh +++ b/scripts/update_and_rebuild_neml2.sh @@ -25,16 +25,12 @@ if [[ "$#" -eq 1 ]] && [[ "$1" == "--help" ]]; then echo " 4. Build NEML2" echo " 5. Install NEML2" echo - echo "NEML2 requires WASP and libtorch as dependencies. They can be " - echo "obtained using the following scripts:" - echo " - WASP: scripts/update_and_rebuild_wasp.sh" - echo " - libtorch: scripts/setup_libtorch.sh" + echo "NEML2 depends on libtorch as a dependency. It can be obtained using the following script:" + echo " scripts/update_and_rebuild_libtorch.sh" echo echo "Influential environment variables:" echo " MOOSE_DIR The path to the MOOSE directory. Default to the parent directory of this script." - echo " WASP_SRC_DIR The path to the WASP source directory. Default to /framework/contrib/wasp." - echo " WASP_DIR The path to the WASP directory. Default to /install." - echo " LIBTORCH_DIR The path to the libtorch directory. Default to /framework/contrib/libtorch." + echo " LIBTORCH_DIR The path to the libtorch directory. Default to /framework/contrib/pytorch/installed." echo " NEML2_DIR The path where to install NEML2. Default to /installed/moose." echo " NEML2_SRC_DIR The path to the NEML2 source directory if a custom NEML2 should be used. If set, " echo " --skip-submodule-update will be assumed." @@ -67,17 +63,7 @@ for ARG in "$@" ; do done # Dependency: libtorch -export LIBTORCH_DIR=${LIBTORCH_DIR:-${MOOSE_DIR}/framework/contrib/libtorch} - -# Dependency: wasp -WASP_SRC_DIR=${WASP_SRC_DIR:-${MOOSE_DIR}/framework/contrib/wasp} -export WASP_DIR=${WASP_DIR:-${WASP_SRC_DIR}/install} - -# Dependency: hit in place if it exists -if [ -z "$HIT_SRC_DIR" ] && [ -d "${MOOSE_DIR}/framework/contrib/hit" ]; then - HIT_SRC_DIR=${MOOSE_DIR}/framework/contrib/hit -fi -export HIT_SRC_DIR +export LIBTORCH_DIR=${LIBTORCH_DIR:-${MOOSE_DIR}/framework/contrib/pytorch/installed} # Handle environment variables if [[ -n "$NEML2_SRC_DIR" ]]; then @@ -95,13 +81,6 @@ if [[ -z "$NEML2_JOBS" ]]; then fi fi -# Dynamic library suffix -if [[ $(uname) == "Darwin" ]]; then - DYLIB_SUFFIX=dylib -else - DYLIB_SUFFIX=so -fi - # Build methods # # Note that the build directory is created under the NEML2 source directory, @@ -121,8 +100,6 @@ fi SCRIPT_NAME=$(basename "$0") echo "****************************************************************************************************" echo "${SCRIPT_NAME} summary:" -echo " HIT_SRC_DIR: ${HIT_SRC_DIR}" -echo " WASP_DIR: ${WASP_DIR}" echo " LIBTORCH_DIR: ${LIBTORCH_DIR}" echo " NEML2_DIR: ${NEML2_DIR}" echo " NEML2_SRC_DIR: ${NEML2_SRC_DIR}" @@ -150,22 +127,14 @@ if [[ ! -d "${LIBTORCH_DIR}" ]]; then fi exit 1 fi -if [[ ! -d "${WASP_DIR}" ]]; then - echo "Error: The WASP directory (${WASP_DIR}) does not exist. Please see --help for more information." - exit 1 -fi -if [[ ! -f "${WASP_DIR}"/lib/libwaspcore.${DYLIB_SUFFIX} ]] || [[ ! -f "${WASP_DIR}"/lib/libwasphit.${DYLIB_SUFFIX} ]]; then - echo "Error: The WASP directory (${WASP_DIR}) does not contain required libraries (core and hit). Please build WASP first." - exit 1 -fi # Step 1: Update the NEML2 submodule if [[ "$SKIP_SUBMODULE_UPDATE" != true ]] && [[ "$FAST" != true ]]; then cd "$MOOSE_DIR" || exit - git submodule update --init --checkout "${NEML2_SRC_DIR}" + git submodule update --init --checkout --recursive "${NEML2_SRC_DIR}" if [[ $? -ne 0 ]] ; then echo "Error: Failed to update the NEML2 submodule with command" - echo " git submodule update --init --checkout ${NEML2_SRC_DIR}" + echo " git submodule update --init --checkout --recursive ${NEML2_SRC_DIR}" exit 1 fi fi @@ -256,7 +225,10 @@ if [[ $? -eq 0 ]]; then echo "NEML2 has been successfully installed. " echo echo "To configure MOOSE with NEML2, run the following commands:" + echo echo " cd ${MOOSE_DIR}" echo " ./configure --with-neml2=${NEML2_DIR} --with-libtorch=${LIBTORCH_DIR}" + echo + echo "Append other configure options as needed. See configure --help for more information." echo "****************************************************************************************************" fi diff --git a/scripts/versioner.yaml b/scripts/versioner.yaml index 576e52e09305..cb0d66a69b9e 100644 --- a/scripts/versioner.yaml +++ b/scripts/versioner.yaml @@ -111,7 +111,7 @@ packages: conda/pyhit/meta.yaml.template: conda/pyhit/meta.yaml # dependers: none moose-dev: - version: 2026.04.21 + version: 2026.05.06 conda: conda/moose-dev templates: conda/moose-dev/meta.yaml.template: conda/moose-dev/meta.yaml @@ -133,7 +133,8 @@ packages: - scripts/configure_wasp.sh - scripts/update_and_rebuild_wasp.sh # libtorch - - scripts/setup_libtorch.sh + - scripts/configure_libtorch.sh + - scripts/update_and_rebuild_libtorch.sh # neml2 - scripts/configure_neml2.sh - scripts/update_and_rebuild_neml2.sh diff --git a/test/src/neml2/NEML2TestModel.C b/test/src/neml2/NEML2TestModel.C index b3318452a6c7..7e417da145ff 100644 --- a/test/src/neml2/NEML2TestModel.C +++ b/test/src/neml2/NEML2TestModel.C @@ -20,14 +20,14 @@ OptionSet NEML2TestModel::expected_options() { auto options = Model::expected_options(); - options.set_input("A") = VariableName("forces", "A"); - options.set_input("B") = VariableName("forces", "B"); - options.set_output("sum") = VariableName("state", "internal", "sum"); - options.set_output("product") = VariableName("state", "internal", "product"); - options.set_parameter>("p1") = "1"; - options.set_parameter>("p2") = "1"; - options.set("error") = false; - options.set("ad") = true; + options.add_input("A", "Input variable A"); + options.add_input("B", "Input variable B"); + options.add_output("sum", "Output variable sum"); + options.add_output("product", "Output variable product"); + options.add_parameter("p1", TensorName("1"), "Parameter p1"); + options.add_parameter("p2", TensorName("1"), "Parameter p2"); + options.add("error", false, "Error flag"); + options.add("ad", true, "Automatic differentiation flag"); return options; } @@ -65,8 +65,6 @@ void NEML2TestModel::set_value(bool out, bool dout_din, bool /*d2out_din2*/) { neml_assert(!_error, "Error flag set!"); - neml_assert(_input_a.tensor().numel() > 0, "Input A is empty!"); - neml_assert(_input_b.tensor().numel() > 0, "Input B is empty!"); if (out) { diff --git a/test/tests/neml2/blocks_different_model.i b/test/tests/neml2/blocks_different_model.i index ee8d62b969db..d92bbaf612e8 100644 --- a/test/tests/neml2/blocks_different_model.i +++ b/test/tests/neml2/blocks_different_model.i @@ -27,43 +27,22 @@ input = 'models/custom_model.i' verbose = true device = 'cpu' - [A] - model = 'model_A' - block = 'A' - - moose_input_types = 'VARIABLE MATERIAL' - moose_inputs = ' a b' - neml2_inputs = ' forces/A forces/B' - moose_output_types = 'MATERIAL MATERIAL' - moose_outputs = ' neml2_sum neml2_product' - neml2_outputs = ' state/internal/sum state/internal/product' + # request derivatives (must be pairs of two) + # derivative name follow moose convention, e.g., 'doutput/dinput' + derivatives = 'product A' - moose_derivative_types = 'MATERIAL' - moose_derivatives = 'neml2_dproduct_da' - neml2_derivatives = 'state/internal/product forces/A' + # output to exodus + export_outputs = 'sum product dproduct/dA' + export_output_targets = 'exodus; exodus; exodus' - export_outputs = 'neml2_sum neml2_product neml2_dproduct_da' - export_output_targets = 'exodus; exodus; exodus' + [A] + model = 'model_A' + block = 'A' [] [B] model = 'model_B' block = 'B' - - moose_input_types = 'VARIABLE MATERIAL' - moose_inputs = ' a b' - neml2_inputs = ' forces/A forces/B' - - moose_output_types = 'MATERIAL MATERIAL' - moose_outputs = ' neml2_sum neml2_product' - neml2_outputs = ' state/internal/sum state/internal/product' - - moose_derivative_types = 'MATERIAL' - moose_derivatives = 'neml2_dproduct_da' - neml2_derivatives = 'state/internal/product forces/A' - - export_outputs = 'neml2_sum neml2_product neml2_dproduct_da' - export_output_targets = 'exodus; exodus; exodus' [] [] @@ -80,37 +59,37 @@ [reaction_1] type = MatReaction variable = u - reaction_rate = neml2_sum + reaction_rate = sum [] [reaction_2] type = MatReaction variable = u - reaction_rate = neml2_product + reaction_rate = product [] [reaction_3] type = MatReaction variable = u - reaction_rate = neml2_dproduct_da + reaction_rate = dproduct/dA [] [] [AuxVariables] - [a] + [A] [] [] [ICs] - [a] + [A] type = FunctionIC - variable = a + variable = A function = 'x' [] [] [Materials] - [b] + [B] type = GenericFunctionMaterial - prop_names = 'b' + prop_names = 'B' prop_values = 'y+t' outputs = 'exodus' [] diff --git a/test/tests/neml2/blocks_empty_neml2.i b/test/tests/neml2/blocks_empty_neml2.i index 9d2164d3abb1..398931c19e8c 100644 --- a/test/tests/neml2/blocks_empty_neml2.i +++ b/test/tests/neml2/blocks_empty_neml2.i @@ -42,17 +42,9 @@ model = 'model_A' block = 'A' - moose_input_types = 'VARIABLE MATERIAL' - moose_inputs = ' a b' - neml2_inputs = ' forces/A forces/B' - - moose_output_types = 'MATERIAL MATERIAL' - moose_outputs = ' neml2_sum neml2_product' - neml2_outputs = ' state/internal/sum state/internal/product' - - moose_derivative_types = 'MATERIAL' - moose_derivatives = 'neml2_dproduct_da' - neml2_derivatives = 'state/internal/product forces/A' + # request derivatives (must be pairs of two) + # derivative name follow moose convention, e.g., 'doutput/dinput' + derivatives = 'product A' [] [] @@ -73,22 +65,22 @@ [source_1] type = MatBodyForce variable = u - material_property = neml2_sum + material_property = sum [] [source_2] type = MatBodyForce variable = u - material_property = neml2_product + material_property = product [] [source_3] type = MatBodyForce variable = u - material_property = neml2_dproduct_da + material_property = dproduct/dA [] [] [AuxVariables] - [a] + [A] [] [pid] order = CONSTANT @@ -101,22 +93,22 @@ [] [ICs] - [a] + [A] type = FunctionIC - variable = a + variable = A function = 'x' [] [] [Materials] - [b] + [B] type = GenericFunctionMaterial - prop_names = 'b' + prop_names = 'B' prop_values = 'y+t' [] [dummy] type = GenericConstantMaterial - prop_names = 'neml2_sum neml2_product neml2_dproduct_da' + prop_names = 'sum product dproduct/dA' prop_values = '0 0 0' block = 'B' [] diff --git a/test/tests/neml2/blocks_same_model.i b/test/tests/neml2/blocks_same_model.i index 3c85b675806e..fc579d83fc63 100644 --- a/test/tests/neml2/blocks_same_model.i +++ b/test/tests/neml2/blocks_same_model.i @@ -28,20 +28,14 @@ verbose = true device = 'cpu' - moose_input_types = 'VARIABLE MATERIAL' - moose_inputs = ' a b' - neml2_inputs = ' forces/A forces/B' + # request derivatives (must be pairs of two) + # derivative name follow moose convention, e.g., 'doutput/dinput' + derivatives = 'product A' - moose_output_types = 'MATERIAL MATERIAL' - moose_outputs = ' neml2_sum neml2_product' - neml2_outputs = ' state/internal/sum state/internal/product' - - moose_derivative_types = 'MATERIAL' - moose_derivatives = 'neml2_dproduct_da' - neml2_derivatives = 'state/internal/product forces/A' - - export_outputs = 'neml2_sum neml2_product neml2_dproduct_da' + # output to exodus + export_outputs = 'sum product dproduct/dA' export_output_targets = 'exodus; exodus; exodus' + [A] model = 'model' block = 'A' @@ -65,37 +59,37 @@ [reaction_1] type = MatReaction variable = u - reaction_rate = neml2_sum + reaction_rate = sum [] [reaction_2] type = MatReaction variable = u - reaction_rate = neml2_product + reaction_rate = product [] [reaction_3] type = MatReaction variable = u - reaction_rate = neml2_dproduct_da + reaction_rate = dproduct/dA [] [] [AuxVariables] - [a] + [A] [] [] [ICs] - [a] + [A] type = FunctionIC - variable = a + variable = A function = 'x' [] [] [Materials] - [b] + [B] type = GenericFunctionMaterial - prop_names = 'b' + prop_names = 'B' prop_values = 'y+t' outputs = 'exodus' [] diff --git a/test/tests/neml2/custom_model.i b/test/tests/neml2/custom_model.i index 0d85fe8c163e..c03edc02be50 100644 --- a/test/tests/neml2/custom_model.i +++ b/test/tests/neml2/custom_model.i @@ -14,19 +14,12 @@ verbose = true device = 'cpu' - moose_input_types = 'VARIABLE MATERIAL' - moose_inputs = ' a b' - neml2_inputs = ' forces/A forces/B' + # request derivatives (must be pairs of two) + # derivative name follow moose convention, e.g., 'doutput/dinput' + derivatives = 'product A' - moose_output_types = 'MATERIAL MATERIAL' - moose_outputs = ' neml2_sum neml2_product' - neml2_outputs = ' state/internal/sum state/internal/product' - - moose_derivative_types = 'MATERIAL' - moose_derivatives = 'neml2_dproduct_da' - neml2_derivatives = 'state/internal/product forces/A' - - export_outputs = 'neml2_sum neml2_product neml2_dproduct_da' + # output to exodus + export_outputs = 'sum product dproduct/dA' export_output_targets = 'exodus; exodus; exodus' [] [] @@ -44,37 +37,37 @@ [reaction_1] type = MatReaction variable = u - reaction_rate = neml2_sum + reaction_rate = sum [] [reaction_2] type = MatReaction variable = u - reaction_rate = neml2_product + reaction_rate = product [] [reaction_3] type = MatReaction variable = u - reaction_rate = neml2_dproduct_da + reaction_rate = dproduct/dA [] [] [AuxVariables] - [a] + [A] [] [] [ICs] - [a] + [A] type = FunctionIC - variable = a + variable = A function = 'x' [] [] [Materials] - [b] + [B] type = GenericFunctionMaterial - prop_names = 'b' + prop_names = 'B' prop_values = 'y+t' outputs = 'exodus' [] diff --git a/test/tests/neml2/error.i b/test/tests/neml2/error.i deleted file mode 100644 index 213da5dc299e..000000000000 --- a/test/tests/neml2/error.i +++ /dev/null @@ -1,86 +0,0 @@ -[Mesh] - [gmg] - type = GeneratedMeshGenerator - dim = 2 - nx = 10 - ny = 10 - [] -[] - -[NEML2] - input = 'models/error.i' - [all] - model = 'model' - verbose = true - device = 'cpu' - - moose_input_types = 'VARIABLE MATERIAL' - moose_inputs = ' a b' - neml2_inputs = ' forces/A forces/B' - - moose_output_types = 'MATERIAL MATERIAL' - moose_outputs = ' neml2_sum neml2_product' - neml2_outputs = ' state/internal/sum state/internal/product' - - moose_derivative_types = 'MATERIAL' - moose_derivatives = 'neml2_dproduct_da' - neml2_derivatives = 'state/internal/product forces/A' - [] -[] - -[Variables] - [u] - [] -[] - -[Kernels] - [diffusion] - type = Diffusion - variable = u - [] - [reaction_1] - type = MatReaction - variable = u - reaction_rate = neml2_sum - [] - [reaction_2] - type = MatReaction - variable = u - reaction_rate = neml2_product - [] - [reaction_3] - type = MatReaction - variable = u - reaction_rate = neml2_dproduct_da - [] -[] - -[AuxVariables] - [a] - [] -[] - -[ICs] - [a] - type = FunctionIC - variable = a - function = 'x' - [] -[] - -[Materials] - [b] - type = GenericFunctionMaterial - prop_names = 'b' - prop_values = 'y+t' - [] -[] - -[Executioner] - type = Transient - solve_type = NEWTON - petsc_options_iname = '-pc_type' - petsc_options_value = 'lu' - num_steps = 1 - dtmin = 1 -[] diff --git a/test/tests/neml2/gold/blocks_different_model_out.e b/test/tests/neml2/gold/blocks_different_model_out.e index 8bee7ad3de26..4929c9dac2cb 100644 Binary files a/test/tests/neml2/gold/blocks_different_model_out.e and b/test/tests/neml2/gold/blocks_different_model_out.e differ diff --git a/test/tests/neml2/gold/blocks_same_model_out.e b/test/tests/neml2/gold/blocks_same_model_out.e index 3f645103af38..7038ea4f658d 100644 Binary files a/test/tests/neml2/gold/blocks_same_model_out.e and b/test/tests/neml2/gold/blocks_same_model_out.e differ diff --git a/test/tests/neml2/gold/custom_model_out.e b/test/tests/neml2/gold/custom_model_out.e index f346babcb695..407d7ecd886d 100644 Binary files a/test/tests/neml2/gold/custom_model_out.e and b/test/tests/neml2/gold/custom_model_out.e differ diff --git a/test/tests/neml2/gold/mesh_change_out.e b/test/tests/neml2/gold/mesh_change_out.e index 271a240a2dc4..5daea34e58bf 100644 Binary files a/test/tests/neml2/gold/mesh_change_out.e and b/test/tests/neml2/gold/mesh_change_out.e differ diff --git a/test/tests/neml2/gold/mesh_change_out.e-s002 b/test/tests/neml2/gold/mesh_change_out.e-s002 index ccb54ada85a5..78add23e8d38 100644 Binary files a/test/tests/neml2/gold/mesh_change_out.e-s002 and b/test/tests/neml2/gold/mesh_change_out.e-s002 differ diff --git a/test/tests/neml2/gold/mesh_change_out.e-s003 b/test/tests/neml2/gold/mesh_change_out.e-s003 index 2c022662e09a..020f567b435b 100644 Binary files a/test/tests/neml2/gold/mesh_change_out.e-s003 and b/test/tests/neml2/gold/mesh_change_out.e-s003 differ diff --git a/test/tests/neml2/gold/mesh_change_out.e-s004 b/test/tests/neml2/gold/mesh_change_out.e-s004 index e786a5bbb433..86e87433b3dd 100644 Binary files a/test/tests/neml2/gold/mesh_change_out.e-s004 and b/test/tests/neml2/gold/mesh_change_out.e-s004 differ diff --git a/test/tests/neml2/gold/mesh_change_out.e-s005 b/test/tests/neml2/gold/mesh_change_out.e-s005 index 4dfd5b6d4093..a26e7b1e809c 100644 Binary files a/test/tests/neml2/gold/mesh_change_out.e-s005 and b/test/tests/neml2/gold/mesh_change_out.e-s005 differ diff --git a/test/tests/neml2/gold/multiple_input_files_out.e b/test/tests/neml2/gold/multiple_input_files_out.e index 5bd8d7b255f6..4a1d463f476f 100644 Binary files a/test/tests/neml2/gold/multiple_input_files_out.e and b/test/tests/neml2/gold/multiple_input_files_out.e differ diff --git a/test/tests/neml2/gold/parameter_out.e b/test/tests/neml2/gold/parameter_out.e index 6383f1a93f1b..574bbbe0d8ef 100644 Binary files a/test/tests/neml2/gold/parameter_out.e and b/test/tests/neml2/gold/parameter_out.e differ diff --git a/test/tests/neml2/gold/simple_scheduler_out.e b/test/tests/neml2/gold/simple_scheduler_out.e index 98b6b8e6f981..8ae0f02fb58d 100644 Binary files a/test/tests/neml2/gold/simple_scheduler_out.e and b/test/tests/neml2/gold/simple_scheduler_out.e differ diff --git a/test/tests/neml2/mesh_change.i b/test/tests/neml2/mesh_change.i index 14a690054401..98e8f6520d12 100644 --- a/test/tests/neml2/mesh_change.i +++ b/test/tests/neml2/mesh_change.i @@ -43,38 +43,24 @@ model = 'model_A_non_ad' block = 'A' - moose_input_types = 'VARIABLE MATERIAL' - moose_inputs = ' a b' - neml2_inputs = ' forces/A forces/B' + # request derivatives (must be pairs of two) + # derivative name follow moose convention, e.g., 'doutput/dinput' + derivatives = 'product A' - moose_output_types = 'MATERIAL MATERIAL' - moose_outputs = ' neml2_sum neml2_product' - neml2_outputs = ' state/internal/sum state/internal/product' - - moose_derivative_types = 'MATERIAL' - moose_derivatives = 'neml2_dproduct_da' - neml2_derivatives = 'state/internal/product forces/A' - - export_outputs = 'neml2_sum neml2_product neml2_dproduct_da' + # output to exodus + export_outputs = 'sum product dproduct/dA' export_output_targets = 'exodus; exodus; exodus' [] [B] model = 'model_B_non_ad' block = 'B' - moose_input_types = 'VARIABLE MATERIAL' - moose_inputs = ' a b' - neml2_inputs = ' forces/A forces/B' - - moose_output_types = 'MATERIAL MATERIAL' - moose_outputs = ' neml2_sum neml2_product' - neml2_outputs = ' state/internal/sum state/internal/product' - - moose_derivative_types = 'MATERIAL' - moose_derivatives = 'neml2_dproduct_da' - neml2_derivatives = 'state/internal/product forces/A' + # request derivatives (must be pairs of two) + # derivative name follow moose convention, e.g., 'doutput/dinput' + derivatives = 'product A' - export_outputs = 'neml2_sum neml2_product neml2_dproduct_da' + # output to exodus + export_outputs = 'sum product dproduct/dA' export_output_targets = 'exodus; exodus; exodus' [] [] @@ -100,37 +86,37 @@ [reaction_1] type = MatReaction variable = u - reaction_rate = neml2_sum + reaction_rate = sum [] [reaction_2] type = MatReaction variable = u - reaction_rate = neml2_product + reaction_rate = product [] [reaction_3] type = MatReaction variable = u - reaction_rate = neml2_dproduct_da + reaction_rate = dproduct/dA [] [] [AuxVariables] - [a] + [A] [] [] [ICs] - [a] + [A] type = FunctionIC - variable = a + variable = A function = 'x' [] [] [Materials] - [b] + [B] type = GenericFunctionMaterial - prop_names = 'b' + prop_names = 'B' prop_values = 'y+t' outputs = 'exodus' [] diff --git a/test/tests/neml2/models/custom_model.i b/test/tests/neml2/models/custom_model.i index f5865d5849b0..b6825e83ec22 100644 --- a/test/tests/neml2/models/custom_model.i +++ b/test/tests/neml2/models/custom_model.i @@ -2,10 +2,10 @@ [model] type = NEML2TestModel # these are the default values for the parameters - A = forces/A - B = forces/B - sum = state/internal/sum - product = state/internal/product + A = 'A' + B = 'B' + sum = 'sum' + product = 'product' [] [model_A] type = NEML2TestModel @@ -33,6 +33,11 @@ p2 = 5 ad = false [] + [error] + type = NEML2TestModel + error = true + jit = false + [] [] [Schedulers] diff --git a/test/tests/neml2/models/error.i b/test/tests/neml2/models/error.i deleted file mode 100644 index c8a6c4500be2..000000000000 --- a/test/tests/neml2/models/error.i +++ /dev/null @@ -1,7 +0,0 @@ -[Models] - [model] - type = NEML2TestModel - error = true - jit = false - [] -[] diff --git a/test/tests/neml2/multiple_input_files.i b/test/tests/neml2/multiple_input_files.i index eb016afbb996..4d285489d718 100644 --- a/test/tests/neml2/multiple_input_files.i +++ b/test/tests/neml2/multiple_input_files.i @@ -31,19 +31,12 @@ model = 'model_A' block = 'A' - moose_input_types = 'VARIABLE MATERIAL' - moose_inputs = ' a b' - neml2_inputs = ' forces/A forces/B' + # request derivatives (must be pairs of two) + # derivative name follow moose convention, e.g., 'doutput/dinput' + derivatives = 'product A' - moose_output_types = 'MATERIAL MATERIAL' - moose_outputs = ' neml2_sum neml2_product' - neml2_outputs = ' state/internal/sum state/internal/product' - - moose_derivative_types = 'MATERIAL' - moose_derivatives = 'neml2_dproduct_da' - neml2_derivatives = 'state/internal/product forces/A' - - export_outputs = 'neml2_sum neml2_product neml2_dproduct_da' + # output to exodus + export_outputs = 'sum product dproduct/dA' export_output_targets = 'exodus; exodus; exodus' [] [B] @@ -51,19 +44,12 @@ model = 'model_B' block = 'B' - moose_input_types = 'VARIABLE MATERIAL' - moose_inputs = ' a b' - neml2_inputs = ' forces/A forces/B' - - moose_output_types = 'MATERIAL MATERIAL' - moose_outputs = ' neml2_sum neml2_product' - neml2_outputs = ' state/internal/sum state/internal/product' - - moose_derivative_types = 'MATERIAL' - moose_derivatives = 'neml2_dproduct_da' - neml2_derivatives = 'state/internal/product forces/A' + # request derivatives (must be pairs of two) + # derivative name follow moose convention, e.g., 'doutput/dinput' + derivatives = 'product A' - export_outputs = 'neml2_sum neml2_product neml2_dproduct_da' + # output to exodus + export_outputs = 'sum product dproduct/dA' export_output_targets = 'exodus; exodus; exodus' [] [] @@ -81,37 +67,37 @@ [reaction_1] type = MatReaction variable = u - reaction_rate = neml2_sum + reaction_rate = sum [] [reaction_2] type = MatReaction variable = u - reaction_rate = neml2_product + reaction_rate = product [] [reaction_3] type = MatReaction variable = u - reaction_rate = neml2_dproduct_da + reaction_rate = dproduct/dA [] [] [AuxVariables] - [a] + [A] [] [] [ICs] - [a] + [A] type = FunctionIC - variable = a + variable = A function = 'x' [] [] [Materials] - [b] + [B] type = GenericFunctionMaterial - prop_names = 'b' + prop_names = 'B' prop_values = 'y+t' outputs = 'exodus' [] diff --git a/test/tests/neml2/parameter.i b/test/tests/neml2/parameter.i index 792bca8b1a67..6854c55015bf 100644 --- a/test/tests/neml2/parameter.i +++ b/test/tests/neml2/parameter.i @@ -14,23 +14,16 @@ verbose = true device = 'cpu' - moose_input_types = 'VARIABLE MATERIAL' - moose_inputs = ' a b' - neml2_inputs = ' forces/A forces/B' + # use moose data as model parameters + parameter_types = 'MATERIAL VARIABLE' + parameters = ' p1 p2' - moose_parameter_types = 'MATERIAL VARIABLE' - moose_parameters = ' p1_mat p2_var' - neml2_parameters = ' p1 p2' + # request derivatives (must be pairs of two) + # derivative name follow moose convention, e.g., 'doutput/dinput' + derivatives = 'product A' - moose_output_types = 'MATERIAL MATERIAL' - moose_outputs = ' neml2_sum neml2_product' - neml2_outputs = ' state/internal/sum state/internal/product' - - moose_derivative_types = 'MATERIAL' - moose_derivatives = 'neml2_dproduct_da' - neml2_derivatives = 'state/internal/product forces/A' - - export_outputs = 'neml2_sum neml2_product neml2_dproduct_da' + # output to exodus + export_outputs = 'sum product dproduct/dA' export_output_targets = 'exodus; exodus; exodus' [] [] @@ -48,46 +41,46 @@ [reaction_1] type = MatReaction variable = u - reaction_rate = neml2_sum + reaction_rate = sum [] [reaction_2] type = MatReaction variable = u - reaction_rate = neml2_product + reaction_rate = product [] [reaction_3] type = MatReaction variable = u - reaction_rate = neml2_dproduct_da + reaction_rate = dproduct/dA [] [] [AuxVariables] - [a] + [A] [] - [p2_var] + [p2] initial_condition = 2 [] [] [ICs] - [a] + [A] type = FunctionIC - variable = a + variable = A function = 'x' [] [] [Materials] - [b] + [B] type = GenericFunctionMaterial - prop_names = 'b' + prop_names = 'B' prop_values = 'y+t' outputs = 'exodus' [] - [p1_mat] + [p1] type = GenericConstantMaterial - prop_names = 'p1_mat' + prop_names = 'p1' prop_values = 3 [] [] diff --git a/test/tests/neml2/simple_scheduler.i b/test/tests/neml2/simple_scheduler.i deleted file mode 100644 index fc8664625471..000000000000 --- a/test/tests/neml2/simple_scheduler.i +++ /dev/null @@ -1,95 +0,0 @@ -[Mesh] - [gmg] - type = GeneratedMeshGenerator - dim = 2 - nx = 10 - ny = 10 - [] -[] - -[NEML2] - input = 'models/custom_model.i' - scheduler = 'simple' - async_dispatch = false - [all] - model = 'model_non_ad' - verbose = true - device = 'cpu' - - moose_input_types = 'VARIABLE MATERIAL' - moose_inputs = ' a b' - neml2_inputs = ' forces/A forces/B' - - moose_output_types = 'MATERIAL MATERIAL' - moose_outputs = ' neml2_sum neml2_product' - neml2_outputs = ' state/internal/sum state/internal/product' - - moose_derivative_types = 'MATERIAL' - moose_derivatives = 'neml2_dproduct_da' - neml2_derivatives = 'state/internal/product forces/A' - - export_outputs = 'neml2_sum neml2_product neml2_dproduct_da' - export_output_targets = 'exodus; exodus; exodus' - [] -[] - -[Variables] - [u] - [] -[] - -[Kernels] - [diffusion] - type = Diffusion - variable = u - [] - [reaction_1] - type = MatReaction - variable = u - reaction_rate = neml2_sum - [] - [reaction_2] - type = MatReaction - variable = u - reaction_rate = neml2_product - [] - [reaction_3] - type = MatReaction - variable = u - reaction_rate = neml2_dproduct_da - [] -[] - -[AuxVariables] - [a] - [] -[] - -[ICs] - [a] - type = FunctionIC - variable = a - function = 'x' - [] -[] - -[Materials] - [b] - type = GenericFunctionMaterial - prop_names = 'b' - prop_values = 'y+t' - outputs = 'exodus' - [] -[] - -[Executioner] - type = Transient - solve_type = NEWTON - petsc_options_iname = '-pc_type' - petsc_options_value = 'lu' - num_steps = 2 -[] - -[Outputs] - exodus = true -[] diff --git a/test/tests/neml2/simple_scheduler_async.i b/test/tests/neml2/simple_scheduler_async.i deleted file mode 100644 index 4802d3942940..000000000000 --- a/test/tests/neml2/simple_scheduler_async.i +++ /dev/null @@ -1,95 +0,0 @@ -[Mesh] - [gmg] - type = GeneratedMeshGenerator - dim = 2 - nx = 10 - ny = 10 - [] -[] - -[NEML2] - input = 'models/custom_model.i' - scheduler = 'simple' - async_dispatch = true - [all] - model = 'model_non_ad' - verbose = true - device = 'cpu' - - moose_input_types = 'VARIABLE MATERIAL' - moose_inputs = ' a b' - neml2_inputs = ' forces/A forces/B' - - moose_output_types = 'MATERIAL MATERIAL' - moose_outputs = ' neml2_sum neml2_product' - neml2_outputs = ' state/internal/sum state/internal/product' - - moose_derivative_types = 'MATERIAL' - moose_derivatives = 'neml2_dproduct_da' - neml2_derivatives = 'state/internal/product forces/A' - - export_outputs = 'neml2_sum neml2_product neml2_dproduct_da' - export_output_targets = 'exodus; exodus; exodus' - [] -[] - -[Variables] - [u] - [] -[] - -[Kernels] - [diffusion] - type = Diffusion - variable = u - [] - [reaction_1] - type = MatReaction - variable = u - reaction_rate = neml2_sum - [] - [reaction_2] - type = MatReaction - variable = u - reaction_rate = neml2_product - [] - [reaction_3] - type = MatReaction - variable = u - reaction_rate = neml2_dproduct_da - [] -[] - -[AuxVariables] - [a] - [] -[] - -[ICs] - [a] - type = FunctionIC - variable = a - function = 'x' - [] -[] - -[Materials] - [b] - type = GenericFunctionMaterial - prop_names = 'b' - prop_values = 'y+t' - outputs = 'exodus' - [] -[] - -[Executioner] - type = Transient - solve_type = NEWTON - petsc_options_iname = '-pc_type' - petsc_options_value = 'lu' - num_steps = 2 -[] - -[Outputs] - exodus = true -[] diff --git a/test/tests/neml2/tests b/test/tests/neml2/tests index f3d1e82d455b..10b68720a839 100644 --- a/test/tests/neml2/tests +++ b/test/tests/neml2/tests @@ -2,10 +2,19 @@ # The original issue is idaholab/blackbear#333 issues = '#26450 #26920' design = 'NEML2/index.md NEML2Action.md' + [custom_model] + requirement = 'The framework shall be capable of running custom NEML2 model implemented in MOOSE (optionally with automatic differentiation).' + type = Exodiff + input = 'custom_model.i' + exodiff = 'custom_model_out.e' + capabilities = 'neml2' + valgrind = heavy + [] [neml2_error] requirement = 'The framework shall be capable of capturing errors that occur during the evaluation of a NEML2 model.' type = RunException - input = 'error.i' + input = 'custom_model.i' + cli_args = 'NEML2/all/model=error' expect_err = 'NEML2 model execution failed on at least one processor' collections = 'SYSTEM' capabilities = 'neml2' @@ -27,14 +36,6 @@ capabilities = 'neml2' valgrind = heavy [] - [custom_model] - requirement = 'The framework shall be capable of running custom NEML2 model implemented in MOOSE (optionally with automatic differentiation).' - type = Exodiff - input = 'custom_model.i' - exodiff = 'custom_model_out.e' - capabilities = 'neml2' - valgrind = heavy - [] [block_restriction] issues = '#27493' collections = 'SYSTEM' @@ -89,7 +90,8 @@ [simple_scheduler] detail = 'with NEML2 SimpleScheduler which dispatches to a single device' type = Exodiff - input = 'simple_scheduler.i' + input = 'custom_model.i' + cli_args = 'NEML2/scheduler=simple NEML2/async_dispatch=false NEML2/all/model=model_non_ad Outputs/file_base=simple_scheduler_out' exodiff = 'simple_scheduler_out.e' capabilities = 'neml2' recover = false @@ -99,8 +101,8 @@ detail = 'with NEML2 SimpleScheduler which asynchronously dispatches to a single device' prereq = 'scheduler/simple_scheduler' type = Exodiff - input = 'simple_scheduler_async.i' - cli_args = 'Outputs/file_base=simple_scheduler_out' + input = 'custom_model.i' + cli_args = 'NEML2/scheduler=simple NEML2/async_dispatch=true NEML2/all/model=model_non_ad Outputs/file_base=simple_scheduler_out' exodiff = 'simple_scheduler_out.e' capabilities = 'neml2' recover = false diff --git a/test/tests/neml2/torchscript/heat_conduction.i b/test/tests/neml2/torchscript/heat_conduction.i index 2ec9f68248d0..e94e9ec78a4f 100644 --- a/test/tests/neml2/torchscript/heat_conduction.i +++ b/test/tests/neml2/torchscript/heat_conduction.i @@ -11,17 +11,9 @@ [thermal_conductivity_model] model = 'kappa' - moose_input_types = 'VARIABLE' - moose_inputs = 'T' - neml2_inputs = 'forces/T' - - moose_output_types = 'MATERIAL' - neml2_outputs = 'state/k_T' - moose_outputs = 'k_T' - - moose_derivative_types = 'MATERIAL' - neml2_derivatives = 'state/k_T forces/T' - moose_derivatives = 'dk_T/dT' + # request derivatives (must be pairs of two) + # derivative name follow moose convention, e.g., 'doutput/dinput' + derivatives = 'k_T T' export_outputs = 'k_T dK_T/dT' export_output_targets = 'exodus; exodus' diff --git a/test/tests/neml2/torchscript/thermal_conductivity.i b/test/tests/neml2/torchscript/thermal_conductivity.i index e443de7e5190..85000b13d6f6 100644 --- a/test/tests/neml2/torchscript/thermal_conductivity.i +++ b/test/tests/neml2/torchscript/thermal_conductivity.i @@ -1,8 +1,8 @@ [Models] [kappa] type = LibtorchModel - inputs = 'forces/T' - outputs = 'state/k_T' + inputs = 'T' + outputs = 'k_T' file_path = 'libtorch/test/thermal_conductivity_model.pt' [] []