12#ifdef MOOSE_LIBTORCH_ENABLED
27 params.
addClassDescription(
"Evaluates a TorchScript model that returns sampled one-dimensional "
28 "profiles and exposes those profiles as interpolated Real functors.");
31 "torch_script_userobject",
32 "TorchScriptUserObject containing the deployed TorchScript model.");
34 params.
addParam<std::vector<PostprocessorName>>(
37 "Ordered postprocessor values passed to the model. Specify either "
38 "input_names or input_values, but not both.");
43 "Ordered constant values passed directly to the model. Specify either "
44 "input_names or input_values, but not both.");
48 "Names assigned to model output channels. The number of names must "
49 "equal the model output channel count.");
52 "profile_coordinates",
53 "Strictly increasing coordinates corresponding to the model output "
57 "Physical point corresponding to profile coordinate zero.");
61 "Physical direction of increasing profile coordinate. The direction "
62 "is normalized internally.");
65 "coordinate_scale", 1.0,
"Physical distance corresponding to one model-coordinate unit.");
68 MooseEnum(
"error clamp extrapolate",
"error"),
69 "Behavior when a MOOSE evaluation point lies outside the supplied "
70 "profile coordinate range.");
74 "Floating-point type expected by the TorchScript model.");
86 "When the TorchScript model is (re-)evaluated to rebuild the profiles. " +
87 execute_options.getDocString());
96 _input_names(getParam<
std::vector<PostprocessorName>>(
"input_names")),
97 _input_values(getParam<
std::vector<Real>>(
"input_values")),
98 _profile_names(getParam<
std::vector<MooseFunctorName>>(
"profile_names")),
99 _profile_coordinates(getParam<
std::vector<Real>>(
"profile_coordinates")),
100 _profile_origin(getParam<Point>(
"profile_origin")),
101 _profile_direction(getParam<RealVectorValue>(
"profile_direction")),
102 _coordinate_scale(getParam<Real>(
"coordinate_scale")),
103 _out_of_range_behavior(getParam<
MooseEnum>(
"out_of_range_behavior")),
104 _tensor_dtype(getParam<
MooseEnum>(
"tensor_dtype")),
105 _profile_update_schedule(_execute_enum.begin(), _execute_enum.end())
107 const bool using_postprocessors = !
_input_names.empty();
110 if (using_postprocessors == using_constants)
111 paramError(
"input_names",
"Specify exactly one of input_names or input_values.");
114 paramError(
"profile_names",
"At least one output profile name is required.");
117 paramError(
"profile_coordinates",
"At least one profile coordinate is required.");
122 paramError(
"profile_coordinates",
"All profile coordinates must be finite.");
125 paramError(
"profile_coordinates",
"Profile coordinates must be strictly increasing.");
129 paramError(
"coordinate_scale",
"coordinate_scale must be finite and greater than zero.");
133 if (!std::isfinite(direction_norm) || direction_norm <= 0.0)
134 paramError(
"profile_direction",
"profile_direction must be finite and nonzero.");
138 if (using_postprocessors)
145 addFunctorProperty<Real>(
147 [
this, profile_index](
const auto & spatial_arg,
const auto &) -> Real
148 {
return sampleProfile(profile_index, spatial_arg.getPoint()); },
167 for (
const auto i : index_range(
values))
168 if (!std::isfinite(
values[i]))
169 mooseError(
"TorchScript1DProfileFunctorMaterial '",
171 "' received non-finite model input ",
176 auto input = torch::from_blob(
values.data(),
177 {1, static_cast<std::int64_t>(values.size())},
178 torch::TensorOptions().dtype(torch::kFloat64).device(torch::kCPU))
182 input = input.to(torch::kFloat32);
190 torch::Tensor output;
194 torch::NoGradGuard no_grad;
202 catch (
const c10::Error & error)
204 mooseError(
"TorchScript inference failed in ",
name(),
":\n", error.what());
206 catch (
const std::exception & error)
208 mooseError(
"TorchScript inference failed in ",
name(),
":\n", error.what());
218 if (output.dim() == 1)
223 " returned a one-dimensional tensor, but ",
225 " profile names were requested.");
227 output = output.unsqueeze(0);
229 else if (output.dim() == 3)
231 if (output.size(0) != 1)
234 " returned a three-dimensional tensor whose batch dimension is ",
236 ". Only a batch size of one is supported.");
238 output = output.squeeze(0);
241 if (output.dim() != 2)
244 " must return [N], [C,N], or [1,C,N]. Received a tensor with ",
248 const auto expected_channels =
static_cast<std::int64_t
>(
_profile_names.size());
252 if (output.size(0) != expected_channels)
254 "TorchScript model in ",
258 " profile channels, but profile_names contains ",
262 if (output.size(1) != expected_stations)
264 "TorchScript model in ",
268 " stations per profile, but profile_coordinates contains ",
272 const auto output_values = output.accessor<double, 2>();
280 values[station] = output_values[channel][station];
282 if (!std::isfinite(
values[station]))
285 " returned a non-finite value for profile '",
299 catch (
const std::exception & error)
301 mooseError(
"Failed to construct profile interpolator '",
326 const Point & point)
const
329 mooseError(
"Invalid profile index ", profile_index,
" requested from ",
name(),
".");
334 "' was evaluated before TorchScript inference completed.");
338 if (!std::isfinite(coordinate))
339 mooseError(
"A non-finite spatial coordinate was calculated while evaluating "
352 "] while evaluating profile '",
366 return _profiles[profile_index]->sample(coordinate);
const ExecFlagType EXEC_TIMESTEP_BEGIN
const ExecFlagType EXEC_INITIAL
std::array< Real, 2 > values
registerMooseObject("NavierStokesApp", TorchScript1DProfileFunctorMaterial)
void addAvailableFlags(const ExecFlagType &flag, Args... flags)
static InputParameters validParams()
torch::DeviceType getLibtorchDevice() const
const std::string & name() const
void paramError(const std::string ¶m, Args... args) const
void mooseError(Args &&... args) const
virtual const PostprocessorValue & getPostprocessorValueByName(const PostprocessorName &name) const
Evaluates a TorchScript model on the schedule given by the execute_on parameter (default: once,...
const std::vector< PostprocessorName > _input_names
Postprocessor-based model inputs.
static InputParameters validParams()
void updateProfiles()
Evaluate the TorchScript model once and (re)build every profile interpolator in _profiles.
const TorchScriptUserObject & _torch_script_userobject
Existing MOOSE object that owns and evaluates the TorchScript module.
const MooseEnum _tensor_dtype
float32 or float64
const std::vector< Real > _profile_coordinates
Coordinates at which the model output values are defined.
const std::vector< MooseFunctorName > _profile_names
Names assigned to the output profile functors.
RealVectorValue _profile_direction
Unit direction of increasing profile coordinate.
const Point _profile_origin
Physical origin of the one-dimensional profile coordinate.
virtual void timestepSetup() override
std::vector< const PostprocessorValue * > _postprocessor_inputs
References to postprocessor values, populated when input_names is used.
virtual void initialSetup() override
const std::set< ExecFlagType > _profile_update_schedule
Execute flags on which updateProfiles() re-runs inference.
TorchScript1DProfileFunctorMaterial(const InputParameters ¶meters)
const MooseEnum _out_of_range_behavior
error, clamp, or extrapolate
Real sampleProfile(unsigned int profile_index, const Point &point) const
Evaluate a cached profile at a physical point.
const Real _coordinate_scale
Physical distance corresponding to one profile-coordinate unit.
torch::Tensor buildInputTensor() const
Construct the model input tensor.
const std::vector< Real > _input_values
Direct constant model inputs.
std::vector< std::unique_ptr< LinearInterpolation > > _profiles
Cached interpolator for each model output channel.
torch::Tensor evaluate(const torch::Tensor &input) const