16 #include "libmesh/id_types.h" 17 #include "neml2/tensors/functions/jacrev.h" 18 #include "neml2/dispatchers/ValueMapLoader.h" 28 params.addParam<std::vector<std::string>>(
32 "List of NEML2 variables to skip error checking when setting up the model input. If an " 33 "input variable is skipped, its value will stay zero. If a required input variable is " 34 "not skipped, an error will be raised."));
45 params.addRequiredParam<UserObjectName>(
46 "batch_index_generator",
47 "The NEML2BatchIndexGenerator used to generate the element-to-batch-index map.");
48 params.addParam<std::vector<UserObjectName>>(
52 "List of MOOSE*ToNEML2 user objects gathering MOOSE data as NEML2 input variables"));
53 params.addParam<std::vector<UserObjectName>>(
57 "List of MOOSE*ToNEML2 user objects gathering MOOSE data as NEML2 model parameters"));
64 params.set<
ExecFlagEnum>(
"execute_on") = execute_options;
82 for (
const auto & gatherer_name :
getParam<std::vector<UserObjectName>>(
"gatherers"))
84 for (
const auto & gatherer_name :
getParam<std::vector<UserObjectName>>(
"param_gatherers"))
88 for (
const auto & var_name :
getParam<std::vector<std::string>>(
"skip_inputs"))
98 for (
const auto & gatherer_name :
getParam<std::vector<UserObjectName>>(
"gatherers"))
102 const auto & uo = getUserObjectByName<MOOSEToNEML2>(gatherer_name,
false);
106 mooseError(
"The MOOSEToNEML2 gatherer named '",
108 "' is gathering MOOSE data for a non-existent NEML2 input variable named '",
114 if (varname.is_old_force() || varname.is_old_state())
124 for (
const auto & gatherer_name :
getParam<std::vector<UserObjectName>>(
"param_gatherers"))
128 const auto & uo = getUserObjectByName<MOOSEToNEML2>(gatherer_name,
false);
132 if (
model().named_parameters().count(uo.NEML2Name()) != 1)
133 mooseError(
"The MOOSEToNEML2 gatherer named '",
135 "' is gathering MOOSE data for a non-existent NEML2 model parameter named '",
147 std::vector<neml2::VariableName> required_inputs =
model().input_axis().variable_names();
148 for (
const auto & input : required_inputs)
153 if (input.is_state())
156 paramError(
"gatherers",
"The required model input `", input,
"` is not gathered");
162 for (
const auto & input : required_inputs)
165 "The NEML2 model requires a stateful input variable `",
167 "`, but its state counterpart on the output axis has not been retrieved by any object. " 168 "Therefore, there is no way to properly propagate the corresponding stateful data in " 169 "time. The common solution to this problem is to add a NEML2ToMOOSE retriever such as " 170 "those called `NEML2To*MOOSEMaterialProperty`.");
181 const neml2::VariableName & var)
185 "The NEML2 input variable `",
187 "` gathered by UO '",
189 "' is already gathered by another gatherer.");
195 const std::string & param)
199 "The NEML2 model parameter `",
201 "` gathered by UO '",
203 "' is already gathered by another gatherer.");
238 auto success =
solve();
253 for (
auto & [var, val] :
_in)
264 for (
const auto & [p, tensor] : dy)
265 model().get_parameter(p).requires_grad_(
true);
267 catch (std::exception & e)
269 mooseError(
"An error occurred while filling inputs for the NEML2 model. Error message:\n",
280 if (!
model().input_axis().has_state())
282 if (!
model().input_axis().has_old_state())
288 const auto & input_state =
model().input_axis().subaxis(neml2::STATE);
289 const auto & input_old_state =
model().input_axis().subaxis(neml2::OLD_STATE);
290 for (
const auto & var : input_state.variable_names())
291 if (input_old_state.has_variable(var))
292 _in[var.prepend(neml2::STATE)] =
_in[var.prepend(neml2::OLD_STATE)];
294 catch (std::exception & e)
296 mooseError(
"An error occurred while applying predictor for the NEML2 model. Error message:\n",
306 std::vector<neml2::Tensor>
defined;
307 for (
const auto & [key,
value] :
_in)
309 const auto batch_shape = neml2::utils::broadcast_batch_sizes(
defined);
313 if (
value.batch_sizes() != batch_shape)
314 _in[key] =
value.batch_unsqueeze(0).batch_expand(batch_shape);
323 TIME_SECTION(
"NEML2 solve", 3,
"Solving NEML2 material model");
326 auto prev_dtype = neml2::get_default_dtype();
327 neml2::set_default_dtype(neml2::kFloat64);
333 neml2::ValueMapLoader loader(
_in, 0);
341 neml2::set_default_dtype(prev_dtype);
343 catch (std::exception & e)
361 target =
_out[y].to(torch::kCPU);
365 for (
auto & [p, target] : dy)
366 target = neml2::jacrev(
_out[y],
367 model().get_parameter(p),
378 for (
auto & [x, target] : dy)
381 if (source.defined())
382 target = source.to(torch::kCPU).batch_expand({neml2::Size(
N)});
388 catch (std::exception & e)
390 mooseError(
"An error occurred while retrieving outputs from the NEML2 model. Error message:\n",
412 std::string msg =
"NEML2 model execution failed on at least one processor with ID " +
413 std::to_string(pid) +
". Error message:\n";
416 msg +=
"\nTo recover, the solution will fail and then be re-attempted with a reduced time " 418 _console << COLOR_YELLOW << msg << COLOR_DEFAULT << std::endl;
430 mooseError(
"NEML2 output variables and derivatives must be retrieved during object " 431 "construction. This is a code problem.");
434 const neml2::Tensor &
439 if (!
model().output_axis().has_variable(output_name))
440 mooseError(
"Trying to retrieve a non-existent NEML2 output variable '", output_name,
"'.");
445 const neml2::Tensor &
447 const neml2::VariableName & input_name)
const 451 if (!
model().output_axis().has_variable(output_name))
452 mooseError(
"Trying to retrieve the derivative of NEML2 output variable '",
454 "' with respect to NEML2 input variable '",
456 "', but the NEML2 output variable does not exist.");
458 if (!
model().input_axis().has_variable(input_name))
459 mooseError(
"Trying to retrieve the derivative of NEML2 output variable '",
461 "' with respect to NEML2 input variable '",
463 "', but the NEML2 input variable does not exist.");
468 const neml2::Tensor &
470 const std::string & parameter_name)
const 474 if (!
model().output_axis().has_variable(output_name))
475 mooseError(
"Trying to retrieve the derivative of NEML2 output variable '",
477 "' with respect to NEML2 model parameter '",
479 "', but the NEML2 output variable does not exist.");
481 if (
model().named_parameters().count(parameter_name) != 1)
482 mooseError(
"Trying to retrieve the derivative of NEML2 output variable '",
484 "' with respect to NEML2 model parameter '",
486 "', but the NEML2 model parameter does not exist.");
virtual void addGatheredVariable(const UserObjectName &, const neml2::VariableName &)
Register a NEML2 input variable gathered by a gatherer.
neml2::WorkScheduler * scheduler()
Get the work scheduler.
std::vector< const MOOSEToNEML2 * > _gatherers
MOOSE data gathering user objects.
A MultiMooseEnum object to hold "execute_on" flags.
static InputParameters validParams()
void execute() override
Execute method.
neml2::DerivMap _retrieved_derivatives
set of derivatives that were retrieved (by other objects)
bool shouldCompute(const SubProblem &)
Determine whether the NEML2 material model should be evaluated.
Interface class to provide common input parameters, members, and methods for MOOSEObjects that use NE...
virtual bool solve()
Perform the material update.
neml2::Model & model() const
Get the NEML2 model.
bool _error
Whether an error was encountered.
const neml2::Device & device() const
Get the target compute device.
processor_id_type rank() const
std::set< neml2::VariableName > _gathered_variable_names
neml2::ValueMap _out
The output variables of the material model.
static std::string NEML2_help_message
const Parallel::Communicator & _communicator
const std::unique_ptr< DispatcherType > & dispatcher() const
Get the work dispatcher.
virtual void extractOutputs()
Extract output derivatives with respect to input variables and model parameters.
registerMooseObject("MooseApp", NEML2ModelExecutor)
void setFailNextNonlinearConvergenceCheck()
Skip further residual evaluations and fail the next nonlinear convergence check(s) ...
ExecFlagEnum getDefaultExecFlagEnum()
Return the default ExecFlagEnum for MOOSE.
std::set< std::string > _gathered_parameter_names
void initialSetup() override
Gets called at the beginning of the simulation before this object is asked to do its job...
const NEML2BatchIndexGenerator & _batch_index_generator
The NEML2BatchIndexGenerator used to generate the element-to-batch-index map.
const neml2::Tensor & getOutputDerivative(const neml2::VariableName &output_name, const neml2::VariableName &input_name) const
Get a reference(!) to the requested output derivative view.
std::string _error_message
Error message.
uint8_t processor_id_type
int & _t_step
The number of the time step.
std::set< neml2::VariableName > _skip_vars
Real value(unsigned n, unsigned alpha, unsigned beta, Real x)
std::map< neml2::VariableName, std::map< std::string, neml2::Tensor > > _retrieved_parameter_derivatives
set of parameter derivatives that were retrieved (by other objects)
virtual void fillInputs()
Fill input variables and model parameters using the gatherers.
std::string docstring(const std::string &desc)
Augment docstring if NEML2 is not enabled.
const T & getParam(const std::string &name) const
Retrieve a parameter for the object.
void initialize() override
Called before execute() is ever called so that data can be cleared.
void paramError(const std::string ¶m, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
void maxloc(T &r, unsigned int &max_id) const
const ExecFlagType EXEC_LINEAR
virtual void checkExecutionStage() const final
Prevent output and derivative retrieval after construction.
virtual void applyPredictor()
Apply the predictor to set current trial state.
void broadcast(T &data, const unsigned int root_id=0, const bool identical_sizes=false) const
static InputParameters actionParams()
Parameters that can be specified under the NEML2Action common area.
const ExecFlagType EXEC_NONLINEAR
std::set< std::string > _depend_uo
Depend UserObjects that to be used both for determining user object sorting and by AuxKernel for find...
const neml2::Tensor & getOutput(const neml2::VariableName &output_name) const
Get a reference(!) to the requested output view.
std::map< std::string, neml2::Tensor > _model_params
The model parameters to update (gathered from MOOSE)
NEML2ModelExecutor executes a NEML2 model.
bool _output_ready
flag that indicates if output data has been fully computed
FEProblemBase & _fe_problem
Reference to the FEProblemBase for this user object.
neml2::DerivMap _dout_din
The derivative of the output variables w.r.t. the input variables.
virtual void addGatheredParameter(const UserObjectName &, const std::string &)
Register a NEML2 model parameter gathered by a gatherer.
void meshChanged() override
Called on this object when the mesh changes.
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type.
static InputParameters validParams()
const neml2::Tensor & getOutputParameterDerivative(const neml2::VariableName &output_name, const std::string ¶meter_name) const
Get a reference(!) to the requested output parameter derivative view.
void finalize() override
Finalize.
const ConsoleStream _console
An instance of helper class to write streams to the Console objects.
virtual void validateModel() const
Validate the NEML2 material model.
virtual bool isTransient() const override
virtual void expandInputs()
Expand tensor shapes if necessary to conformal sizes.
std::size_t getBatchIndex() const
Get the current batch index (in almost all cases this is the total batch size)
class infix_ostream_iterator if defined(__GNUC__) &&!defined(__clang__) &&(__GNUC__<
GCC9 currently hits a "no type named 'value_type'" error during build if this is removed and iterator...
neml2::VariableName parseVariableName(const std::string &)
Parse a raw string into NEML2 variable name.
std::size_t getBatchIndex(dof_id_type elem_id) const
Get the batch index for the given element ID.
neml2::ValueMap _in
The input variables of the material model.
neml2::ValueMap _retrieved_outputs
set of output variables that were retrieved (by other objects)
NEML2ModelExecutor(const InputParameters ¶ms)
virtual bool startedInitialSetup()
Returns true if we are in or beyond the initialSetup stage.
NEML2BatchIndexGenerator iterates over the mesh and generates a map from element ID to batch index wh...
const ExecFlagType EXEC_INITIAL