21 #include "libmesh/parallel_algebra.h" 22 #include "libmesh/meshfree_interpolation.h" 23 #include "libmesh/system.h" 24 #include "libmesh/radial_basis_interpolation.h" 30 MultiAppInterpolationTransfer,
39 "Transfers the value to the target domain from a combination/interpolation of the values on " 40 "the nearest nodes in the source domain, using coefficients based on the distance to each " 43 "num_points", 3,
"The number of nearest points to use for interpolation.");
45 "power", 2,
"The polynomial power to use for calculation of the decay in the interpolation.");
47 MooseEnum interp_type(
"inverse_distance radial_basis",
"inverse_distance");
48 params.
addParam<
MooseEnum>(
"interp_type", interp_type,
"The algorithm to use for interpolation.");
52 "Radius to use for radial_basis interpolation. If negative " 53 "then the radius is taken as the max distance between " 58 "gap width with which we want to temporarily shrink mesh in transfering solution");
60 MooseEnum shrink_type(
"SOURCE TARGET",
"SOURCE");
61 params.
addParam<
MooseEnum>(
"shrink_mesh", shrink_type,
"Which mesh we want to shrink");
63 params.
addParam<std::vector<SubdomainName>>(
66 "Gap subdomains we want to exclude when constructing/using virtually translated points");
70 "If the distance between two points is smaller than distance_tol, two " 71 "points will be considered as identical");
79 _num_points(getParam<unsigned
int>(
"num_points")),
80 _power(getParam<
Real>(
"power")),
81 _interp_type(getParam<
MooseEnum>(
"interp_type")),
82 _radius(getParam<
Real>(
"radius")),
83 _shrink_gap_width(getParam<
Real>(
"shrink_gap_width")),
84 _shrink_mesh(getParam<
MooseEnum>(
"shrink_mesh")),
85 _exclude_gap_blocks(getParam<
std::vector<SubdomainName>>(
"exclude_gap_blocks")),
86 _distance_tol(getParam<
Real>(
"distance_tol"))
92 paramError(
"variable",
" Support single to-variable only ");
95 paramError(
"source_variable",
" Support single from-variable only ");
101 std::set<subdomain_id_type> & subdomainids)
106 auto & node_to_elem =
mesh.nodeToElemMap();
107 auto node_to_elem_pair = node_to_elem.find(node.
id());
109 if (node_to_elem_pair == node_to_elem.end())
110 mooseError(
"Can not find elements for node ", node.
id());
112 subdomainids.clear();
114 for (
auto element : node_to_elem_pair->second)
119 subdomainids.insert(subdomain);
131 const auto & from_mesh = from_moose_mesh.
getMesh();
139 auto from_sys_num = from_sys.
number();
145 bool from_is_nodal = fe_type.family ==
LAGRANGE;
148 if (fe_type.order >
FIRST && !from_is_nodal)
149 mooseError(
"We don't currently support second order or higher elemental variable ");
153 std::vector<Point> & src_pts(idi->get_source_points());
154 std::vector<Number> & src_vals(idi->get_source_vals());
157 std::unordered_map<dof_id_type, Point> from_tranforms;
158 std::set<subdomain_id_type> exclude_block_ids;
163 exclude_block_ids.insert(exclude_subdomainids.begin(), exclude_subdomainids.end());
169 std::set<subdomain_id_type> subdomainids;
170 std::vector<subdomain_id_type> include_block_ids;
173 for (
const auto *
const from_node : from_mesh.local_node_ptr_range())
176 if (from_node->n_comp(from_sys_num, from_var_num) == 0)
181 if (from_tranforms.size() > 0)
183 subdomainIDsNode(const_cast<MooseMesh &>(from_moose_mesh), *from_node, subdomainids);
186 include_block_ids.clear();
187 include_block_ids.resize(
std::max(subdomainids.size(), exclude_block_ids.size()));
188 auto it = std::set_difference(subdomainids.begin(),
190 exclude_block_ids.begin(),
191 exclude_block_ids.end(),
192 include_block_ids.begin());
194 include_block_ids.resize(it - include_block_ids.begin());
196 if (include_block_ids.size())
197 translate = from_tranforms[*include_block_ids.begin()];
203 dof_id_type from_dof = from_node->dof_number(from_sys_num, from_var_num, 0);
204 src_vals.push_back(from_solution(from_dof));
205 src_pts.push_back(from_app_transform(*from_node) +
translate);
210 std::vector<Point> points;
211 for (
const auto *
const from_elem :
212 as_range(from_mesh.local_elements_begin(), from_mesh.local_elements_end()))
215 if (from_elem->n_dofs(from_sys_num, from_var_num) < 1)
219 if (from_is_constant)
220 points.push_back(from_elem->vertex_average());
222 for (
const auto & node : from_elem->node_ref_range())
223 points.push_back(node);
225 unsigned int n_comp = from_elem->n_comp(from_sys_num, from_var_num);
226 auto n_points = points.size();
228 if (n_points != n_comp)
231 " does not equal to number of variable components ",
234 unsigned int offset = 0;
238 if (from_tranforms.size() > 0)
240 auto subdomain = from_elem->subdomain_id();
243 mooseError(
"subdomain id does not make sense", subdomain);
246 if (exclude_block_ids.find(subdomain) == exclude_block_ids.end())
252 for (
const auto & point : points)
254 dof_id_type from_dof = from_elem->dof_number(from_sys_num, from_var_num, offset++);
255 src_vals.push_back(from_solution(from_dof));
256 src_pts.push_back(from_app_transform(point) +
translate);
276 auto to_sys_num = to_sys.
number();
283 std::unordered_map<dof_id_type, Point> to_tranforms;
284 std::set<subdomain_id_type> exclude_block_ids;
289 exclude_block_ids.insert(exclude_subdomainids.begin(), exclude_subdomainids.end());
294 bool to_is_nodal = to_fe_type.family ==
LAGRANGE;
296 if (to_fe_type.order >
FIRST && !to_is_nodal)
297 mooseError(
"We don't currently support second order or higher elemental variable ");
299 std::set<subdomain_id_type> subdomainids;
300 std::vector<subdomain_id_type> include_block_ids;
301 std::vector<Point> pts;
302 std::vector<Number> vals;
305 for (
const auto *
const node : to_mesh.local_node_ptr_range())
307 if (node->n_dofs(to_sys_num, to_var_num) <= 0)
311 if (to_tranforms.size() > 0)
313 subdomainIDsNode(const_cast<MooseMesh &>(to_moose_mesh), *node, subdomainids);
316 include_block_ids.clear();
317 include_block_ids.resize(
std::max(subdomainids.size(), exclude_block_ids.size()));
318 auto it = std::set_difference(subdomainids.begin(),
320 exclude_block_ids.begin(),
321 exclude_block_ids.end(),
322 include_block_ids.begin());
323 include_block_ids.resize(it - include_block_ids.begin());
324 if (include_block_ids.size())
325 translate = to_tranforms[*include_block_ids.begin()];
331 pts.push_back(to_app_transform(*node) +
translate);
335 dof_id_type dof = node->dof_number(to_sys_num, to_var_num, 0);
336 to_solution.
set(dof, vals.front());
341 std::vector<Point> points;
342 for (
const auto *
const elem :
343 as_range(to_mesh.local_elements_begin(), to_mesh.local_elements_end()))
346 if (elem->n_dofs(to_sys_num, to_var_num) < 1)
351 points.push_back(elem->vertex_average());
353 for (
const auto & node : elem->node_ref_range())
354 points.push_back(node);
356 auto n_points = points.size();
357 unsigned int n_comp = elem->n_comp(to_sys_num, to_var_num);
359 if (n_points != n_comp)
362 " does not equal to number of variable components ",
367 if (to_tranforms.size() > 0)
369 auto subdomain = elem->subdomain_id();
372 mooseError(
"subdomain id does not make sense", subdomain);
374 if (exclude_block_ids.find(subdomain) == exclude_block_ids.end())
380 unsigned int offset = 0;
381 for (
const auto & point : points)
384 pts.push_back(to_app_transform(point) +
translate);
388 dof_id_type dof = elem->dof_number(to_sys_num, to_var_num, offset++);
389 to_solution.
set(dof, vals.front());
401 TIME_SECTION(
"MultiAppGeometricInterpolationTransfer::execute()",
403 "Transferring variables based on node interpolation");
407 std::unique_ptr<InverseDistanceInterpolation<LIBMESH_DIM>> idi;
411 idi = std::make_unique<InverseDistanceInterpolation<LIBMESH_DIM>>(
415 idi = std::make_unique<RadialBasisInterpolation<LIBMESH_DIM>>(fe_problem.
comm(),
_radius);
435 idi->prepare_for_use();
437 for (
unsigned int i = 0; i <
getToMultiApp()->numGlobalApps(); i++)
443 auto & to_var = to_problem.getVariable(0,
465 const auto & from_var = from_problem.getVariable(0,
474 idi->prepare_for_use();
497 const MooseMesh & mesh, std::unordered_map<dof_id_type, Point> & transformation)
499 auto & libmesh_mesh =
mesh.getMesh();
501 auto & subdomainids =
mesh.meshSubdomains();
506 for (
auto subdomain_id : subdomainids)
508 max_subdomain_id = max_subdomain_id > subdomain_id ? max_subdomain_id : subdomain_id;
511 max_subdomain_id += 1;
513 std::unordered_map<dof_id_type, Point> subdomain_centers;
514 std::unordered_map<dof_id_type, dof_id_type> nelems;
517 as_range(libmesh_mesh.local_elements_begin(), libmesh_mesh.local_elements_end()))
520 subdomain_centers[max_subdomain_id] += elem->vertex_average();
521 nelems[max_subdomain_id] += 1;
523 auto subdomain = elem->subdomain_id();
529 subdomain_centers[subdomain] += elem->vertex_average();
531 nelems[subdomain] += 1;
538 subdomain_centers[max_subdomain_id] /= nelems[max_subdomain_id];
540 for (
auto subdomain_id : subdomainids)
542 subdomain_centers[subdomain_id] /= nelems[subdomain_id];
547 transformation.clear();
548 for (
auto subdomain_id : subdomainids)
550 transformation[subdomain_id] =
551 subdomain_centers[max_subdomain_id] - subdomain_centers[subdomain_id];
553 auto norm = transformation[subdomain_id].norm();
558 transformation[subdomain_id] /=
norm;
std::vector< std::unique_ptr< MultiAppCoordTransform > > _to_transforms
void interpolateTargetPoints(FEProblemBase &to_problem, MooseVariableFieldBase &to_var, NumericVector< Real > &to_solution, const MultiAppCoordTransform &to_app_transform, const std::unique_ptr< libMesh::InverseDistanceInterpolation< Moose::dim >> &idi)
const std::shared_ptr< MultiApp > getFromMultiApp() const
Get the MultiApp to transfer data from.
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 ...
MooseEnum _current_direction
AuxVariableName _to_var_name
Interpolate variable values using geometry/mesh-based coefficients.
virtual libMesh::System & system()=0
Get the reference to the libMesh system.
const std::vector< VariableName > _from_var_names
Name of variables transferring from.
const Parallel::Communicator & comm() const
FEProblemBase & _fe_problem
const std::shared_ptr< MultiApp > getToMultiApp() const
Get the MultiApp to transfer data to.
This class provides an interface for common operations on field variables of both FE and FV types wit...
The following methods are specializations for using the libMesh::Parallel::packed_range_* routines fo...
Base class for a system (of equations)
bool hasFromMultiApp() const
Whether the transfer owns a non-null from_multi_app.
Specialization of SubProblem for solving nonlinear equations plus auxiliary equations.
std::vector< SubdomainID > getSubdomainIDs(const std::vector< SubdomainName > &subdomain_names) const
Get the associated subdomainIDs for the subdomain names that are passed in.
virtual const MooseVariableFieldBase & getVariable(const THREAD_ID tid, const std::string &var_name, Moose::VarKindType expected_var_type=Moose::VarKindType::VAR_ANY, Moose::VarFieldType expected_var_field_type=Moose::VarFieldType::VAR_FIELD_ANY) const override
Returns the variable reference for requested variable which must be of the expected_var_type (Nonline...
auto max(const L &left, const R &right)
unsigned int variable_number(std::string_view var) const
bool _displaced_target_mesh
True if displaced mesh is used for the target mesh, otherwise false.
const SubdomainID INVALID_BLOCK_ID
void errorIfDistributedMesh(std::string name) const
Generate a unified error message if the underlying libMesh mesh is a DistributedMesh.
unsigned int number() const
registerMooseObjectRenamed("MooseApp", MultiAppInterpolationTransfer, "12/31/2023 24:00", MultiAppGeometricInterpolationTransfer)
const std::string & name() const
Get the name of the class.
MeshBase & getMesh()
Accessor for the underlying libMesh Mesh object.
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
const std::vector< AuxVariableName > _to_var_names
Name of variables transferring to.
std::unique_ptr< NumericVector< Number > > solution
MooseMesh wraps a libMesh::Mesh object and enhances its capabilities by caching additional data and s...
registerMooseObject("MooseApp", MultiAppGeometricInterpolationTransfer)
void computeTransformation(const MooseMesh &mesh, std::unordered_map< dof_id_type, Point > &transformation)
Transfers variables on possibly different meshes while conserving a user defined property (Postproces...
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
void fillSourceInterpolationPoints(FEProblemBase &from_problem, const MooseVariableFieldBase &from_var, const MultiAppCoordTransform &from_app_transform, std::unique_ptr< libMesh::InverseDistanceInterpolation< Moose::dim >> &idi)
const FEType & variable_type(const unsigned int i) const
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
subdomain_id_type subdomain_id() const
virtual const Elem & elem_ref(const dof_id_type i) const
std::vector< std::unique_ptr< MultiAppCoordTransform > > _from_transforms
MultiAppGeometricInterpolationTransfer(const InputParameters ¶meters)
virtual MooseMesh & mesh() override
bool _displaced_source_mesh
True if displaced mesh is used for the source mesh, otherwise false.
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type and optionally a file path to the top-level block p...
static InputParameters validParams()
void subdomainIDsNode(MooseMesh &mesh, const Node &node, std::set< subdomain_id_type > &subdomainids)
virtual void set(const numeric_index_type i, const T value)=0
SystemBase & sys()
Get the system this variable is part of.
void ErrorVector unsigned int
static InputParameters validParams()
std::vector< SubdomainName > _exclude_gap_blocks
virtual void execute() override
Execute the transfer.
VariableName _from_var_name
This values are used if a derived class only supports one variable.