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 3739 : MultiAppUserObjectTransfer::validParams()
34 : {
35 3739 : InputParameters params = MultiAppConservativeTransfer::validParams();
36 : // MultiAppUserObjectTransfer does not need source variable since it query values from user
37 : // objects
38 11217 : params.set<std::vector<VariableName>>("source_variable") = std::vector<VariableName>{};
39 7478 : params.suppressParameter<std::vector<VariableName>>("source_variable");
40 14956 : 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 11217 : params.addParam<bool>("all_parent_nodes_contained_in_sub_app",
45 7478 : 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 22434 : 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 11217 : params.addParam<bool>(
59 : "skip_bounding_box_check",
60 7478 : false,
61 : "Skip the check if the to_elem is within the bounding box of the from_app.");
62 14956 : params.addParam<std::vector<SubdomainName>>(
63 : "block", "The block we are transferring to (if not specified, whole domain is used).");
64 14956 : 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 7478 : 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 7478 : params.addParam<bool>("nearest_sub_app",
74 7478 : 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 3739 : MultiAppTransfer::addUserObjectExecutionCheckParam(params);
78 :
79 3739 : return params;
80 0 : }
81 :
82 339 : MultiAppUserObjectTransfer::MultiAppUserObjectTransfer(const InputParameters & parameters)
83 : : MultiAppConservativeTransfer(parameters),
84 339 : _user_object_name(getParam<UserObjectName>("user_object")),
85 339 : _all_parent_nodes_contained_in_sub_app(
86 678 : isParamValid("all_master_nodes_contained_in_sub_app")
87 684 : ? getParam<bool>("all_master_nodes_contained_in_sub_app")
88 1347 : : getParam<bool>("all_parent_nodes_contained_in_sub_app")),
89 678 : _skip_bbox_check(getParam<bool>("skip_bounding_box_check")),
90 1356 : _nearest_sub_app(getParam<bool>("nearest_sub_app"))
91 : {
92 339 : mooseDeprecated("MultiAppUserObjectTransfer is deprecated. Use "
93 : "MultiAppGeneralFieldUserObjectTransfer instead and adapt the parameters");
94 :
95 : // This transfer does not work with DistributedMesh
96 678 : _fe_problem.mesh().errorIfDistributedMesh("MultiAppUserObjectTransfer");
97 :
98 339 : if (_to_var_names.size() != 1)
99 0 : paramError("variable", " Support single to-variable only ");
100 :
101 339 : if (_from_var_names.size() > 0)
102 0 : paramError("source_variable",
103 : " You should not provide any source variables since the transfer takes values from "
104 : "user objects ");
105 :
106 1143 : if (isParamValid("block") && isParamValid("boundary"))
107 0 : mooseError(name(), ": Transfer can be either block- or boundary-restricted. Not both.");
108 :
109 1704 : if (isParamValid("to_multi_app") && isParamValid("from_multi_app") &&
110 339 : getToMultiApp() != getFromMultiApp())
111 0 : paramError("to_multi_app",
112 : "Sibling multiapp transfer has not been implemented for this transfer.");
113 339 : }
114 :
115 : void
116 531 : MultiAppUserObjectTransfer::execute()
117 : {
118 2655 : TIME_SECTION(
119 : "MultiAppUserObjectTransfer::execute()", 5, "Performing transfer with a user object");
120 :
121 531 : getAppInfo();
122 :
123 : // Execute the user object if it was specified to execute on TRANSFER
124 531 : switch (_current_direction)
125 : {
126 223 : case TO_MULTIAPP:
127 : {
128 223 : checkParentAppUserObjectExecuteOn(_user_object_name);
129 223 : _fe_problem.computeUserObjectByName(EXEC_TRANSFER, Moose::PRE_AUX, _user_object_name);
130 223 : _fe_problem.computeUserObjectByName(EXEC_TRANSFER, Moose::POST_AUX, _user_object_name);
131 223 : break;
132 : }
133 308 : case FROM_MULTIAPP:
134 308 : errorIfObjectExecutesOnTransferInSourceApp(_user_object_name);
135 : }
136 :
137 531 : switch (_current_direction)
138 : {
139 223 : case TO_MULTIAPP:
140 : {
141 461 : for (unsigned int i = 0; i < getToMultiApp()->numGlobalApps(); i++)
142 : {
143 247 : if (getToMultiApp()->hasLocalApp(i))
144 : {
145 235 : Moose::ScopedCommSwapper swapper(getToMultiApp()->comm());
146 :
147 : // Loop over the parent app nodes and set the value of the variable
148 235 : System * to_sys = find_sys(getToMultiApp()->appProblemBase(i).es(), _to_var_name);
149 :
150 235 : unsigned int sys_num = to_sys->number();
151 235 : unsigned int var_num = to_sys->variable_number(_to_var_name);
152 :
153 235 : NumericVector<Real> & solution = getToMultiApp()->appTransferVector(i, _to_var_name);
154 :
155 235 : MooseMesh * mesh = NULL;
156 :
157 235 : if (_displaced_target_mesh && getToMultiApp()->appProblemBase(i).getDisplacedProblem())
158 54 : mesh = &getToMultiApp()->appProblemBase(i).getDisplacedProblem()->mesh();
159 : else
160 181 : mesh = &getToMultiApp()->appProblemBase(i).mesh();
161 :
162 235 : _blk_ids.clear();
163 235 : _bnd_ids.clear();
164 705 : if (isParamValid("block"))
165 : {
166 : const std::vector<SubdomainName> & blocks =
167 202 : getParam<std::vector<SubdomainName>>("block");
168 199 : for (const auto & b : blocks)
169 101 : if (!MooseMeshUtils::hasSubdomainName(*mesh, b))
170 6 : paramError("block", "The block '", b, "' was not found in the mesh");
171 :
172 98 : std::vector<SubdomainID> ids = mesh->getSubdomainIDs(blocks);
173 98 : _blk_ids.insert(ids.begin(), ids.end());
174 98 : }
175 402 : else if (isParamValid("boundary"))
176 : {
177 : const std::vector<BoundaryName> & boundary_names =
178 6 : getParam<std::vector<BoundaryName>>("boundary");
179 3 : for (const auto & b : boundary_names)
180 3 : if (!MooseMeshUtils::hasBoundaryName(*mesh, b))
181 6 : paramError("boundary", "The boundary '", b, "' was not found in the mesh");
182 :
183 0 : std::vector<BoundaryID> ids = mesh->getBoundaryIDs(boundary_names, true);
184 0 : _bnd_ids.insert(ids.begin(), ids.end());
185 0 : }
186 :
187 229 : auto & fe_type = to_sys->variable_type(var_num);
188 229 : bool is_constant = fe_type.order == CONSTANT;
189 229 : bool is_nodal = fe_type.family == LAGRANGE;
190 :
191 229 : if (fe_type.order > FIRST && !is_nodal)
192 0 : mooseError("We don't currently support second order or higher elemental variable ");
193 :
194 : const UserObject & user_object =
195 229 : getToMultiApp()->problemBase().getUserObjectBase(_user_object_name);
196 : mooseAssert(_from_transforms.size() == 1, "This should have size 1");
197 229 : const auto & from_transform = *_from_transforms[0];
198 229 : const auto & to_transform = *_to_transforms[i];
199 :
200 229 : if (is_nodal)
201 : {
202 2354 : for (auto & node : mesh->getMesh().local_node_ptr_range())
203 : {
204 2269 : if (blockRestricted() && !hasBlocks(mesh, node))
205 68 : continue;
206 :
207 2201 : if (boundaryRestricted() && !isBoundaryNode(mesh, node))
208 0 : continue;
209 :
210 2201 : if (node->n_dofs(sys_num, var_num) > 0) // If this variable has dofs at this node
211 : {
212 : // The zero only works for LAGRANGE!
213 2201 : dof_id_type dof = node->dof_number(sys_num, var_num, 0);
214 :
215 2201 : swapper.forceSwap();
216 : Real from_value =
217 2201 : user_object.spatialValue(from_transform.mapBack(to_transform(*node)));
218 2198 : swapper.forceSwap();
219 :
220 2198 : solution.set(dof, from_value);
221 : }
222 85 : }
223 : }
224 : else // Elemental
225 : {
226 141 : std::vector<Point> points;
227 282 : for (auto & elem : as_range(mesh->getMesh().local_elements_begin(),
228 6457 : mesh->getMesh().local_elements_end()))
229 : {
230 6034 : if (blockRestricted() && !hasBlocks(elem))
231 80 : continue;
232 :
233 5954 : if (boundaryRestricted() && !isBoundaryElem(mesh, elem))
234 0 : continue;
235 :
236 : // Skip this element if the variable has no dofs at it.
237 5954 : if (elem->n_dofs(sys_num, var_num) < 1)
238 0 : continue;
239 :
240 5954 : points.clear();
241 : // grap sample points
242 : // for constant shape function, we take the element centroid
243 5954 : if (is_constant)
244 2754 : points.push_back(elem->vertex_average());
245 : // for higher order method, we take all nodes of element
246 : // this works for the first order L2 Lagrange.
247 : else
248 16000 : for (auto & node : elem->node_ref_range())
249 12800 : points.push_back(node);
250 :
251 5954 : auto n_points = points.size();
252 5954 : unsigned int n_comp = elem->n_comp(sys_num, var_num);
253 : // We assume each point corresponds to one component of elemental variable
254 5954 : if (n_points != n_comp)
255 0 : mooseError(" Number of points ",
256 : n_points,
257 : " does not equal to number of variable components ",
258 : n_comp);
259 :
260 5954 : unsigned int offset = 0;
261 21508 : for (auto & point : points) // If this variable has dofs at this elem
262 : {
263 15554 : dof_id_type dof = elem->dof_number(sys_num, var_num, offset++);
264 :
265 15554 : swapper.forceSwap();
266 : Real from_value =
267 15554 : user_object.spatialValue(from_transform.mapBack(to_transform(point)));
268 15554 : swapper.forceSwap();
269 :
270 15554 : solution.set(dof, from_value);
271 : }
272 141 : }
273 141 : }
274 :
275 226 : solution.close();
276 226 : to_sys->update();
277 226 : }
278 : }
279 :
280 214 : break;
281 : }
282 308 : case FROM_MULTIAPP:
283 : {
284 308 : FEProblemBase & to_problem = getFromMultiApp()->problemBase();
285 : mooseAssert(_to_transforms.size() == 1, "This should only be size one");
286 308 : const auto & to_transform = *_to_transforms[0];
287 308 : MooseVariableFEBase & to_var = to_problem.getVariable(
288 : 0, _to_var_name, Moose::VarKindType::VAR_ANY, Moose::VarFieldType::VAR_FIELD_STANDARD);
289 308 : SystemBase & to_system_base = to_var.sys();
290 :
291 308 : System & to_sys = to_system_base.system();
292 :
293 308 : unsigned int to_sys_num = to_sys.number();
294 :
295 : // Only works with a serialized mesh to transfer to!
296 : mooseAssert(to_sys.get_mesh().is_serial(),
297 : "MultiAppUserObjectTransfer only works with ReplicatedMesh!");
298 :
299 308 : unsigned int to_var_num = to_sys.variable_number(to_var.name());
300 :
301 : // EquationSystems & to_es = to_sys.get_equation_systems();
302 :
303 : // Create a serialized version of the solution vector
304 308 : NumericVector<Number> * to_solution = to_sys.solution.get();
305 :
306 308 : MooseMesh * to_mesh = NULL;
307 :
308 308 : if (_displaced_target_mesh && to_problem.getDisplacedProblem())
309 0 : to_mesh = &to_problem.getDisplacedProblem()->mesh();
310 : else
311 308 : to_mesh = &to_problem.mesh();
312 :
313 308 : _blk_ids.clear();
314 308 : _bnd_ids.clear();
315 924 : if (isParamValid("block"))
316 : {
317 6 : const std::vector<SubdomainName> & blocks = getParam<std::vector<SubdomainName>>("block");
318 3 : for (const auto & b : blocks)
319 3 : if (!MooseMeshUtils::hasSubdomainName(*to_mesh, b))
320 6 : paramError("block", "The block '", b, "' was not found in the mesh");
321 :
322 0 : std::vector<SubdomainID> ids = to_mesh->getSubdomainIDs(blocks);
323 0 : _blk_ids.insert(ids.begin(), ids.end());
324 0 : }
325 915 : else if (isParamValid("boundary"))
326 : {
327 : const std::vector<BoundaryName> & boundary_names =
328 196 : getParam<std::vector<BoundaryName>>("boundary");
329 193 : for (const auto & b : boundary_names)
330 98 : if (!MooseMeshUtils::hasBoundaryName(*to_mesh, b))
331 6 : paramError("boundary", "The boundary '", b, "' was not found in the mesh");
332 :
333 95 : std::vector<BoundaryID> ids = to_mesh->getBoundaryIDs(boundary_names, true);
334 95 : _bnd_ids.insert(ids.begin(), ids.end());
335 95 : }
336 :
337 302 : auto & fe_type = to_sys.variable_type(to_var_num);
338 302 : bool is_constant = fe_type.order == CONSTANT;
339 302 : bool is_nodal = fe_type.family == LAGRANGE;
340 :
341 302 : if (fe_type.order > FIRST && !is_nodal)
342 0 : mooseError("We don't currently support second order or higher elemental variable ");
343 :
344 302 : if (_all_parent_nodes_contained_in_sub_app)
345 : {
346 : // check to see if parent app nodes or elements lies within any of the sub application
347 : // bounding boxes
348 3 : if (is_nodal)
349 : {
350 0 : for (auto & node : to_mesh->getMesh().node_ptr_range())
351 : {
352 0 : if (blockRestricted() && !hasBlocks(to_mesh, node))
353 0 : continue;
354 :
355 0 : if (boundaryRestricted() && !isBoundaryNode(to_mesh, node))
356 0 : continue;
357 :
358 0 : if (node->n_dofs(to_sys_num, to_var_num) > 0)
359 : {
360 0 : const auto transformed_node = to_transform(*node);
361 :
362 0 : unsigned int node_found_in_sub_app = 0;
363 0 : for (unsigned int i = 0; i < getFromMultiApp()->numGlobalApps(); i++)
364 : {
365 0 : if (!getFromMultiApp()->hasLocalApp(i))
366 0 : continue;
367 :
368 0 : BoundingBox app_box = getFromMultiApp()->getBoundingBox(
369 0 : i, _displaced_source_mesh, _from_transforms[i].get());
370 :
371 0 : if (app_box.contains_point(transformed_node))
372 0 : ++node_found_in_sub_app;
373 : }
374 :
375 0 : if (node_found_in_sub_app == 0)
376 0 : mooseError("MultiAppUserObjectTransfer: Parent app node ",
377 : transformed_node,
378 : " not found within the bounding box of any of the sub applications.");
379 0 : else if (node_found_in_sub_app > 1)
380 0 : mooseError("MultiAppUserObjectTransfer: Parent app node ",
381 : transformed_node,
382 : " found within the bounding box of two or more sub applications.");
383 : }
384 0 : }
385 : }
386 : else // elemental
387 : {
388 3 : std::vector<Point> points;
389 3 : for (auto & elem :
390 6 : as_range(to_mesh->getMesh().elements_begin(), to_mesh->getMesh().elements_end()))
391 : {
392 3 : if (blockRestricted() && !hasBlocks(elem))
393 0 : continue;
394 :
395 3 : if (boundaryRestricted() && !isBoundaryElem(to_mesh, elem))
396 0 : continue;
397 :
398 : // Skip this element if the variable has no dofs at it.
399 3 : if (elem->n_dofs(to_sys_num, to_var_num) < 1)
400 0 : continue;
401 :
402 3 : points.clear();
403 : // grap sample points
404 : // for constant shape function, we take the element centroid
405 3 : if (is_constant)
406 3 : points.push_back(to_transform(elem->vertex_average()));
407 : // for higher order method, we take all nodes of element
408 : // this works for the first order L2 Lagrange.
409 : else
410 0 : for (auto & node : elem->node_ref_range())
411 0 : points.push_back(to_transform(node));
412 :
413 3 : auto n_points = points.size();
414 3 : unsigned int n_comp = elem->n_comp(to_sys_num, to_var_num);
415 : // We assume each point corresponds to one component of elemental variable
416 3 : if (n_points != n_comp)
417 0 : mooseError(" Number of points ",
418 : n_points,
419 : " does not equal to number of variable components ",
420 : n_comp);
421 :
422 3 : for (auto & point : points)
423 : {
424 3 : unsigned int elem_found_in_sub_app = 0;
425 :
426 6 : for (unsigned int i = 0; i < getFromMultiApp()->numGlobalApps(); i++)
427 : {
428 3 : if (!getFromMultiApp()->hasLocalApp(i))
429 0 : continue;
430 :
431 6 : BoundingBox app_box = getFromMultiApp()->getBoundingBox(
432 3 : i, _displaced_source_mesh, _from_transforms[i].get());
433 :
434 3 : if (app_box.contains_point(point))
435 0 : ++elem_found_in_sub_app;
436 : }
437 :
438 3 : if (elem_found_in_sub_app == 0)
439 6 : mooseError("MultiAppUserObjectTransfer: Parent app element with ",
440 3 : n_points > 1 ? "node" : "centroid",
441 : " at ",
442 : point,
443 : " not found within the bounding box of any of the sub applications.");
444 :
445 0 : else if (elem_found_in_sub_app > 1)
446 0 : mooseError("MultiAppUserObjectTransfer: Parent app element with ",
447 0 : n_points > 1 ? "node" : "centroid",
448 : " at ",
449 : point,
450 : " found within the bounding box of two or more sub applications.");
451 : }
452 0 : }
453 0 : }
454 : }
455 :
456 299 : if (is_nodal)
457 : {
458 228240 : for (auto & node : to_mesh->getMesh().node_ptr_range())
459 : {
460 228061 : if (blockRestricted() && !hasBlocks(to_mesh, node))
461 0 : continue;
462 :
463 228061 : if (boundaryRestricted() && !isBoundaryNode(to_mesh, node))
464 1656 : continue;
465 :
466 226405 : if (node->n_dofs(to_sys_num, to_var_num) > 0) // If this variable has dofs at this node
467 : {
468 226405 : const auto transformed_node = to_transform(*node);
469 226405 : const auto sub_app = findSubAppToTransferFrom(transformed_node);
470 :
471 : // Check to see if a sub-app was found
472 226405 : if (sub_app == static_cast<unsigned int>(-1))
473 136309 : continue;
474 :
475 90096 : const auto & from_transform = *_from_transforms[sub_app];
476 90096 : const auto & user_object = _multi_app->appUserObjectBase(sub_app, _user_object_name);
477 :
478 90096 : dof_id_type dof = node->dof_number(to_sys_num, to_var_num, 0);
479 :
480 90096 : Real from_value = 0;
481 : {
482 90096 : Moose::ScopedCommSwapper swapper(getFromMultiApp()->comm());
483 90096 : from_value = user_object.spatialValue(from_transform.mapBack(transformed_node));
484 90096 : }
485 :
486 90096 : if (from_value == std::numeric_limits<Real>::infinity())
487 0 : mooseError("MultiAppUserObjectTransfer: Point corresponding to parent app node at (",
488 : transformed_node,
489 : ") not found in the sub application.");
490 90096 : to_solution->set(dof, from_value);
491 : }
492 179 : }
493 : }
494 : else // Elemental
495 : {
496 120 : std::vector<Point> points;
497 120 : for (auto & elem :
498 199507 : as_range(to_mesh->getMesh().elements_begin(), to_mesh->getMesh().elements_end()))
499 : {
500 199267 : if (blockRestricted() && !hasBlocks(elem))
501 1948 : continue;
502 :
503 199267 : if (boundaryRestricted() && !isBoundaryElem(to_mesh, elem))
504 588 : continue;
505 :
506 : // Skip this element if the variable has no dofs at it.
507 198679 : if (elem->n_dofs(to_sys_num, to_var_num) < 1)
508 1360 : continue;
509 :
510 197319 : points.clear();
511 : // grap sample points
512 : // for constant shape function, we take the element centroid
513 197319 : if (is_constant)
514 197319 : points.push_back(to_transform(elem->vertex_average()));
515 : // for higher order method, we take all nodes of element
516 : // this works for the first order L2 Lagrange.
517 : else
518 0 : for (auto & node : elem->node_ref_range())
519 0 : points.push_back(to_transform(node));
520 :
521 197319 : auto n_points = points.size();
522 197319 : unsigned int n_comp = elem->n_comp(to_sys_num, to_var_num);
523 : // We assume each point corresponds to one component of elemental variable
524 197319 : if (n_points != n_comp)
525 0 : mooseError(" Number of points ",
526 : n_points,
527 : " does not equal to number of variable components ",
528 : n_comp);
529 :
530 197319 : unsigned int offset = 0;
531 394638 : for (auto & point : points) // If this variable has dofs at this elem
532 : {
533 197319 : const auto sub_app = findSubAppToTransferFrom(point);
534 :
535 : // Check to see if a sub-app was found
536 197319 : if (sub_app == static_cast<unsigned int>(-1))
537 119640 : continue;
538 :
539 77679 : const auto & from_transform = *_from_transforms[sub_app];
540 : const auto & user_object =
541 77679 : getFromMultiApp()->appUserObjectBase(sub_app, _user_object_name);
542 :
543 77679 : dof_id_type dof = elem->dof_number(to_sys_num, to_var_num, offset++);
544 :
545 77679 : Real from_value = 0;
546 : {
547 77679 : Moose::ScopedCommSwapper swapper(getFromMultiApp()->comm());
548 77679 : from_value = user_object.spatialValue(from_transform.mapBack(point));
549 77679 : }
550 :
551 77679 : if (from_value == std::numeric_limits<Real>::infinity())
552 0 : mooseError("MultiAppUserObjectTransfer: Point corresponding to element's centroid (",
553 : point,
554 : ") not found in sub application.");
555 :
556 77679 : to_solution->set(dof, from_value);
557 : }
558 120 : }
559 120 : }
560 :
561 299 : to_solution->close();
562 299 : to_sys.update();
563 :
564 299 : break;
565 : }
566 : }
567 :
568 513 : postExecute();
569 513 : }
570 :
571 : bool
572 435634 : MultiAppUserObjectTransfer::blockRestricted() const
573 : {
574 435634 : return !_blk_ids.empty();
575 : }
576 :
577 : bool
578 435486 : MultiAppUserObjectTransfer::boundaryRestricted() const
579 : {
580 435486 : return !_bnd_ids.empty();
581 : }
582 :
583 : bool
584 160 : MultiAppUserObjectTransfer::hasBlocks(const Elem * elem) const
585 : {
586 160 : return _blk_ids.find(elem->subdomain_id()) != _blk_ids.end();
587 : }
588 :
589 : bool
590 204 : MultiAppUserObjectTransfer::hasBlocks(const MooseMesh * mesh, const Node * node) const
591 : {
592 204 : const auto & node_blk_ids = mesh->getNodeBlockIds(*node);
593 204 : std::set<SubdomainID> u;
594 204 : std::set_intersection(_blk_ids.begin(),
595 : _blk_ids.end(),
596 : node_blk_ids.begin(),
597 : node_blk_ids.end(),
598 : std::inserter(u, u.begin()));
599 408 : return !u.empty();
600 204 : }
601 :
602 : bool
603 2208 : MultiAppUserObjectTransfer::isBoundaryNode(const MooseMesh * mesh, const Node * node) const
604 : {
605 3864 : for (auto & bid : _bnd_ids)
606 2208 : if (mesh->isBoundaryNode(node->id(), bid))
607 552 : return true;
608 1656 : return false;
609 : }
610 :
611 : bool
612 882 : MultiAppUserObjectTransfer::isBoundaryElem(const MooseMesh * mesh, const Elem * elem) const
613 : {
614 1470 : for (auto & bid : _bnd_ids)
615 882 : if (mesh->isBoundaryElem(elem->id(), bid))
616 294 : return true;
617 588 : return false;
618 : }
619 :
620 : unsigned int
621 423724 : MultiAppUserObjectTransfer::findSubAppToTransferFrom(const Point & p)
622 : {
623 : // Just find the nearest app to this point
624 423724 : if (_nearest_sub_app)
625 : {
626 207132 : unsigned int closest_app = 0;
627 207132 : Real closest_distance = std::numeric_limits<Real>::max();
628 :
629 : mooseAssert(_multi_app->numGlobalApps() > 0, "No Multiapps To Transfer From");
630 :
631 621396 : for (unsigned int i = 0; i < _multi_app->numGlobalApps(); i++)
632 : {
633 : // Obtain the possibly transformed app position by querying the transform with the origin
634 414264 : const auto app_position = _multi_app->runningInPosition()
635 414264 : ? (*_from_transforms[i])(_multi_app->position(i))
636 414264 : : (*_from_transforms[i])(Point(0));
637 :
638 414264 : auto distance = (p - app_position).norm();
639 :
640 414264 : if (distance < closest_distance)
641 : {
642 309864 : closest_app = i;
643 309864 : closest_distance = distance;
644 : }
645 : }
646 :
647 : // We can only get the value if we have this app
648 : // otherwise - another processor will set it
649 207132 : if (_multi_app->hasLocalApp(closest_app))
650 155349 : return closest_app;
651 : else
652 51783 : return -1;
653 : }
654 :
655 : // Find the app that contains this point...
656 :
657 : // This loop counts _down_ so that it can preserve legacy behavior of the
658 : // last sub-app "winning" to be able to set the value at this point
659 626397 : for (int i = _multi_app->numGlobalApps() - 1; i >= 0; i--)
660 : {
661 422231 : if (!_multi_app->hasLocalApp(i))
662 103339 : continue;
663 :
664 : BoundingBox app_box =
665 318892 : _multi_app->getBoundingBox(i, _displaced_source_mesh, _from_transforms[i].get());
666 :
667 318892 : if (_skip_bbox_check || app_box.contains_point(p))
668 12426 : return static_cast<unsigned int>(i);
669 : }
670 :
671 204166 : return -1;
672 : }
|