19#include "libmesh/elem.h"
20#include "libmesh/mesh_base.h"
21#include "libmesh/parallel_ghost_sync.h"
22#include <libmesh/int_range.h>
29 "displacement_x",
"displacement_y",
"displacement_z"};
38 "Actively displaces the selected mesh nodes by parsed expressions for the x, y, and z "
39 "displacement components, evaluated relative to each node's original position.");
41 params.
addParam<std::vector<BoundaryName>>(
42 "boundary", {},
"List of boundaries whose nodes are displaced");
43 params.
addParam<std::vector<SubdomainName>>(
46 "List of blocks whose nodes are displaced. If neither 'block' nor 'boundary' is specified, "
47 "all blocks in the mesh are used.");
49 params.
addParam<ParsedFunctionExpression>(
50 _disp_name[0],
"0",
"Parsed expression for the displacement in the x direction");
51 params.
addParam<ParsedFunctionExpression>(
52 _disp_name[1],
"0",
"Parsed expression for the displacement in the y direction");
53 params.
addParam<ParsedFunctionExpression>(
54 _disp_name[2],
"0",
"Parsed expression for the displacement in the z direction");
56 params.
addParam<std::vector<VariableName>>(
57 "coupled_variables", {},
"Nodal variables usable as symbols in the displacement expressions");
58 params.
addParam<std::vector<FunctionName>>(
59 "functions", {},
"Functions usable as symbols in the displacement expressions");
60 params.
addParam<std::vector<PostprocessorName>>(
61 "postprocessors", {},
"Postprocessors usable as symbols in the displacement expressions");
62 params.
addParam<std::vector<MooseFunctorName>>(
65 "Functors (e.g. functor material properties) usable as symbols in the displacement "
66 "expressions. They are evaluated at each node in its original (undisplaced) position.");
67 params.
addParam<std::vector<std::string>>(
70 "Symbolic name to use for each functor in 'functor_names' in the displacement expressions. "
71 "If not provided, then the actual functor names will be used.");
73 params.
addParam<std::vector<std::string>>(
74 "constant_names", {},
"Vector of constants used in the parsed function");
75 params.
addParam<std::vector<std::string>>(
76 "constant_expressions",
78 "Vector of values for the constants in constant_names (can be an FParser expression)");
82 params.
addParam<std::vector<AuxVariableName>>(
83 "original_coordinate_variables",
85 "If set, the original (undisplaced) node coordinates are written to these three nodal "
86 "auxiliary variables, given in x, y, z order, which must be created by the user.");
87 params.
addParam<std::vector<AuxVariableName>>(
88 "parsed_displacement_variables",
90 "If set, the current node displacement (current minus original position) is written to these "
91 "three nodal auxiliary variables, given in x, y, z order, which must be created by the "
94 "density_factor_variable",
96 "If set, the per-element density adjustment factor (original volume divided by current "
97 "volume) is written to this elemental aux variable, which must be created by the user.");
100 "notify_mesh_changed",
102 "Whether to notify the problem that the mesh has changed (by calling meshChanged) after the "
103 "nodes are moved, so that mesh-dependent caches, the displaced mesh, geometric searches, and "
104 "outputs are updated.");
117 _mesh(_subproblem.
mesh()),
118 _boundary_ids(_mesh.getBoundaryIDs(getParam<
std::vector<BoundaryName>>(
"boundary"))),
119 _subdomain_ids(_mesh.getSubdomainIDs(getParam<
std::vector<SubdomainName>>(
"block"))),
121 declareRestartableData<
std::unordered_map<dof_id_type, Point>>(
"original_position")),
123 !getParam<
std::vector<AuxVariableName>>(
"original_coordinate_variables").empty()),
124 _output_displacements(
125 !getParam<
std::vector<AuxVariableName>>(
"parsed_displacement_variables").empty()),
126 _output_density_factor(!getParam<AuxVariableName>(
"density_factor_variable").empty()),
128 _density_factor_var(0),
131 declareRestartableData<
std::unordered_map<dof_id_type, Real>>(
"original_volume")),
132 _original_volume_recorded(declareRestartableData<bool>(
"original_volume_recorded", false)),
133 _notify_mesh_changed(getParam<bool>(
"notify_mesh_changed"))
135 const auto & var_names = getParam<std::vector<VariableName>>(
"coupled_variables");
136 const auto & func_names = getParam<std::vector<FunctionName>>(
"functions");
137 const auto & pp_names = getParam<std::vector<PostprocessorName>>(
"postprocessors");
138 const auto & functor_names = getParam<std::vector<MooseFunctorName>>(
"functor_names");
139 const auto & functor_symbols = getParam<std::vector<std::string>>(
"functor_symbols");
141 if (!functor_symbols.empty() && functor_symbols.size() != functor_names.size())
142 paramError(
"functor_symbols",
"functor_symbols must be the same length as functor_names.");
145 std::vector<std::string> functor_syms;
146 for (
const auto i : index_range(functor_names))
147 functor_syms.push_back(functor_symbols.empty() ? std::string(functor_names[i])
148 : functor_symbols[i]);
153 auto add_symbol = [&symbols](
const std::string & s)
154 { symbols += (symbols.empty() ?
"" :
",") + s; };
156 for (
const auto &
name : var_names)
163 "' is not nodal. Only nodal variables can be used in the displacement "
168 for (
const auto &
name : func_names)
173 for (
const auto &
name : pp_names)
178 for (
const auto i : index_range(functor_names))
188 "' is a variable. Use 'coupled_variables' instead, which reads nodal values "
189 "safely in parallel.");
190 _functors.push_back(&getFunctor<Real>(functor_names[i]));
191 add_symbol(functor_syms[i]);
195 for (
const auto & reserved : {
"x",
"y",
"z",
"t"})
197 if (std::find(var_names.begin(), var_names.end(), reserved) != var_names.end() ||
198 std::find(func_names.begin(), func_names.end(), reserved) != func_names.end() ||
199 std::find(pp_names.begin(), pp_names.end(), reserved) != pp_names.end() ||
200 std::find(functor_syms.begin(), functor_syms.end(), reserved) != functor_syms.end())
203 "' is reserved for coordinates/time and cannot be used as a coupled variable, "
204 "function, postprocessor, or functor name.");
205 add_symbol(reserved);
208 const auto & constant_names = getParam<std::vector<std::string>>(
"constant_names");
209 const auto & constant_expressions = getParam<std::vector<std::string>>(
"constant_expressions");
210 for (
const auto i : make_range(3))
214 getParam<ParsedFunctionExpression>(
_disp_name[i]),
217 constant_expressions,
230 "original_coordinate_variables",
231 getParam<std::vector<AuxVariableName>>(
"original_coordinate_variables"),
236 "parsed_displacement_variables",
237 getParam<std::vector<AuxVariableName>>(
"parsed_displacement_variables"),
242 const auto name = getParam<AuxVariableName>(
"density_factor_variable");
245 "No auxiliary variable named '",
247 "' was found. Create an elemental (family = MONOMIAL, order = CONSTANT) auxiliary "
248 "variable with that name.");
254 "' must be an elemental variable (e.g. family = MONOMIAL, order = CONSTANT).");
262 const std::string & param_name,
263 const std::vector<AuxVariableName> & names,
264 std::vector<unsigned int> & var_numbers)
266 if (names.size() != 3)
268 "Exactly three variable names must be provided, for the x, y, and z components.");
270 for (
const auto &
name : names)
274 "No auxiliary variable named '",
276 "' was found. Create a nodal (e.g. LAGRANGE) auxiliary variable with that name.");
279 paramError(param_name,
"Auxiliary variable '",
name,
"' must be a nodal variable.");
280 var_numbers.push_back(var.
number());
294 false,
false,
false);
305 for (
const auto *
const elem :
_mesh.
getMesh().active_local_element_ptr_range())
329 if (Node *
const node =
mesh.query_node_ptr(node_id))
340 std::set<dof_id_type> displaced_nodes;
341 for (
auto *
const elem :
mesh.active_element_ptr_range())
343 if (!all_blocks && !subdomains.count(elem->subdomain_id()))
345 for (
auto & node : elem->node_ref_range())
346 if (displaced_nodes.insert(node.id()).second)
357 libMesh::Parallel::sync_dofobject_data_by_id(
358 mesh.comm(),
mesh.nodes_begin(),
mesh.nodes_end(), sync_positions);
369 const Point & ref = it->second;
374 if (owner_only && node.processor_id() !=
processor_id())
380 const auto sys_num = var->sys().number();
383 if (node.n_dofs(sys_num, var->number()) == 0)
386 "' has no degrees of freedom at node ",
388 ". All 'coupled_variables' must be defined on the blocks/boundaries being moved.");
389 const auto dof = node.dof_number(sys_num, var->number(), 0);
390 _func_params[k++] = (*var->sys().currentSolution())(dof);
405 for (
const auto *
const functor :
_functors)
413 for (
const auto i : make_range(3))
432 const Node *
const node =
mesh.query_node_ptr(node_id);
441 (*node)(i)-original(i));
447 for (
auto *
const elem :
mesh.active_local_element_ptr_range())
450 const Real factor = (v_new != 0.0) ?
_original_volume[elem->id()] / v_new : 1.0;
454 aux_solution.close();
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
registerMooseObject("MooseApp", MoveNodesByParsedExpressionModifier)
Real elementVolume(const Elem *elem) const
On-demand computation of volume element accounting for RZ/RSpherical.
A MultiMooseEnum object to hold "execute_on" flags.
AuxiliarySystem & getAuxiliarySystem()
virtual Assembly & assembly(const THREAD_ID tid, const unsigned int sys_num) override
virtual void meshChanged(bool intermediate_change, bool contract_mesh, bool clean_refinement_flags)
Update data after a mesh change.
const Function & getFunctionByName(const FunctionName &name) const
Get a function with a given name.
std::vector< GenericReal< is_ad > > _func_params
Array to stage the parameters passed to the functions when calling Eval.
void parsedFunctionSetup(SymFunctionPtr &function, const std::string &expression, const std::string &variables, const std::vector< std::string > &constant_names, const std::vector< std::string > &constant_expressions, const libMesh::Parallel::Communicator &comm) const
Performs setup steps on a SymFunction.
GenericReal< is_ad > evaluate(SymFunctionPtr &, const std::string &object_name="")
Evaluate FParser object and check EvalError.
static InputParameters validParams()
static InputParameters validParams()
const std::string & name() const
Get the name of the class.
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 ...
bool isParamSetByUser(const std::string &name) const
Test if the supplied parameter is set by a user, as opposed to not set or set to default.
const T & getParam(const std::string &name) const
Retrieve a parameter for the object.
MeshBase & getMesh()
Accessor for the underlying libMesh Mesh object.
const std::vector< dof_id_type > & getNodeList(boundary_id_type nodeset_id) const
Return a writable reference to a vector of node IDs that belong to nodeset_id.
unsigned int number() const
Get variable number coming from libMesh.
bool isNodal() const override
Is this variable nodal.
MeshModifier that actively displaces the selected nodes by three parsed expressions (x,...
std::unordered_map< dof_id_type, Point > & _original_position
Original (reference) position of each node, captured on first touch.
MooseMesh & _mesh
Reference to the current simulation mesh.
const bool _output_coordinates
Optional outputs, each enabled only when its parameter is provided.
const std::vector< SubdomainID > _subdomain_ids
Blocks whose nodes are displaced.
static InputParameters validParams()
SymFunctionPtr _displacement[3]
The three parsed displacement functions (x, y, z)
const std::vector< BoundaryID > _boundary_ids
Boundaries whose nodes are displaced.
const bool _output_displacements
std::vector< const PostprocessorValue * > _postprocessors
Postprocessor values referenced in the expressions, in symbol order.
unsigned int _aux_sys_num
Auxiliary system number (set when any output is enabled)
MoveNodesByParsedExpressionModifier(const InputParameters ¶meters)
void displaceNode(Node &node, bool owner_only)
Displace a single node by the parsed expressions, relative to its original position.
const bool _output_density_factor
std::vector< unsigned int > _coordinate_var
Aux variable numbers of the original-coordinate components (x, y, z)
std::vector< const Function * > _functions
Functions referenced in the expressions, in symbol order.
std::vector< const Moose::Functor< Real > * > _functors
Functors referenced in the expressions, in symbol order.
const bool _notify_mesh_changed
Whether to notify the problem that the mesh changed after moving nodes.
std::vector< const MooseVariable * > _coupled_vars
Coupled (nodal) variables referenced in the expressions, in symbol order.
unsigned int _density_factor_var
Aux variable number of the per-element density adjustment factor.
static const std::string _disp_name[3]
Parameter names of the three displacement expressions (x, y, z)
void setupNodalOutputVariables(const std::string ¶m_name, const std::vector< AuxVariableName > &names, std::vector< unsigned int > &var_numbers)
Validate a list of three nodal output aux variable names (exactly three, each existing and nodal) and...
void writeOutputs()
Write the optional original-coordinate, displacement, and density-factor aux variables.
bool & _original_volume_recorded
Whether the original element volumes have been recorded yet.
std::unordered_map< dof_id_type, Real > & _original_volume
Original (undisplaced) coordinate-aware element volumes, captured once.
Assembly * _assembly
Assembly used to compute coordinate-aware element volumes (density factor)
void moveNodes()
Displace all selected nodes (boundary/block restricted, or all blocks)
std::vector< unsigned int > _displacement_var
Aux variable numbers of the displacement components (x, y, z)
void prepare()
Capture the original element volumes (once) before moving any nodes.
virtual void execute() override
Execute method.
An interface for accessing Moose::Functors for systems that do not care about automatic differentiati...
static InputParameters validParams()
virtual const PostprocessorValue & getPostprocessorValueByName(const PostprocessorName &name) const
Retrieve the value of the Postprocessor.
virtual MooseVariable & getStandardVariable(const THREAD_ID tid, const std::string &var_name)=0
Returns the variable reference for requested MooseVariable which may be in any system.
virtual bool hasVariable(const std::string &var_name) const =0
Whether or not this problem has the variable.
unsigned int number() const
Gets the number of this system.
NumericVector< Number > & solution()
Moose::StateArg determineState() const
Create a functor state argument that corresponds to the implicit state of this object.
SubProblem & _subproblem
Reference to the Subproblem for this user object.
FEProblemBase & _fe_problem
Reference to the FEProblemBase for this user object.
const THREAD_ID _tid
Thread ID of this postprocessor.
processor_id_type processor_id() const
const Parallel::Communicator & comm() const
static constexpr std::size_t dim
This is the dimension of all vector and tensor datastructures used in MOOSE.
static const std::set< SubdomainID > undefined_subdomain_connection
A static member that can be used when the connection of a node to subdomains is unknown.