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 14973 : MultiAppUserObjectTransfer::validParams()
34 : {
35 14973 : InputParameters params = MultiAppConservativeTransfer::validParams();
36 : // MultiAppUserObjectTransfer does not need source variable since it query values from user
37 : // objects
38 14973 : params.set<std::vector<VariableName>>("source_variable") = std::vector<VariableName>{};
39 14973 : params.suppressParameter<std::vector<VariableName>>("source_variable");
40 14973 : 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 44919 : params.addParam<bool>("all_parent_nodes_contained_in_sub_app",
45 29946 : 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 14973 : 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 44919 : params.addParam<bool>(
59 : "skip_bounding_box_check",
60 29946 : false,
61 : "Skip the check if the to_elem is within the bounding box of the from_app.");
62 14973 : params.addParam<std::vector<SubdomainName>>(
63 : "block", "The block we are transferring to (if not specified, whole domain is used).");
64 14973 : 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 14973 : 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 44919 : params.addParam<bool>("nearest_sub_app",
74 29946 : 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 14973 : return params;
78 0 : }
79 :
80 354 : MultiAppUserObjectTransfer::MultiAppUserObjectTransfer(const InputParameters & parameters)
81 : : MultiAppConservativeTransfer(parameters),
82 354 : _user_object_name(getParam<UserObjectName>("user_object")),
83 354 : _all_parent_nodes_contained_in_sub_app(
84 708 : isParamValid("all_master_nodes_contained_in_sub_app")
85 708 : ? getParam<bool>("all_master_nodes_contained_in_sub_app")
86 354 : : getParam<bool>("all_parent_nodes_contained_in_sub_app")),
87 354 : _skip_bbox_check(getParam<bool>("skip_bounding_box_check")),
88 708 : _nearest_sub_app(getParam<bool>("nearest_sub_app"))
89 : {
90 354 : mooseDeprecated("MultiAppUserObjectTransfer is deprecated. Use "
91 : "MultiAppGeneralFieldUserObjectTransfer instead and adapt the parameters");
92 :
93 : // This transfer does not work with DistributedMesh
94 354 : _fe_problem.mesh().errorIfDistributedMesh("MultiAppUserObjectTransfer");
95 :
96 354 : if (_to_var_names.size() != 1)
97 0 : paramError("variable", " Support single to-variable only ");
98 :
99 354 : 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 354 : if (isParamValid("block") && isParamValid("boundary"))
105 0 : mooseError(name(), ": Transfer can be either block- or boundary-restricted. Not both.");
106 :
107 708 : if (isParamValid("to_multi_app") && isParamValid("from_multi_app") &&
108 354 : getToMultiApp() != getFromMultiApp())
109 0 : paramError("to_multi_app",
110 : "Sibling multiapp transfer has not been implemented for this transfer.");
111 354 : }
112 :
113 : void
114 521 : MultiAppUserObjectTransfer::execute()
115 : {
116 521 : TIME_SECTION(
117 : "MultiAppUserObjectTransfer::execute()", 5, "Performing transfer with a user object");
118 :
119 521 : getAppInfo();
120 :
121 : // Execute the user object if it was specified to execute on TRANSFER
122 521 : switch (_current_direction)
123 : {
124 220 : case TO_MULTIAPP:
125 : {
126 220 : _fe_problem.computeUserObjectByName(EXEC_TRANSFER, Moose::PRE_AUX, _user_object_name);
127 220 : _fe_problem.computeUserObjectByName(EXEC_TRANSFER, Moose::POST_AUX, _user_object_name);
128 220 : break;
129 : }
130 301 : case FROM_MULTIAPP:
131 301 : errorIfObjectExecutesOnTransferInSourceApp(_user_object_name);
132 : }
133 :
134 521 : switch (_current_direction)
135 : {
136 220 : case TO_MULTIAPP:
137 : {
138 450 : for (unsigned int i = 0; i < getToMultiApp()->numGlobalApps(); i++)
139 : {
140 242 : if (getToMultiApp()->hasLocalApp(i))
141 : {
142 230 : Moose::ScopedCommSwapper swapper(getToMultiApp()->comm());
143 :
144 : // Loop over the parent app nodes and set the value of the variable
145 230 : System * to_sys = find_sys(getToMultiApp()->appProblemBase(i).es(), _to_var_name);
146 :
147 230 : unsigned int sys_num = to_sys->number();
148 230 : unsigned int var_num = to_sys->variable_number(_to_var_name);
149 :
150 230 : NumericVector<Real> & solution = getToMultiApp()->appTransferVector(i, _to_var_name);
151 :
152 230 : MooseMesh * mesh = NULL;
153 :
154 230 : if (_displaced_target_mesh && getToMultiApp()->appProblemBase(i).getDisplacedProblem())
155 54 : mesh = &getToMultiApp()->appProblemBase(i).getDisplacedProblem()->mesh();
156 : else
157 176 : mesh = &getToMultiApp()->appProblemBase(i).mesh();
158 :
159 230 : _blk_ids.clear();
160 230 : _bnd_ids.clear();
161 230 : if (isParamValid("block"))
162 : {
163 : const std::vector<SubdomainName> & blocks =
164 100 : getParam<std::vector<SubdomainName>>("block");
165 196 : for (const auto & b : blocks)
166 100 : if (!MooseMeshUtils::hasSubdomainName(*mesh, b))
167 4 : paramError("block", "The block '", b, "' was not found in the mesh");
168 :
169 96 : std::vector<SubdomainID> ids = mesh->getSubdomainIDs(blocks);
170 96 : _blk_ids.insert(ids.begin(), ids.end());
171 96 : }
172 130 : 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 222 : auto & fe_type = to_sys->variable_type(var_num);
185 222 : bool is_constant = fe_type.order == CONSTANT;
186 222 : bool is_nodal = fe_type.family == LAGRANGE;
187 :
188 222 : 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 222 : getToMultiApp()->problemBase().getUserObjectBase(_user_object_name);
193 : mooseAssert(_from_transforms.size() == 1, "This should have size 1");
194 222 : const auto & from_transform = *_from_transforms[0];
195 222 : const auto & to_transform = *_to_transforms[i];
196 :
197 222 : if (is_nodal)
198 : {
199 4322 : for (auto & node : mesh->getMesh().local_node_ptr_range())
200 : {
201 2123 : if (blockRestricted() && !hasBlocks(mesh, node))
202 64 : continue;
203 :
204 2059 : if (boundaryRestricted() && !isBoundaryNode(mesh, node))
205 0 : continue;
206 :
207 2059 : 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 2059 : dof_id_type dof = node->dof_number(sys_num, var_num, 0);
211 :
212 2059 : swapper.forceSwap();
213 : Real from_value =
214 2059 : user_object.spatialValue(from_transform.mapBack(to_transform(*node)));
215 2055 : swapper.forceSwap();
216 :
217 2055 : solution.set(dof, from_value);
218 : }
219 80 : }
220 : }
221 : else // Elemental
222 : {
223 138 : std::vector<Point> points;
224 276 : for (auto & elem : as_range(mesh->getMesh().local_elements_begin(),
225 12110 : mesh->getMesh().local_elements_end()))
226 : {
227 5848 : if (blockRestricted() && !hasBlocks(elem))
228 80 : continue;
229 :
230 5768 : if (boundaryRestricted() && !isBoundaryElem(mesh, elem))
231 0 : continue;
232 :
233 : // Skip this element if the variable has no dofs at it.
234 5768 : if (elem->n_dofs(sys_num, var_num) < 1)
235 0 : continue;
236 :
237 5768 : points.clear();
238 : // grap sample points
239 : // for constant shape function, we take the element centroid
240 5768 : if (is_constant)
241 2568 : 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 16000 : for (auto & node : elem->node_ref_range())
246 12800 : points.push_back(node);
247 :
248 5768 : auto n_points = points.size();
249 5768 : unsigned int n_comp = elem->n_comp(sys_num, var_num);
250 : // We assume each point corresponds to one component of elemental variable
251 5768 : 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 5768 : unsigned int offset = 0;
258 21136 : for (auto & point : points) // If this variable has dofs at this elem
259 : {
260 15368 : dof_id_type dof = elem->dof_number(sys_num, var_num, offset++);
261 :
262 15368 : swapper.forceSwap();
263 : Real from_value =
264 15368 : user_object.spatialValue(from_transform.mapBack(to_transform(point)));
265 15368 : swapper.forceSwap();
266 :
267 15368 : solution.set(dof, from_value);
268 : }
269 138 : }
270 138 : }
271 :
272 218 : solution.close();
273 218 : to_sys->update();
274 218 : }
275 : }
276 :
277 208 : break;
278 : }
279 301 : case FROM_MULTIAPP:
280 : {
281 301 : FEProblemBase & to_problem = getFromMultiApp()->problemBase();
282 : mooseAssert(_to_transforms.size() == 1, "This should only be size one");
283 301 : const auto & to_transform = *_to_transforms[0];
284 301 : MooseVariableFEBase & to_var = to_problem.getVariable(
285 : 0, _to_var_name, Moose::VarKindType::VAR_ANY, Moose::VarFieldType::VAR_FIELD_STANDARD);
286 301 : SystemBase & to_system_base = to_var.sys();
287 :
288 301 : System & to_sys = to_system_base.system();
289 :
290 301 : 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 301 : 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 301 : NumericVector<Number> * to_solution = to_sys.solution.get();
302 :
303 301 : MooseMesh * to_mesh = NULL;
304 :
305 301 : if (_displaced_target_mesh && to_problem.getDisplacedProblem())
306 0 : to_mesh = &to_problem.getDisplacedProblem()->mesh();
307 : else
308 301 : to_mesh = &to_problem.mesh();
309 :
310 301 : _blk_ids.clear();
311 301 : _bnd_ids.clear();
312 301 : 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 297 : else if (isParamValid("boundary"))
323 : {
324 : const std::vector<BoundaryName> & boundary_names =
325 96 : getParam<std::vector<BoundaryName>>("boundary");
326 188 : for (const auto & b : boundary_names)
327 96 : if (!MooseMeshUtils::hasBoundaryName(*to_mesh, b))
328 4 : paramError("boundary", "The boundary '", b, "' was not found in the mesh");
329 :
330 92 : std::vector<BoundaryID> ids = to_mesh->getBoundaryIDs(boundary_names, true);
331 92 : _bnd_ids.insert(ids.begin(), ids.end());
332 92 : }
333 :
334 293 : auto & fe_type = to_sys.variable_type(to_var_num);
335 293 : bool is_constant = fe_type.order == CONSTANT;
336 293 : bool is_nodal = fe_type.family == LAGRANGE;
337 :
338 293 : if (fe_type.order > FIRST && !is_nodal)
339 0 : mooseError("We don't currently support second order or higher elemental variable ");
340 :
341 293 : 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 289 : if (is_nodal)
454 : {
455 419010 : for (auto & node : to_mesh->getMesh().node_ptr_range())
456 : {
457 209418 : if (blockRestricted() && !hasBlocks(to_mesh, node))
458 0 : continue;
459 :
460 209418 : if (boundaryRestricted() && !isBoundaryNode(to_mesh, node))
461 1584 : continue;
462 :
463 207834 : if (node->n_dofs(to_sys_num, to_var_num) > 0) // If this variable has dofs at this node
464 : {
465 207834 : const auto transformed_node = to_transform(*node);
466 207834 : const auto sub_app = findSubAppToTransferFrom(transformed_node);
467 :
468 : // Check to see if a sub-app was found
469 207834 : if (sub_app == static_cast<unsigned int>(-1))
470 127575 : continue;
471 :
472 80259 : const auto & from_transform = *_from_transforms[sub_app];
473 80259 : const auto & user_object = _multi_app->appUserObjectBase(sub_app, _user_object_name);
474 :
475 80259 : dof_id_type dof = node->dof_number(to_sys_num, to_var_num, 0);
476 :
477 80259 : Real from_value = 0;
478 : {
479 80259 : Moose::ScopedCommSwapper swapper(getFromMultiApp()->comm());
480 80259 : from_value = user_object.spatialValue(from_transform.mapBack(transformed_node));
481 80259 : }
482 :
483 80259 : 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 80259 : to_solution->set(dof, from_value);
488 : }
489 174 : }
490 : }
491 : else // Elemental
492 : {
493 115 : std::vector<Point> points;
494 115 : for (auto & elem :
495 366158 : as_range(to_mesh->getMesh().elements_begin(), to_mesh->getMesh().elements_end()))
496 : {
497 182964 : if (blockRestricted() && !hasBlocks(elem))
498 1856 : continue;
499 :
500 182964 : if (boundaryRestricted() && !isBoundaryElem(to_mesh, elem))
501 576 : continue;
502 :
503 : // Skip this element if the variable has no dofs at it.
504 182388 : if (elem->n_dofs(to_sys_num, to_var_num) < 1)
505 1280 : continue;
506 :
507 181108 : points.clear();
508 : // grap sample points
509 : // for constant shape function, we take the element centroid
510 181108 : if (is_constant)
511 181108 : 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 181108 : auto n_points = points.size();
519 181108 : 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 181108 : 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 181108 : unsigned int offset = 0;
528 362216 : for (auto & point : points) // If this variable has dofs at this elem
529 : {
530 181108 : const auto sub_app = findSubAppToTransferFrom(point);
531 :
532 : // Check to see if a sub-app was found
533 181108 : if (sub_app == static_cast<unsigned int>(-1))
534 111840 : continue;
535 :
536 69268 : const auto & from_transform = *_from_transforms[sub_app];
537 : const auto & user_object =
538 69268 : getFromMultiApp()->appUserObjectBase(sub_app, _user_object_name);
539 :
540 69268 : dof_id_type dof = elem->dof_number(to_sys_num, to_var_num, offset++);
541 :
542 69268 : Real from_value = 0;
543 : {
544 69268 : Moose::ScopedCommSwapper swapper(getFromMultiApp()->comm());
545 69268 : from_value = user_object.spatialValue(from_transform.mapBack(point));
546 69268 : }
547 :
548 69268 : 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 69268 : to_solution->set(dof, from_value);
554 : }
555 115 : }
556 115 : }
557 :
558 289 : to_solution->close();
559 289 : to_sys.update();
560 :
561 289 : break;
562 : }
563 : }
564 :
565 497 : postExecute();
566 497 : }
567 :
568 : bool
569 400357 : MultiAppUserObjectTransfer::blockRestricted() const
570 : {
571 400357 : return !_blk_ids.empty();
572 : }
573 :
574 : bool
575 400213 : MultiAppUserObjectTransfer::boundaryRestricted() const
576 : {
577 400213 : return !_bnd_ids.empty();
578 : }
579 :
580 : bool
581 160 : MultiAppUserObjectTransfer::hasBlocks(const Elem * elem) const
582 : {
583 160 : return _blk_ids.find(elem->subdomain_id()) != _blk_ids.end();
584 : }
585 :
586 : bool
587 192 : MultiAppUserObjectTransfer::hasBlocks(const MooseMesh * mesh, const Node * node) const
588 : {
589 192 : const auto & node_blk_ids = mesh->getNodeBlockIds(*node);
590 192 : std::set<SubdomainID> u;
591 192 : 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 384 : return !u.empty();
597 192 : }
598 :
599 : bool
600 2112 : MultiAppUserObjectTransfer::isBoundaryNode(const MooseMesh * mesh, const Node * node) const
601 : {
602 3696 : for (auto & bid : _bnd_ids)
603 2112 : if (mesh->isBoundaryNode(node->id(), bid))
604 528 : return true;
605 1584 : return false;
606 : }
607 :
608 : bool
609 864 : MultiAppUserObjectTransfer::isBoundaryElem(const MooseMesh * mesh, const Elem * elem) const
610 : {
611 1440 : for (auto & bid : _bnd_ids)
612 864 : if (mesh->isBoundaryElem(elem->id(), bid))
613 288 : return true;
614 576 : return false;
615 : }
616 :
617 : unsigned int
618 388942 : MultiAppUserObjectTransfer::findSubAppToTransferFrom(const Point & p)
619 : {
620 : // Just find the nearest app to this point
621 388942 : if (_nearest_sub_app)
622 : {
623 189871 : unsigned int closest_app = 0;
624 189871 : Real closest_distance = std::numeric_limits<Real>::max();
625 :
626 : mooseAssert(_multi_app->numGlobalApps() > 0, "No Multiapps To Transfer From");
627 :
628 569613 : 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 379742 : const auto app_position = _multi_app->runningInPosition()
632 379742 : ? (*_from_transforms[i])(_multi_app->position(i))
633 379742 : : (*_from_transforms[i])(Point(0));
634 :
635 379742 : auto distance = (p - app_position).norm();
636 :
637 379742 : if (distance < closest_distance)
638 : {
639 284042 : closest_app = i;
640 284042 : 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 189871 : if (_multi_app->hasLocalApp(closest_app))
647 138088 : 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 575492 : for (int i = _multi_app->numGlobalApps() - 1; i >= 0; i--)
657 : {
658 387860 : if (!_multi_app->hasLocalApp(i))
659 103339 : continue;
660 :
661 : BoundingBox app_box =
662 284521 : _multi_app->getBoundingBox(i, _displaced_source_mesh, _from_transforms[i].get());
663 :
664 284521 : if (_skip_bbox_check || app_box.contains_point(p))
665 11439 : return static_cast<unsigned int>(i);
666 : }
667 :
668 187632 : return -1;
669 : }
|