20 #include "libmesh/system.h" 21 #include "libmesh/mesh_tools.h" 22 #include "libmesh/id_types.h" 23 #include "libmesh/parallel_algebra.h" 24 #include "libmesh/dof_object.h" 36 "Transfer the value to the target domain from the nearest node in the source domain.");
40 "The boundary we are transferring from (if not specified, whole domain is used).");
41 params.
addParam<std::vector<BoundaryName>>(
43 "The boundary we are transferring to (if not specified, whole domain is used).");
44 params.
addParam<
bool>(
"fixed_meshes",
46 "Set to true when the meshes are not changing (ie, " 47 "no movement or adaptivity). This will cache " 48 "nearest node neighbors to greatly speed up the " 57 _fixed_meshes(getParam<bool>(
"fixed_meshes")),
58 _node_map(declareRestartableData<
std::map<
dof_id_type, Node *>>(
"node_map")),
60 _neighbors_cached(declareRestartableData<bool>(
"neighbors_cached", false)),
73 "MultiAppGeneralFieldNearestNodeTransfer instead and adapt the parameters");
76 paramError(
"variable",
" Support single to-variable only");
79 paramError(
"source_variable",
" Support single from-variable only");
86 "MultiAppNearestNodeTransfer::execute()", 5,
"Transferring variables based on nearest nodes");
89 std::vector<BoundingBox> bboxes;
94 const auto & sb = getParam<BoundaryName>(
"source_boundary");
96 paramError(
"source_boundary",
"The boundary '", sb,
"' was not found in the mesh");
124 std::map<processor_id_type, std::vector<Point>> outgoing_qps;
128 std::map<processor_id_type, std::map<std::pair<unsigned int, dof_id_type>,
dof_id_type>>
133 for (
unsigned int i_to = 0; i_to <
_to_problems.size(); i_to++)
136 unsigned int sys_num = to_sys->number();
137 unsigned int var_num = to_sys->variable_number(
_to_var_name);
138 MeshBase * to_mesh = &
_to_meshes[i_to]->getMesh();
139 const auto to_global_num =
142 auto & fe_type = to_sys->variable_type(var_num);
143 bool is_constant = fe_type.order ==
CONSTANT;
144 bool is_to_nodal = fe_type.family ==
LAGRANGE;
147 if (fe_type.order >
FIRST && !is_to_nodal)
148 mooseError(
"We don't currently support second order or higher elemental variable ");
152 "Setting a target boundary is only valid for receiving " 153 "variables of the LAGRANGE basis");
162 std::set<Node *> local_nodes_found;
164 for (
const auto & node : target_local_nodes)
167 if (node->n_dofs(sys_num, var_num) < 1)
170 const auto transformed_node = to_transform(*node);
174 for (
const auto & bbox : bboxes)
177 if (
distance < nearest_max_distance)
181 unsigned int from0 = 0;
183 from0 += froms_per_proc[i_proc], i_proc++)
185 for (
unsigned int i_from = from0; i_from < from0 + froms_per_proc[i_proc]; i_from++)
189 if (
distance <= nearest_max_distance ||
190 bboxes[i_from].contains_point(transformed_node))
192 std::pair<unsigned int, dof_id_type> key(i_to, node->id());
194 node_index_map[i_proc][key] = outgoing_qps[i_proc].size();
195 outgoing_qps[i_proc].push_back(transformed_node);
196 local_nodes_found.insert(node);
206 for (
const auto & node : target_local_nodes)
207 if (node->n_dofs(sys_num, var_num) && !local_nodes_found.count(node))
210 ": No candidate BoundingBoxes found for node ",
213 to_transform(*node));
220 std::set<Elem *> local_elems_found;
221 std::vector<Point> points;
222 std::vector<dof_id_type> point_ids;
223 for (
auto & elem :
as_range(to_mesh->local_elements_begin(), to_mesh->local_elements_end()))
226 if (elem->n_dofs(sys_num, var_num) < 1)
234 points.push_back(to_transform(elem->vertex_average()));
235 point_ids.push_back(elem->id());
240 for (
auto & node : elem->node_ref_range())
242 points.push_back(to_transform(node));
243 point_ids.push_back(node.id());
246 unsigned int offset = 0;
247 for (
auto & point : points)
251 for (
const auto & bbox : bboxes)
254 if (
distance < nearest_max_distance)
258 unsigned int from0 = 0;
260 from0 += froms_per_proc[i_proc], i_proc++)
262 for (
unsigned int i_from = from0; i_from < from0 + froms_per_proc[i_proc]; i_from++)
265 if (
distance <= nearest_max_distance || bboxes[i_from].contains_point(point))
267 std::pair<unsigned int, dof_id_type> key(
271 if (node_index_map[i_proc].find(key) != node_index_map[i_proc].end())
273 node_index_map[i_proc][key] = outgoing_qps[i_proc].size();
274 outgoing_qps[i_proc].push_back(point);
275 local_elems_found.insert(elem);
286 for (
auto & elem :
as_range(to_mesh->local_elements_begin(), to_mesh->local_elements_end()))
287 if (elem->n_dofs(sys_num, var_num) && !local_elems_found.count(elem))
290 ": No candidate BoundingBoxes found for Elem ",
293 to_transform(elem->vertex_average()));
307 std::map<processor_id_type, std::vector<Real>> incoming_evals;
311 std::map<processor_id_type, std::vector<Real>> processor_outgoing_evals;
319 std::vector<std::vector<std::pair<Point, DofObject *>>> local_entities(
322 std::vector<std::vector<unsigned int>> local_comps(froms_per_proc[
processor_id()]);
325 std::vector<std::reference_wrapper<MooseVariableFEBase>> _from_vars;
327 for (
unsigned int i_local_from = 0; i_local_from < froms_per_proc[
processor_id()];
332 auto & from_fe_type = from_var.
feType();
333 bool is_constant = from_fe_type.order ==
CONSTANT;
334 bool is_to_nodal = from_fe_type.family ==
LAGRANGE;
337 if (from_fe_type.order >
FIRST && !is_to_nodal)
338 mooseError(
"We don't currently support second order or higher elemental variable ");
340 _from_vars.emplace_back(from_var);
342 local_entities[i_local_from],
343 local_comps[i_local_from],
349 std::map<processor_id_type, std::vector<Point>> incoming_qps;
350 auto qps_action_functor = [&incoming_qps](
processor_id_type pid,
const std::vector<Point> & qps)
353 auto & incoming_qps_from_pid = incoming_qps[pid];
355 incoming_qps_from_pid.reserve(incoming_qps_from_pid.size() + qps.size());
356 std::copy(qps.begin(), qps.end(), std::back_inserter(incoming_qps_from_pid));
359 Parallel::push_parallel_vector_data(
comm(), outgoing_qps, qps_action_functor);
361 for (
auto & qps : incoming_qps)
368 froms.resize(qps.second.size());
372 dof_ids.resize(qps.second.size());
373 std::fill(dof_ids.begin(), dof_ids.end(), DofObject::invalid_id);
376 std::vector<Real> & outgoing_evals = processor_outgoing_evals[pid];
381 outgoing_evals.resize(2 * qps.second.size());
383 for (std::size_t qp = 0; qp < qps.second.size(); qp++)
385 const Point & qpt = qps.second[qp];
387 for (
unsigned int i_local_from = 0; i_local_from < froms_per_proc[
processor_id()];
391 System & from_sys = from_var.
sys().
system();
392 unsigned int from_sys_num = from_sys.number();
393 unsigned int from_var_num = from_sys.variable_number(from_var.
name());
394 const auto from_global_num =
398 for (
unsigned int i_node = 0; i_node < local_entities[i_local_from].size(); i_node++)
402 Real current_distance =
403 (qpt - from_transform(local_entities[i_local_from][i_node].first)).
norm();
412 if (current_distance < outgoing_evals[2 * qp])
415 if (local_entities[i_local_from][i_node].second->n_dofs(from_sys_num, from_var_num) >
418 dof_id_type from_dof = local_entities[i_local_from][i_node].second->dof_number(
419 from_sys_num, from_var_num, local_comps[i_local_from][i_node]);
427 outgoing_evals[2 * qp] = current_distance;
428 outgoing_evals[2 * qp + 1] = (*from_sys.solution)(from_dof);
449 std::vector<Real> & outgoing_evals = processor_outgoing_evals[pid];
450 outgoing_evals.resize(problem_from.second.size());
452 for (
unsigned int qp = 0; qp < outgoing_evals.size(); qp++)
454 const auto from_problem = problem_from.second[qp];
458 "The state of the from problem and dof id should match.");
467 System & from_sys = from_var.
sys().
system();
469 outgoing_evals[qp] = (*from_sys.solution)(from_dof);
474 auto evals_action_functor =
478 auto & incoming_evals_for_pid = incoming_evals[pid];
480 incoming_evals_for_pid.reserve(incoming_evals_for_pid.size() + evals.size());
481 std::copy(evals.begin(), evals.end(), std::back_inserter(incoming_evals_for_pid));
484 Parallel::push_parallel_vector_data(
comm(), processor_outgoing_evals, evals_action_functor);
491 for (
unsigned int i_to = 0; i_to <
_to_problems.size(); i_to++)
496 unsigned int sys_num = to_sys->number();
497 unsigned int var_num = to_sys->variable_number(
_to_var_name);
499 NumericVector<Real> * solution =
nullptr;
506 solution = to_sys->solution.get();
512 const MeshBase & to_mesh =
_to_meshes[i_to]->getMesh();
514 auto & fe_type = to_sys->variable_type(var_num);
515 bool is_constant = fe_type.order ==
CONSTANT;
516 bool is_to_nodal = fe_type.family ==
LAGRANGE;
519 if (fe_type.order >
FIRST && !is_to_nodal)
520 mooseError(
"We don't currently support second order or higher elemental variable ");
526 for (
const auto & node : target_local_nodes)
529 if (node->n_dofs(sys_num, var_num) < 1)
542 for (
auto & evals : incoming_evals)
546 std::pair<unsigned int, dof_id_type> key(i_to, node->id());
547 if (node_index_map[pid].find(key) == node_index_map[pid].end())
549 unsigned int qp_ind = node_index_map[pid][key];
551 if (evals.second[2 * qp_ind] >= min_dist)
556 min_dist = evals.second[2 * qp_ind];
557 best_val = evals.second[2 * qp_ind + 1];
574 dof_id_type dof = node->dof_number(sys_num, var_num, 0);
575 solution->set(dof, best_val);
580 std::vector<Point> points;
581 std::vector<dof_id_type> point_ids;
582 for (
auto & elem : to_mesh.active_local_element_ptr_range())
585 if (elem->n_dofs(sys_num, var_num) < 1)
594 points.push_back(elem->vertex_average());
595 point_ids.push_back(elem->id());
601 for (
auto & node : elem->node_ref_range())
603 points.push_back(node);
604 point_ids.push_back(node.id());
607 unsigned int n_comp = elem->n_comp(sys_num, var_num);
609 if (points.size() != n_comp)
612 " does not equal to number of variable components ",
615 for (MooseIndex(points) offset = 0; offset < points.size(); offset++)
622 for (
auto & evals : incoming_evals)
626 std::pair<unsigned int, dof_id_type> key(i_to, point_id);
627 if (node_index_map[pid].find(key) == node_index_map[pid].end())
630 unsigned int qp_ind = node_index_map[pid][key];
631 if (evals.second[2 * qp_ind] >= min_dist)
634 min_dist = evals.second[2 * qp_ind];
635 best_val = evals.second[2 * qp_ind + 1];
650 dof_id_type dof = elem->dof_number(sys_num, var_num, offset);
651 solution->set(dof, best_val);
668 std::array<Point, 2> source_points = {{bbox.first, bbox.second}};
670 std::array<Point, 8> all_points;
671 for (
unsigned int x = 0; x < 2; x++)
672 for (
unsigned int y = 0; y < 2; y++)
673 for (
unsigned int z = 0; z < 2; z++)
674 all_points[x + 2 * y + 4 * z] =
675 Point(source_points[x](0), source_points[y](1), source_points[z](2));
677 Real max_distance = 0.;
679 for (
unsigned int i = 0; i < 8; i++)
692 std::array<Point, 2> source_points = {{bbox.first, bbox.second}};
694 std::array<Point, 8> all_points;
695 for (
unsigned int x = 0; x < 2; x++)
696 for (
unsigned int y = 0; y < 2; y++)
697 for (
unsigned int z = 0; z < 2; z++)
698 all_points[x + 2 * y + 4 * z] =
699 Point(source_points[x](0), source_points[y](1), source_points[z](2));
703 for (
unsigned int i = 0; i < 8; i++)
716 std::vector<std::pair<Point, DofObject *>> & local_entities,
717 std::vector<unsigned int> & local_comps,
721 mooseAssert(
mesh,
"mesh should not be a nullptr");
722 mooseAssert(local_entities.empty(),
"local_entities should be empty");
723 MeshBase & mesh_base =
mesh->getMesh();
727 const auto & sb = getParam<BoundaryName>(
"source_boundary");
730 paramError(
"source_boundary",
"The boundary '", sb,
"' was not found in the mesh");
735 for (
const auto & bnode : bnd_nodes)
737 unsigned int comp = 0;
738 if (bnode->_bnd_id == src_bnd_id &&
739 bnode->_node->processor_id() == mesh_base.processor_id())
741 local_entities.emplace_back(*bnode->_node, bnode->_node);
742 local_comps.push_back(comp++);
749 for (
const auto & belem : bnd_elems)
751 unsigned int comp = 0;
752 if (belem->_bnd_id == src_bnd_id &&
753 belem->_elem->processor_id() == mesh_base.processor_id())
758 local_entities.emplace_back(belem->_elem->vertex_average(), belem->_elem);
759 local_comps.push_back(comp++);
764 for (
auto & node : belem->_elem->node_ref_range())
766 local_entities.emplace_back(node, belem->_elem);
767 local_comps.push_back(comp++);
778 local_entities.reserve(mesh_base.n_local_nodes());
779 for (
auto & node : mesh_base.local_node_ptr_range())
781 unsigned int comp = 0;
782 local_entities.emplace_back(*node, node);
783 local_comps.push_back(comp++);
788 local_entities.reserve(mesh_base.n_local_elem());
789 for (
auto & elem : mesh_base.active_local_element_ptr_range())
791 unsigned int comp = 0;
795 local_entities.emplace_back(elem->vertex_average(), elem);
796 local_comps.push_back(comp++);
801 for (
auto & node : elem->node_ref_range())
803 local_entities.emplace_back(node, elem);
804 local_comps.push_back(comp++);
812 const std::vector<Node *> &
816 MeshBase & to_mesh =
_to_meshes[to_problem_id]->getMesh();
820 const std::vector<BoundaryName> & target_boundaries =
821 getParam<std::vector<BoundaryName>>(
"target_boundary");
822 for (
const auto & b : target_boundaries)
824 paramError(
"target_boundary",
"The boundary '", b,
"' was not found in the mesh");
828 for (
const auto & t : target_boundaries)
832 for (
const auto & bnode : bnd_nodes)
833 if (bnode->_bnd_id == target_bnd_id &&
834 bnode->_node->processor_id() ==
_to_meshes[to_problem_id]->processor_id())
842 for (
auto & node : to_mesh.local_node_ptr_range())
NumericVector< Real > & getTransferVector(unsigned int i_local, std::string var_name)
If we are transferring to a multiapp, return the appropriate solution vector.
std::map< std::pair< unsigned int, dof_id_type >, unsigned int > & _cached_from_inds
std::vector< std::unique_ptr< MultiAppCoordTransform > > _to_transforms
const unsigned int invalid_uint
void mooseDeprecated(Args &&... args) const
bool hasBoundaryName(const MeshBase &input_mesh, const BoundaryName &name)
Whether a particular boundary name exists in the mesh.
MultiAppNearestNodeTransfer(const InputParameters ¶meters)
MooseEnum _current_direction
const BoundaryID INVALID_BOUNDARY_ID
AuxVariableName _to_var_name
Real bboxMaxDistance(const Point &p, const BoundingBox &bbox)
Return the distance between the given point and the farthest corner of the given bounding box...
registerMooseObjectDeprecated("MooseApp", MultiAppNearestNodeTransfer, "12/31/2024 24:00")
StoredRange< MooseMesh::const_bnd_elem_iterator, const BndElement * > ConstBndElemRange
std::vector< EquationSystems * > _to_es
const std::vector< Node * > & getTargetLocalNodes(const unsigned int to_problem_id)
Get the local nodes on the target boundary for the transfer.
std::vector< BoundingBox > getFromBoundingBoxes()
Return the bounding boxes of all the "from" domains, including all the domains not local to this proc...
const std::vector< VariableName > _from_var_names
Name of variables transferring from.
std::vector< FEProblemBase * > _to_problems
const std::string & name() const override
Get the variable name.
std::vector< Node * > _target_local_nodes
Target local nodes for receiving a nodal variable.
const Parallel::Communicator & comm() const
virtual void postExecute()
Add some extra work if necessary after execute().
This class provides an interface for common operations on field variables of both FE and FV types wit...
Real bboxMinDistance(const Point &p, const BoundingBox &bbox)
Return the distance between the given point and the nearest corner of the given bounding box...
Real distance(const Point &p)
virtual const std::string & name() const
Get the name of the class.
const FEType & feType() const
Get the type of finite element object.
Copy the value to the target domain from the nearest node in the source domain.
auto max(const L &left, const R &right)
std::vector< unsigned int > _to_local2global_map
Given local app index, returns global app index.
virtual void execute() override
Execute the transfer.
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
std::map< processor_id_type, std::vector< dof_id_type > > & _cached_dof_ids
BoundaryID getBoundaryID(const BoundaryName &boundary_name, const MeshBase &mesh)
Gets the boundary ID associated with the given BoundaryName.
uint8_t processor_id_type
processor_id_type n_processors() const
std::vector< MooseMesh * > _from_meshes
boundary_id_type BoundaryID
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
const std::vector< AuxVariableName > _to_var_names
Name of variables transferring to.
MooseMesh wraps a libMesh::Mesh object and enhances its capabilities by caching additional data and s...
std::vector< unsigned int > getFromsPerProc()
Return the number of "from" domains that each processor owns.
Transfers variables on possibly different meshes while conserving a user defined property (Postproces...
std::map< processor_id_type, std::vector< unsigned int > > & _cached_froms
virtual System & system()=0
Get the reference to the libMesh system.
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 ...
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
std::vector< std::unique_ptr< MultiAppCoordTransform > > _from_transforms
std::vector< unsigned int > _from_local2global_map
Given local app index, returns global app index.
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type.
static InputParameters validParams()
static void addBBoxFactorParam(InputParameters ¶ms)
Add the bounding box factor parameter to the supplied input parameters.
static InputParameters validParams()
void paramWarning(const std::string ¶m, Args... args) const
Emits a warning prefixed with the file and line number of the given param (from the input file) along...
static System * find_sys(EquationSystems &es, const std::string &var_name)
Small helper function for finding the system containing the variable.
StoredRange< MooseMesh::const_bnd_node_iterator, const BndNode * > ConstBndNodeRange
Some useful StoredRange typedefs.
processor_id_type processor_id() const
SystemBase & sys()
Get the system this variable is part of.
void getLocalEntitiesAndComponents(MooseMesh *mesh, std::vector< std::pair< Point, DofObject *>> &local_entities, std::vector< unsigned int > &local_comps, bool nodal, bool constant)
Get nearest node candidates.
std::map< std::pair< unsigned int, dof_id_type >, unsigned int > & _cached_qp_inds
std::vector< FEProblemBase * > _from_problems
void ErrorVector unsigned int
bool _fixed_meshes
If true then node connections will be cached.
std::vector< MooseMesh * > _to_meshes
VariableName _from_var_name
This values are used if a derived class only supports one variable.