Line data Source code
1 : //* This file is part of the MOOSE framework
2 : //* https://mooseframework.inl.gov
3 : //*
4 : //* All rights reserved, see COPYRIGHT for full restrictions
5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 : //*
7 : //* Licensed under LGPL 2.1, please see LICENSE for details
8 : //* https://www.gnu.org/licenses/lgpl-2.1.html
9 :
10 : #include "MultiAppUserObjectTransfer.h"
11 : #include "MooseAppCoordTransform.h"
12 :
13 : #include <limits>
14 :
15 : // MOOSE includes
16 : #include "DisplacedProblem.h"
17 : #include "FEProblem.h"
18 : #include "MooseMesh.h"
19 : #include "MooseTypes.h"
20 : #include "MooseVariableFE.h"
21 : #include "MultiApp.h"
22 : #include "UserObject.h"
23 :
24 : // libMesh
25 : #include "libmesh/meshfree_interpolation.h"
26 : #include "libmesh/system.h"
27 : #include "libmesh/mesh_function.h"
28 : #include "libmesh/mesh_tools.h"
29 :
30 : registerMooseObjectDeprecated("MooseApp", MultiAppUserObjectTransfer, "12/31/2024 24:00");
31 :
32 : InputParameters
33 15025 : MultiAppUserObjectTransfer::validParams()
34 : {
35 15025 : InputParameters params = MultiAppConservativeTransfer::validParams();
36 : // MultiAppUserObjectTransfer does not need source variable since it query values from user
37 : // objects
38 15025 : params.set<std::vector<VariableName>>("source_variable") = std::vector<VariableName>{};
39 15025 : params.suppressParameter<std::vector<VariableName>>("source_variable");
40 15025 : params.addRequiredParam<UserObjectName>(
41 : "user_object",
42 : "The UserObject you want to transfer values from. Note: This might be a "
43 : "UserObject from your MultiApp's input file!");
44 45075 : params.addParam<bool>("all_parent_nodes_contained_in_sub_app",
45 30050 : false,
46 : "Set to true if every parent app node is mapped to a distinct point on one "
47 : "of the subApps during a transfer from sub App to Parent App. If parent app"
48 : " node cannot be found within bounding boxes of any of the subApps, an "
49 : " error is generated.");
50 15025 : params.addDeprecatedParam<bool>(
51 : "all_master_nodes_contained_in_sub_app",
52 : "Set to true if every parent app node is mapped to a distinct point on one "
53 : "of the subApps during a transfer from sub App to Parent App. If parent app"
54 : " node cannot be found within bounding boxes of any of the subApps, an "
55 : " error is generated.",
56 : "all_master_nodes_contained_in_sub_app is deprecated. Use "
57 : "all_parent_nodes_contained_in_sub_app");
58 45075 : params.addParam<bool>(
59 : "skip_bounding_box_check",
60 30050 : false,
61 : "Skip the check if the to_elem is within the bounding box of the from_app.");
62 15025 : params.addParam<std::vector<SubdomainName>>(
63 : "block", "The block we are transferring to (if not specified, whole domain is used).");
64 15025 : params.addParam<std::vector<BoundaryName>>(
65 : "boundary",
66 : "The boundary we are transferring to (if not specified, whole domain is used unless 'block' "
67 : "parameter is used).");
68 :
69 15025 : params.addClassDescription(
70 : "Samples a variable's value in the Parent app domain at the point where the MultiApp is and "
71 : "copies that value into a post-processor in the MultiApp");
72 :
73 45075 : params.addParam<bool>("nearest_sub_app",
74 30050 : false,
75 : "When True, a from_multiapp transfer will work by finding the nearest "
76 : "(using the `location`) sub-app and query that for the value to transfer");
77 15025 : return params;
78 0 : }
79 :
80 380 : MultiAppUserObjectTransfer::MultiAppUserObjectTransfer(const InputParameters & parameters)
81 : : MultiAppConservativeTransfer(parameters),
82 380 : _user_object_name(getParam<UserObjectName>("user_object")),
83 380 : _all_parent_nodes_contained_in_sub_app(
84 760 : isParamValid("all_master_nodes_contained_in_sub_app")
85 760 : ? getParam<bool>("all_master_nodes_contained_in_sub_app")
86 380 : : getParam<bool>("all_parent_nodes_contained_in_sub_app")),
87 380 : _skip_bbox_check(getParam<bool>("skip_bounding_box_check")),
88 760 : _nearest_sub_app(getParam<bool>("nearest_sub_app"))
89 : {
90 380 : mooseDeprecated("MultiAppUserObjectTransfer is deprecated. Use "
91 : "MultiAppGeneralFieldUserObjectTransfer instead and adapt the parameters");
92 :
93 : // This transfer does not work with DistributedMesh
94 380 : _fe_problem.mesh().errorIfDistributedMesh("MultiAppUserObjectTransfer");
95 :
96 380 : if (_to_var_names.size() != 1)
97 0 : paramError("variable", " Support single to-variable only ");
98 :
99 380 : if (_from_var_names.size() > 0)
100 0 : paramError("source_variable",
101 : " You should not provide any source variables since the transfer takes values from "
102 : "user objects ");
103 :
104 380 : if (isParamValid("block") && isParamValid("boundary"))
105 0 : mooseError(name(), ": Transfer can be either block- or boundary-restricted. Not both.");
106 :
107 760 : if (isParamValid("to_multi_app") && isParamValid("from_multi_app") &&
108 380 : getToMultiApp() != getFromMultiApp())
109 0 : paramError("to_multi_app",
110 : "Sibling multiapp transfer has not been implemented for this transfer.");
111 380 : }
112 :
113 : void
114 589 : MultiAppUserObjectTransfer::execute()
115 : {
116 589 : TIME_SECTION(
117 : "MultiAppUserObjectTransfer::execute()", 5, "Performing transfer with a user object");
118 :
119 589 : getAppInfo();
120 :
121 : // Execute the user object if it was specified to execute on TRANSFER
122 589 : switch (_current_direction)
123 : {
124 248 : case TO_MULTIAPP:
125 : {
126 248 : _fe_problem.computeUserObjectByName(EXEC_TRANSFER, Moose::PRE_AUX, _user_object_name);
127 248 : _fe_problem.computeUserObjectByName(EXEC_TRANSFER, Moose::POST_AUX, _user_object_name);
128 248 : break;
129 : }
130 341 : case FROM_MULTIAPP:
131 341 : errorIfObjectExecutesOnTransferInSourceApp(_user_object_name);
132 : }
133 :
134 589 : switch (_current_direction)
135 : {
136 248 : case TO_MULTIAPP:
137 : {
138 510 : for (unsigned int i = 0; i < getToMultiApp()->numGlobalApps(); i++)
139 : {
140 274 : if (getToMultiApp()->hasLocalApp(i))
141 : {
142 262 : Moose::ScopedCommSwapper swapper(getToMultiApp()->comm());
143 :
144 : // Loop over the parent app nodes and set the value of the variable
145 262 : System * to_sys = find_sys(getToMultiApp()->appProblemBase(i).es(), _to_var_name);
146 :
147 262 : unsigned int sys_num = to_sys->number();
148 262 : unsigned int var_num = to_sys->variable_number(_to_var_name);
149 :
150 262 : NumericVector<Real> & solution = getToMultiApp()->appTransferVector(i, _to_var_name);
151 :
152 262 : MooseMesh * mesh = NULL;
153 :
154 262 : if (_displaced_target_mesh && getToMultiApp()->appProblemBase(i).getDisplacedProblem())
155 61 : mesh = &getToMultiApp()->appProblemBase(i).getDisplacedProblem()->mesh();
156 : else
157 201 : mesh = &getToMultiApp()->appProblemBase(i).mesh();
158 :
159 262 : _blk_ids.clear();
160 262 : _bnd_ids.clear();
161 262 : if (isParamValid("block"))
162 : {
163 : const std::vector<SubdomainName> & blocks =
164 112 : getParam<std::vector<SubdomainName>>("block");
165 220 : for (const auto & b : blocks)
166 112 : if (!MooseMeshUtils::hasSubdomainName(*mesh, b))
167 4 : paramError("block", "The block '", b, "' was not found in the mesh");
168 :
169 108 : std::vector<SubdomainID> ids = mesh->getSubdomainIDs(blocks);
170 108 : _blk_ids.insert(ids.begin(), ids.end());
171 108 : }
172 150 : else if (isParamValid("boundary"))
173 : {
174 : const std::vector<BoundaryName> & boundary_names =
175 4 : getParam<std::vector<BoundaryName>>("boundary");
176 4 : for (const auto & b : boundary_names)
177 4 : if (!MooseMeshUtils::hasBoundaryName(*mesh, b))
178 4 : paramError("boundary", "The boundary '", b, "' was not found in the mesh");
179 :
180 0 : std::vector<BoundaryID> ids = mesh->getBoundaryIDs(boundary_names, true);
181 0 : _bnd_ids.insert(ids.begin(), ids.end());
182 0 : }
183 :
184 254 : auto & fe_type = to_sys->variable_type(var_num);
185 254 : bool is_constant = fe_type.order == CONSTANT;
186 254 : bool is_nodal = fe_type.family == LAGRANGE;
187 :
188 254 : if (fe_type.order > FIRST && !is_nodal)
189 0 : mooseError("We don't currently support second order or higher elemental variable ");
190 :
191 : const UserObject & user_object =
192 254 : getToMultiApp()->problemBase().getUserObjectBase(_user_object_name);
193 : mooseAssert(_from_transforms.size() == 1, "This should have size 1");
194 254 : const auto & from_transform = *_from_transforms[0];
195 254 : const auto & to_transform = *_to_transforms[i];
196 :
197 254 : if (is_nodal)
198 : {
199 5189 : for (auto & node : mesh->getMesh().local_node_ptr_range())
200 : {
201 2550 : if (blockRestricted() && !hasBlocks(mesh, node))
202 76 : continue;
203 :
204 2474 : if (boundaryRestricted() && !isBoundaryNode(mesh, node))
205 0 : continue;
206 :
207 2474 : if (node->n_dofs(sys_num, var_num) > 0) // If this variable has dofs at this node
208 : {
209 : // The zero only works for LAGRANGE!
210 2474 : dof_id_type dof = node->dof_number(sys_num, var_num, 0);
211 :
212 2474 : swapper.forceSwap();
213 : Real from_value =
214 2474 : user_object.spatialValue(from_transform.mapBack(to_transform(*node)));
215 2470 : swapper.forceSwap();
216 :
217 2470 : solution.set(dof, from_value);
218 : }
219 93 : }
220 : }
221 : else // Elemental
222 : {
223 157 : std::vector<Point> points;
224 314 : for (auto & elem : as_range(mesh->getMesh().local_elements_begin(),
225 14059 : mesh->getMesh().local_elements_end()))
226 : {
227 6794 : if (blockRestricted() && !hasBlocks(elem))
228 92 : continue;
229 :
230 6702 : if (boundaryRestricted() && !isBoundaryElem(mesh, elem))
231 0 : continue;
232 :
233 : // Skip this element if the variable has no dofs at it.
234 6702 : if (elem->n_dofs(sys_num, var_num) < 1)
235 0 : continue;
236 :
237 6702 : points.clear();
238 : // grap sample points
239 : // for constant shape function, we take the element centroid
240 6702 : if (is_constant)
241 3102 : points.push_back(elem->vertex_average());
242 : // for higher order method, we take all nodes of element
243 : // this works for the first order L2 Lagrange.
244 : else
245 18000 : for (auto & node : elem->node_ref_range())
246 14400 : points.push_back(node);
247 :
248 6702 : auto n_points = points.size();
249 6702 : unsigned int n_comp = elem->n_comp(sys_num, var_num);
250 : // We assume each point corresponds to one component of elemental variable
251 6702 : if (n_points != n_comp)
252 0 : mooseError(" Number of points ",
253 : n_points,
254 : " does not equal to number of variable components ",
255 : n_comp);
256 :
257 6702 : unsigned int offset = 0;
258 24204 : for (auto & point : points) // If this variable has dofs at this elem
259 : {
260 17502 : dof_id_type dof = elem->dof_number(sys_num, var_num, offset++);
261 :
262 17502 : swapper.forceSwap();
263 : Real from_value =
264 17502 : user_object.spatialValue(from_transform.mapBack(to_transform(point)));
265 17502 : swapper.forceSwap();
266 :
267 17502 : solution.set(dof, from_value);
268 : }
269 157 : }
270 157 : }
271 :
272 250 : solution.close();
273 250 : to_sys->update();
274 250 : }
275 : }
276 :
277 236 : break;
278 : }
279 341 : case FROM_MULTIAPP:
280 : {
281 341 : FEProblemBase & to_problem = getFromMultiApp()->problemBase();
282 : mooseAssert(_to_transforms.size() == 1, "This should only be size one");
283 341 : const auto & to_transform = *_to_transforms[0];
284 341 : MooseVariableFEBase & to_var = to_problem.getVariable(
285 : 0, _to_var_name, Moose::VarKindType::VAR_ANY, Moose::VarFieldType::VAR_FIELD_STANDARD);
286 341 : SystemBase & to_system_base = to_var.sys();
287 :
288 341 : System & to_sys = to_system_base.system();
289 :
290 341 : unsigned int to_sys_num = to_sys.number();
291 :
292 : // Only works with a serialized mesh to transfer to!
293 : mooseAssert(to_sys.get_mesh().is_serial(),
294 : "MultiAppUserObjectTransfer only works with ReplicatedMesh!");
295 :
296 341 : unsigned int to_var_num = to_sys.variable_number(to_var.name());
297 :
298 : // EquationSystems & to_es = to_sys.get_equation_systems();
299 :
300 : // Create a serialized version of the solution vector
301 341 : NumericVector<Number> * to_solution = to_sys.solution.get();
302 :
303 341 : MooseMesh * to_mesh = NULL;
304 :
305 341 : if (_displaced_target_mesh && to_problem.getDisplacedProblem())
306 0 : to_mesh = &to_problem.getDisplacedProblem()->mesh();
307 : else
308 341 : to_mesh = &to_problem.mesh();
309 :
310 341 : _blk_ids.clear();
311 341 : _bnd_ids.clear();
312 341 : if (isParamValid("block"))
313 : {
314 4 : const std::vector<SubdomainName> & blocks = getParam<std::vector<SubdomainName>>("block");
315 4 : for (const auto & b : blocks)
316 4 : if (!MooseMeshUtils::hasSubdomainName(*to_mesh, b))
317 4 : paramError("block", "The block '", b, "' was not found in the mesh");
318 :
319 0 : std::vector<SubdomainID> ids = to_mesh->getSubdomainIDs(blocks);
320 0 : _blk_ids.insert(ids.begin(), ids.end());
321 0 : }
322 337 : else if (isParamValid("boundary"))
323 : {
324 : const std::vector<BoundaryName> & boundary_names =
325 108 : getParam<std::vector<BoundaryName>>("boundary");
326 212 : for (const auto & b : boundary_names)
327 108 : if (!MooseMeshUtils::hasBoundaryName(*to_mesh, b))
328 4 : paramError("boundary", "The boundary '", b, "' was not found in the mesh");
329 :
330 104 : std::vector<BoundaryID> ids = to_mesh->getBoundaryIDs(boundary_names, true);
331 104 : _bnd_ids.insert(ids.begin(), ids.end());
332 104 : }
333 :
334 333 : auto & fe_type = to_sys.variable_type(to_var_num);
335 333 : bool is_constant = fe_type.order == CONSTANT;
336 333 : bool is_nodal = fe_type.family == LAGRANGE;
337 :
338 333 : if (fe_type.order > FIRST && !is_nodal)
339 0 : mooseError("We don't currently support second order or higher elemental variable ");
340 :
341 333 : if (_all_parent_nodes_contained_in_sub_app)
342 : {
343 : // check to see if parent app nodes or elements lies within any of the sub application
344 : // bounding boxes
345 4 : if (is_nodal)
346 : {
347 0 : for (auto & node : to_mesh->getMesh().node_ptr_range())
348 : {
349 0 : if (blockRestricted() && !hasBlocks(to_mesh, node))
350 0 : continue;
351 :
352 0 : if (boundaryRestricted() && !isBoundaryNode(to_mesh, node))
353 0 : continue;
354 :
355 0 : if (node->n_dofs(to_sys_num, to_var_num) > 0)
356 : {
357 0 : const auto transformed_node = to_transform(*node);
358 :
359 0 : unsigned int node_found_in_sub_app = 0;
360 0 : for (unsigned int i = 0; i < getFromMultiApp()->numGlobalApps(); i++)
361 : {
362 0 : if (!getFromMultiApp()->hasLocalApp(i))
363 0 : continue;
364 :
365 0 : BoundingBox app_box = getFromMultiApp()->getBoundingBox(
366 0 : i, _displaced_source_mesh, _from_transforms[i].get());
367 :
368 0 : if (app_box.contains_point(transformed_node))
369 0 : ++node_found_in_sub_app;
370 : }
371 :
372 0 : if (node_found_in_sub_app == 0)
373 0 : mooseError("MultiAppUserObjectTransfer: Parent app node ",
374 : transformed_node,
375 : " not found within the bounding box of any of the sub applications.");
376 0 : else if (node_found_in_sub_app > 1)
377 0 : mooseError("MultiAppUserObjectTransfer: Parent app node ",
378 : transformed_node,
379 : " found within the bounding box of two or more sub applications.");
380 : }
381 0 : }
382 : }
383 : else // elemental
384 : {
385 4 : std::vector<Point> points;
386 4 : for (auto & elem :
387 8 : as_range(to_mesh->getMesh().elements_begin(), to_mesh->getMesh().elements_end()))
388 : {
389 4 : if (blockRestricted() && !hasBlocks(elem))
390 0 : continue;
391 :
392 4 : if (boundaryRestricted() && !isBoundaryElem(to_mesh, elem))
393 0 : continue;
394 :
395 : // Skip this element if the variable has no dofs at it.
396 4 : if (elem->n_dofs(to_sys_num, to_var_num) < 1)
397 0 : continue;
398 :
399 4 : points.clear();
400 : // grap sample points
401 : // for constant shape function, we take the element centroid
402 4 : if (is_constant)
403 4 : points.push_back(to_transform(elem->vertex_average()));
404 : // for higher order method, we take all nodes of element
405 : // this works for the first order L2 Lagrange.
406 : else
407 0 : for (auto & node : elem->node_ref_range())
408 0 : points.push_back(to_transform(node));
409 :
410 4 : auto n_points = points.size();
411 4 : unsigned int n_comp = elem->n_comp(to_sys_num, to_var_num);
412 : // We assume each point corresponds to one component of elemental variable
413 4 : if (n_points != n_comp)
414 0 : mooseError(" Number of points ",
415 : n_points,
416 : " does not equal to number of variable components ",
417 : n_comp);
418 :
419 4 : for (auto & point : points)
420 : {
421 4 : unsigned int elem_found_in_sub_app = 0;
422 :
423 8 : for (unsigned int i = 0; i < getFromMultiApp()->numGlobalApps(); i++)
424 : {
425 4 : if (!getFromMultiApp()->hasLocalApp(i))
426 0 : continue;
427 :
428 8 : BoundingBox app_box = getFromMultiApp()->getBoundingBox(
429 4 : i, _displaced_source_mesh, _from_transforms[i].get());
430 :
431 4 : if (app_box.contains_point(point))
432 0 : ++elem_found_in_sub_app;
433 : }
434 :
435 4 : if (elem_found_in_sub_app == 0)
436 8 : mooseError("MultiAppUserObjectTransfer: Parent app element with ",
437 4 : n_points > 1 ? "node" : "centroid",
438 : " at ",
439 : point,
440 : " not found within the bounding box of any of the sub applications.");
441 :
442 0 : else if (elem_found_in_sub_app > 1)
443 0 : mooseError("MultiAppUserObjectTransfer: Parent app element with ",
444 0 : n_points > 1 ? "node" : "centroid",
445 : " at ",
446 : point,
447 : " found within the bounding box of two or more sub applications.");
448 : }
449 0 : }
450 0 : }
451 : }
452 :
453 329 : if (is_nodal)
454 : {
455 494539 : for (auto & node : to_mesh->getMesh().node_ptr_range())
456 : {
457 247171 : if (blockRestricted() && !hasBlocks(to_mesh, node))
458 0 : continue;
459 :
460 247171 : if (boundaryRestricted() && !isBoundaryNode(to_mesh, node))
461 1800 : continue;
462 :
463 245371 : if (node->n_dofs(to_sys_num, to_var_num) > 0) // If this variable has dofs at this node
464 : {
465 245371 : const auto transformed_node = to_transform(*node);
466 245371 : const auto sub_app = findSubAppToTransferFrom(transformed_node);
467 :
468 : // Check to see if a sub-app was found
469 245371 : if (sub_app == static_cast<unsigned int>(-1))
470 145273 : continue;
471 :
472 100098 : const auto & from_transform = *_from_transforms[sub_app];
473 100098 : const auto & user_object = _multi_app->appUserObjectBase(sub_app, _user_object_name);
474 :
475 100098 : dof_id_type dof = node->dof_number(to_sys_num, to_var_num, 0);
476 :
477 100098 : Real from_value = 0;
478 : {
479 100098 : Moose::ScopedCommSwapper swapper(getFromMultiApp()->comm());
480 100098 : from_value = user_object.spatialValue(from_transform.mapBack(transformed_node));
481 100098 : }
482 :
483 100098 : if (from_value == std::numeric_limits<Real>::infinity())
484 0 : mooseError("MultiAppUserObjectTransfer: Point corresponding to parent app node at (",
485 : transformed_node,
486 : ") not found in the sub application.");
487 100098 : to_solution->set(dof, from_value);
488 : }
489 197 : }
490 : }
491 : else // Elemental
492 : {
493 132 : std::vector<Point> points;
494 132 : for (auto & elem :
495 432318 : as_range(to_mesh->getMesh().elements_begin(), to_mesh->getMesh().elements_end()))
496 : {
497 216027 : if (blockRestricted() && !hasBlocks(elem))
498 2168 : continue;
499 :
500 216027 : if (boundaryRestricted() && !isBoundaryElem(to_mesh, elem))
501 648 : continue;
502 :
503 : // Skip this element if the variable has no dofs at it.
504 215379 : if (elem->n_dofs(to_sys_num, to_var_num) < 1)
505 1520 : continue;
506 :
507 213859 : points.clear();
508 : // grap sample points
509 : // for constant shape function, we take the element centroid
510 213859 : if (is_constant)
511 213859 : points.push_back(to_transform(elem->vertex_average()));
512 : // for higher order method, we take all nodes of element
513 : // this works for the first order L2 Lagrange.
514 : else
515 0 : for (auto & node : elem->node_ref_range())
516 0 : points.push_back(to_transform(node));
517 :
518 213859 : auto n_points = points.size();
519 213859 : unsigned int n_comp = elem->n_comp(to_sys_num, to_var_num);
520 : // We assume each point corresponds to one component of elemental variable
521 213859 : if (n_points != n_comp)
522 0 : mooseError(" Number of points ",
523 : n_points,
524 : " does not equal to number of variable components ",
525 : n_comp);
526 :
527 213859 : unsigned int offset = 0;
528 427718 : for (auto & point : points) // If this variable has dofs at this elem
529 : {
530 213859 : const auto sub_app = findSubAppToTransferFrom(point);
531 :
532 : // Check to see if a sub-app was found
533 213859 : if (sub_app == static_cast<unsigned int>(-1))
534 127560 : continue;
535 :
536 86299 : const auto & from_transform = *_from_transforms[sub_app];
537 : const auto & user_object =
538 86299 : getFromMultiApp()->appUserObjectBase(sub_app, _user_object_name);
539 :
540 86299 : dof_id_type dof = elem->dof_number(to_sys_num, to_var_num, offset++);
541 :
542 86299 : Real from_value = 0;
543 : {
544 86299 : Moose::ScopedCommSwapper swapper(getFromMultiApp()->comm());
545 86299 : from_value = user_object.spatialValue(from_transform.mapBack(point));
546 86299 : }
547 :
548 86299 : if (from_value == std::numeric_limits<Real>::infinity())
549 0 : mooseError("MultiAppUserObjectTransfer: Point corresponding to element's centroid (",
550 : point,
551 : ") not found in sub application.");
552 :
553 86299 : to_solution->set(dof, from_value);
554 : }
555 132 : }
556 132 : }
557 :
558 329 : to_solution->close();
559 329 : to_sys.update();
560 :
561 329 : break;
562 : }
563 : }
564 :
565 565 : postExecute();
566 565 : }
567 :
568 : bool
569 472546 : MultiAppUserObjectTransfer::blockRestricted() const
570 : {
571 472546 : return !_blk_ids.empty();
572 : }
573 :
574 : bool
575 472378 : MultiAppUserObjectTransfer::boundaryRestricted() const
576 : {
577 472378 : return !_bnd_ids.empty();
578 : }
579 :
580 : bool
581 184 : MultiAppUserObjectTransfer::hasBlocks(const Elem * elem) const
582 : {
583 184 : return _blk_ids.find(elem->subdomain_id()) != _blk_ids.end();
584 : }
585 :
586 : bool
587 228 : MultiAppUserObjectTransfer::hasBlocks(const MooseMesh * mesh, const Node * node) const
588 : {
589 228 : const auto & node_blk_ids = mesh->getNodeBlockIds(*node);
590 228 : std::set<SubdomainID> u;
591 228 : std::set_intersection(_blk_ids.begin(),
592 : _blk_ids.end(),
593 : node_blk_ids.begin(),
594 : node_blk_ids.end(),
595 : std::inserter(u, u.begin()));
596 456 : return !u.empty();
597 228 : }
598 :
599 : bool
600 2400 : MultiAppUserObjectTransfer::isBoundaryNode(const MooseMesh * mesh, const Node * node) const
601 : {
602 4200 : for (auto & bid : _bnd_ids)
603 2400 : if (mesh->isBoundaryNode(node->id(), bid))
604 600 : return true;
605 1800 : return false;
606 : }
607 :
608 : bool
609 972 : MultiAppUserObjectTransfer::isBoundaryElem(const MooseMesh * mesh, const Elem * elem) const
610 : {
611 1620 : for (auto & bid : _bnd_ids)
612 972 : if (mesh->isBoundaryElem(elem->id(), bid))
613 324 : return true;
614 648 : return false;
615 : }
616 :
617 : unsigned int
618 459230 : MultiAppUserObjectTransfer::findSubAppToTransferFrom(const Point & p)
619 : {
620 : // Just find the nearest app to this point
621 459230 : if (_nearest_sub_app)
622 : {
623 224393 : unsigned int closest_app = 0;
624 224393 : Real closest_distance = std::numeric_limits<Real>::max();
625 :
626 : mooseAssert(_multi_app->numGlobalApps() > 0, "No Multiapps To Transfer From");
627 :
628 673179 : for (unsigned int i = 0; i < _multi_app->numGlobalApps(); i++)
629 : {
630 : // Obtain the possibly transformed app position by querying the transform with the origin
631 448786 : const auto app_position = _multi_app->runningInPosition()
632 448786 : ? (*_from_transforms[i])(_multi_app->position(i))
633 448786 : : (*_from_transforms[i])(Point(0));
634 :
635 448786 : auto distance = (p - app_position).norm();
636 :
637 448786 : if (distance < closest_distance)
638 : {
639 335686 : closest_app = i;
640 335686 : closest_distance = distance;
641 : }
642 : }
643 :
644 : // We can only get the value if we have this app
645 : // otherwise - another processor will set it
646 224393 : if (_multi_app->hasLocalApp(closest_app))
647 172610 : return closest_app;
648 : else
649 51783 : return -1;
650 : }
651 :
652 : // Find the app that contains this point...
653 :
654 : // This loop counts _down_ so that it can preserve legacy behavior of the
655 : // last sub-app "winning" to be able to set the value at this point
656 678616 : for (int i = _multi_app->numGlobalApps() - 1; i >= 0; i--)
657 : {
658 457566 : if (!_multi_app->hasLocalApp(i))
659 103339 : continue;
660 :
661 : BoundingBox app_box =
662 354227 : _multi_app->getBoundingBox(i, _displaced_source_mesh, _from_transforms[i].get());
663 :
664 354227 : if (_skip_bbox_check || app_box.contains_point(p))
665 13787 : return static_cast<unsigned int>(i);
666 : }
667 :
668 221050 : return -1;
669 : }
|