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);
173 Real nearest_max_distance = std::numeric_limits<Real>::max();
174 for (
const auto & bbox : bboxes)
177 if (
distance < nearest_max_distance)
181 unsigned int from0 = 0;
182 for (processor_id_type i_proc = 0; i_proc <
n_processors();
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)
250 Real nearest_max_distance = std::numeric_limits<Real>::max();
251 for (
const auto & bbox : bboxes)
254 if (
distance < nearest_max_distance)
258 unsigned int from0 = 0;
259 for (processor_id_type i_proc = 0; i_proc <
n_processors();
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)
363 const processor_id_type pid = qps.first;
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];
386 outgoing_evals[2 * qp] = std::numeric_limits<Real>::max();
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);
448 const processor_id_type pid = problem_from.first;
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 =
475 [&incoming_evals](processor_id_type pid,
const std::vector<Real> & evals)
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)
541 Real min_dist = std::numeric_limits<Real>::max();
542 for (
auto & evals : incoming_evals)
545 const processor_id_type pid = evals.first;
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++)
617 dof_id_type point_id = point_ids[offset];
621 Real min_dist = std::numeric_limits<Real>::max();
622 for (
auto & evals : incoming_evals)
624 const processor_id_type pid = evals.first;
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);