https://mooseframework.inl.gov
Loading...
Searching...
No Matches
MultiAppTransfer.C
Go to the documentation of this file.
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// MOOSE includes
11#include "MultiAppTransfer.h"
12#include "Transfer.h"
13#include "MooseTypes.h"
14#include "FEProblem.h"
15#include "DisplacedProblem.h"
16#include "MultiApp.h"
17#include "MooseMesh.h"
18#include "UserObject.h"
19
20#include "libmesh/parallel_algebra.h"
21#include "libmesh/mesh_tools.h"
22
25{
27 params.addDeprecatedParam<MultiAppName>("multi_app",
28 "The name of the MultiApp to transfer data with",
29 "Use to_multiapp & from_multiapp parameters now");
30 params.addParam<MultiAppName>("from_multi_app", "The name of the MultiApp to receive data from");
31 params.addParam<MultiAppName>("to_multi_app", "The name of the MultiApp to transfer the data to");
32
33 // MultiAppTransfers by default will execute with their associated MultiApp. These flags will be
34 // added by FEProblemBase when the transfer is added.
35 ExecFlagEnum & exec_enum = params.set<ExecFlagEnum>("execute_on", true);
37 // Add the POST_ADAPTIVITY execution flag.
38#ifdef LIBMESH_ENABLE_AMR
39 exec_enum.addAvailableFlags(EXEC_POST_ADAPTIVITY);
40#endif
41 exec_enum = EXEC_SAME_AS_MULTIAPP;
42 params.setDocString("execute_on", exec_enum.getDocString());
43
44 params.addParam<bool>(
45 "check_multiapp_execute_on",
46 true,
47 "When false the check between the multiapp and transfer execute on flags is not performed.");
48 params.addParam<bool>("displaced_source_mesh",
49 false,
50 "Whether or not to use the displaced mesh for the source mesh.");
51 params.addParam<bool>("displaced_target_mesh",
52 false,
53 "Whether or not to use the displaced mesh for the target mesh.");
55 return params;
56}
57
58void
60{
61 params.addRangeCheckedParam<Real>(
62 "bbox_factor",
63 1 + TOLERANCE,
64 "bbox_factor>0",
65 "Multiply bounding box width (in all directions) by the prescribed factor. Values less than "
66 "1 will shrink the bounding box; values greater than 1 will enlarge the bounding box. It is "
67 "generally not advised to ever shrink the bounding box. On the other hand it may be helpful "
68 "to enlarge the bounding box. Larger bounding boxes will lead to more accurate determination "
69 "of the closest node/element with the tradeoff of more communication.");
70}
71
72void
74{
75 params.addParam<bool>(
76 "skip_coordinate_collapsing",
77 true,
78 "Whether to skip coordinate collapsing (translation and rotation are still performed, only "
79 "XYZ, RZ etc collapsing is skipped) when performing mapping and inverse "
80 "mapping coordinate transformation operations. This parameter should only "
81 "be set by users who really know what they're doing.");
82 params.addParamNamesToGroup("skip_coordinate_collapsing", "Advanced");
83}
84
85void
87{
88 params.addParam<bool>("warn_source_object_execution_schedule",
89 true,
90 "Emit a warning when the transfer execution schedule is detected to lag "
91 "information from the user object. Note that the check cannot detect all "
92 "potential wrong combinations of user-object/transfer execution schedules");
93}
94
96 : Transfer(parameters),
97 _skip_coordinate_collapsing(getParam<bool>("skip_coordinate_collapsing")),
98 _displaced_source_mesh(getParam<bool>("displaced_source_mesh")),
99 _displaced_target_mesh(getParam<bool>("displaced_target_mesh")),
100 _bbox_factor(isParamValid("bbox_factor") ? getParam<Real>("bbox_factor") : 1)
101{
102 // Get the multiapps from their names
103 if (!isParamValid("multi_app"))
104 {
105 if (isParamValid("from_multi_app"))
106 {
107 _from_multi_app = _fe_problem.getMultiApp(getParam<MultiAppName>("from_multi_app"));
109 }
110 if (isParamValid("to_multi_app"))
111 {
112 _to_multi_app = _fe_problem.getMultiApp(getParam<MultiAppName>("to_multi_app"));
114 }
115 if (!isParamValid("direction") && !isParamValid("from_multi_app") &&
116 !isParamValid("to_multi_app"))
117 mooseError("from_multi_app and/or to_multi_app must be specified");
118 }
119 else
120 {
121 // Check deprecated direction parameter
122 for (const auto & dir : _directions)
123 {
124 if (dir == FROM_MULTIAPP)
125 {
126 _from_multi_app = _fe_problem.getMultiApp(getParam<MultiAppName>("multi_app"));
128 }
129 else if (dir == TO_MULTIAPP)
130 {
131 _to_multi_app = _fe_problem.getMultiApp(getParam<MultiAppName>("multi_app"));
133 }
134 else
135 paramError("direction",
136 "BETWEN_MULTIAPP transfers should be specified using to/from_multi_app");
137 }
138 }
139
140 if (getParam<bool>("check_multiapp_execute_on"))
142
143 // Fill direction attributes, for backward compatibility but also convenience
144 if (!isParamValid("direction"))
145 {
147 _directions.setAdditionalValue("from_multiapp");
149 _directions.setAdditionalValue("to_multiapp");
151 _directions.setAdditionalValue("between_multiapp");
152
153 // So it's available in the next constructors
156 }
157
158 // Check the parameter for sibling transfers being nested within multiapp execution loop
159 const auto & exec_on = getExecuteOnEnum();
160 if (getParam<bool>("check_multiapp_execute_on") && isParamValid("execute_after_from_multiapp") &&
162 ((_from_multi_app->getExecuteOnEnum() != exec_on) &&
163 !(exec_on.size() == 1 && int(exec_on.get(0)) == EXEC_SAME_AS_MULTIAPP)))
164 paramError("execute_after_from_multiapp",
165 "This parameter is only obeyed when the from_multi_app and the transfer are "
166 "executing on the same execute_on flag.\nfrom_multi_app execution schedule: ",
167 Moose::stringify(_from_multi_app->getExecuteOnEnum()),
168 "\nTransfer execution schedule: ",
169 Moose::stringify(exec_on),
170 "\nYou can disable this error by setting 'check_multiapp_execute_on' to false.");
171 // This parameter is only obeyed for BETWEEN_MULTIAPP
172 if (!(_directions.size() == 1 && _directions.get(0) == BETWEEN_MULTIAPP) &&
173 isParamValid("execute_after_from_multiapp"))
174 paramError("execute_after_from_multiapp",
175 "This parameter is only intended for modifying the execution schedule of "
176 "siblings transfers, e.g. transfers from a from_multi_app to a to_multi_app");
177 // The default isn't enough to achieve staggering unless users staggered the multiapps.
178 // This is effectively a warning by default for sibling transfers BUT:
179 // - the order of execution is actually important here. You don't want to make things explicit
180 // (in terms of time integration) by lagging a term on accident
181 // - we would need dependency resolution between multiapps to set the order group to get
182 // staggering by default.
183 if (getParam<bool>("check_multiapp_execute_on") && _directions.contains("between_multiapp") &&
185 _from_multi_app->getParam<unsigned int>("execution_order_group") >=
186 _to_multi_app->getParam<unsigned int>("execution_order_group") &&
187 // no need to check ordering groups if executing apps on different schedules
188 _from_multi_app->getExecuteOnEnum() == _to_multi_app->getExecuteOnEnum() &&
189 // no need to check ordering groups if transfer is executed on a different schedule
190 ((_from_multi_app->getExecuteOnEnum() == exec_on) ||
191 (exec_on.size() == 1 && int(exec_on.get(0)) == EXEC_SAME_AS_MULTIAPP)))
192 paramWarning("execute_after_from_multiapp",
193 "Transfer is set to execute after the 'from_multi_app' but the 'to_multi_app' is "
194 "executing before or in the same 'execution_order_group' as the 'from_multi_app'. "
195 "Thus the transfer is not actually executing in between the 'from_' and "
196 "'to_multi_app', but after both.\nfrom_multi_app execution order group: ",
197 Moose::stringify(_from_multi_app->getParam<unsigned int>("execution_order_group")),
198 "\nto_multi_app execution order group: ",
199 Moose::stringify(_to_multi_app->getParam<unsigned int>("execution_order_group")),
200 "\nYou can disable this warning by setting 'check_multiapp_execute_on' to false.");
201
202 // Handle deprecated parameters
203 if (parameters.isParamSetByUser("direction"))
204 {
205 if (!isParamValid("multi_app"))
206 paramError("direction",
207 "The deprecated 'direction' parameter is meant to be used in conjunction with the "
208 "'multi_app' parameter");
209 if (isParamValid("to_multi_app") || isParamValid("from_multi_app"))
210 paramError("direction",
211 "The deprecated 'direction' parameter is not meant to be used in conjunction with "
212 "the 'from_multi_app' or 'to_multi_app' parameters");
213 }
214}
215
216void
218{
220 if (getExecuteOnEnum() != _from_multi_app->getExecuteOnEnum())
221 mooseDoOnce(
222 mooseWarning("MultiAppTransfer execute_on flags do not match associated from_multi_app "
223 "execute_on flags"));
224
226 if (getExecuteOnEnum() != _to_multi_app->getExecuteOnEnum())
227 mooseDoOnce(
228 mooseWarning("MultiAppTransfer execute_on flags do not match associated to_multi_app "
229 "execute_on flags"));
230
231 // In the case of siblings transfer, the check will be looser
233 if (getExecuteOnEnum() != _from_multi_app->getExecuteOnEnum() &&
234 getExecuteOnEnum() != _to_multi_app->getExecuteOnEnum())
235 mooseDoOnce(
236 mooseWarning("MultiAppTransfer execute_on flags do not match associated to_multi_app "
237 "and from_multi_app execute_on flags"));
238}
239
240void
241MultiAppTransfer::variableIntegrityCheck(const AuxVariableName & var_name,
242 bool is_from_multiapp) const
243{
244 bool variable_found = false;
245 bool has_an_app = false;
246
247 // Check the from_multi_app for the variable
248 if (is_from_multiapp && _from_multi_app)
249 for (unsigned int i = 0; i < _from_multi_app->numGlobalApps(); i++)
250 if (_from_multi_app->hasLocalApp(i))
251 {
252 has_an_app = true;
253 if (_from_multi_app->appProblemBase(i).hasVariable(var_name))
254 variable_found = true;
255 }
256
257 // Check the to_multi_app for the variable
258 if (!is_from_multiapp && _to_multi_app)
259 for (unsigned int i = 0; i < _to_multi_app->numGlobalApps(); i++)
260 if (_to_multi_app->hasLocalApp(i))
261 {
262 has_an_app = true;
263 if (_to_multi_app->appProblemBase(i).hasVariable(var_name))
264 variable_found = true;
265 }
266
267 if (!variable_found && has_an_app)
268 mooseError("Cannot find variable ", var_name, " for ", name(), " Transfer");
269}
270
271void
273{
274 // Check for siblings transfer support
277
278 getAppInfo();
279
280 if (_from_multi_app)
281 _from_multi_app->addAssociatedTransfer(*this);
282 if (_to_multi_app)
283 _to_multi_app->addAssociatedTransfer(*this);
284}
285
286void
288{
289 // I would like to do all of this in initialSetup, but it will fail with
290 // multiapps that reset. A reset deletes and rebuilds the FEProblems so all
291 // of the pointers will be broken.
292
293 // Clear the vectors since we've probably built them up from a previous call
294 _from_problems.clear();
295 _to_problems.clear();
296 _from_es.clear();
297 _to_es.clear();
298 _from_meshes.clear();
299 _to_meshes.clear();
300 _to_positions.clear();
301 _from_positions.clear();
302 _to_transforms.clear();
303 _from_transforms.clear();
304 // Clear this map since we build it from scratch every time we transfer
305 // Otherwise, this will cause two issues: 1) increasing memory usage
306 // for a simulation that requires many transfers, 2) producing wrong results
307 // when we do collective communication on this vector.
308 _to_local2global_map.clear();
310
311 // Build the vectors for to problems, from problems, and subapps positions.
313 {
314 _to_problems.push_back(&_from_multi_app->problemBase());
315 _to_positions.push_back(Point(0., 0., 0.));
317 }
319 {
320 _from_problems.push_back(&_to_multi_app->problemBase());
321 _from_positions.push_back(Point(0., 0., 0.));
323 }
325 {
326 mooseAssert(&_from_multi_app->problemBase().coordTransform() ==
327 &_to_multi_app->problemBase().coordTransform(),
328 "I believe these should be the same. If not, then it will be difficult to define a "
329 "canonical reference frame.");
332 }
333
334 // Build the from and to equation systems and mesh vectors.
335 for (unsigned int i = 0; i < _to_problems.size(); i++)
336 {
337 // TODO: Do I actually want es or displaced es?
338 _to_es.push_back(&_to_problems[i]->es());
339 if (_displaced_target_mesh && _to_problems[i]->getDisplacedProblem())
340 _to_meshes.push_back(&_to_problems[i]->getDisplacedProblem()->mesh());
341 else
342 _to_meshes.push_back(&_to_problems[i]->mesh());
343 }
344
345 for (unsigned int i = 0; i < _from_problems.size(); i++)
346 {
347 _from_es.push_back(&_from_problems[i]->es());
348 if (_displaced_source_mesh && _from_problems[i]->getDisplacedProblem())
349 _from_meshes.push_back(&_from_problems[i]->getDisplacedProblem()->mesh());
350 else
351 _from_meshes.push_back(&_from_problems[i]->mesh());
352 }
353
354 // The coordinate transform data of a multiapp is read from its app 0 and broadcast to all ranks.
355 // App 0 does not necessarily live on the main-app's rank 0: when multiapps are executed
356 // concurrently they are partitioned onto disjoint subsets of ranks, so a child's app 0 may sit
357 // on any rank. Read the data on whichever rank owns app 0 and broadcast from there. The parent
358 // app problem, by contrast, is always available on rank 0.
359 auto app0_root = [this](MultiApp & multiapp)
360 {
361 processor_id_type root = 0;
362 if (multiapp.hasLocalApp(0) && multiapp.isRootProcessor())
363 root = _communicator.rank();
364 _communicator.max(root);
365 return root;
366 };
367
368 MooseAppCoordTransform::MinimalData from_app_transform_construction_data{};
370 {
371 if (_communicator.rank() == 0)
372 from_app_transform_construction_data =
373 _to_multi_app->problemBase().coordTransform().minimalDataDescription();
374 _communicator.broadcast(from_app_transform_construction_data);
375 }
376 else
377 {
378 const auto root = app0_root(*_from_multi_app);
379 if (_communicator.rank() == root)
380 from_app_transform_construction_data =
381 _from_multi_app->appProblemBase(0).coordTransform().minimalDataDescription();
382 _communicator.broadcast(from_app_transform_construction_data, root);
383 }
385 std::make_unique<MooseAppCoordTransform>(from_app_transform_construction_data);
386
387 MooseAppCoordTransform::MinimalData to_app_transform_construction_data{};
389 {
390 if (_communicator.rank() == 0)
391 to_app_transform_construction_data =
392 _from_multi_app->problemBase().coordTransform().minimalDataDescription();
393 _communicator.broadcast(to_app_transform_construction_data);
394 }
395 else
396 {
397 const auto root = app0_root(*_to_multi_app);
398 if (_communicator.rank() == root)
399 to_app_transform_construction_data =
400 _to_multi_app->appProblemBase(0).coordTransform().minimalDataDescription();
401 _communicator.broadcast(to_app_transform_construction_data, root);
402 }
404 std::make_unique<MooseAppCoordTransform>(to_app_transform_construction_data);
405
406 /*
407 * skip_coordinate_collapsing: whether to set the transform to skip coordinate collapsing
408 * (from XYZ to RZ for example)
409 * transforms: vector of transforms to add the new transforms to
410 * moose_app_transform: base for the new transform
411 * is_parent_app_transform: whether working on the transform for the parent app (this app, the
412 * one creating the transfer) or for child apps
413 * multiapp: pointer to the multiapp to obtain the position of the child apps
414 */
415 auto create_multiapp_transforms = [this](auto & transforms,
416 const auto & moose_app_transform,
417 const bool is_parent_app_transform,
418 const MultiApp * const multiapp = nullptr)
419 {
420 mooseAssert(is_parent_app_transform || multiapp,
421 "Coordinate transform must be created either for child app or parent app");
422 if (is_parent_app_transform)
423 {
424 transforms.push_back(std::make_unique<MultiAppCoordTransform>(moose_app_transform));
425 transforms.back()->skipCoordinateCollapsing(_skip_coordinate_collapsing);
426 // zero translation
427 }
428 else
429 {
430 mooseAssert(transforms.size() == 0, "transforms should not be initialized at this point");
431 for (const auto i : make_range(multiapp->numGlobalApps()))
432 {
433 transforms.push_back(std::make_unique<MultiAppCoordTransform>(moose_app_transform));
434 auto & transform = transforms[i];
435 transform->skipCoordinateCollapsing(_skip_coordinate_collapsing);
436 if (multiapp->usingPositions())
437 transform->setTranslationVector(multiapp->position(i));
438 }
439 }
440 };
441
443 {
444 create_multiapp_transforms(
446 create_multiapp_transforms(_from_transforms, *_from_moose_app_transform, true);
447 }
449 {
450 create_multiapp_transforms(_to_transforms, *_to_moose_app_transform, true);
451 create_multiapp_transforms(
453 }
455 {
456 create_multiapp_transforms(
458 create_multiapp_transforms(
460 }
461
462 auto check_transform_compatibility = [this](const MultiAppCoordTransform & transform)
463 {
464 if (transform.hasNonTranslationTransformation() && !usesMooseAppCoordTransform())
465 mooseWarning("Transfer '",
466 name(),
467 "' of type '",
468 type(),
469 "' has non-translation transformations but it does not implement coordinate "
470 "transformations using the 'MooseAppCoordTransform' class. Your data transfers "
471 "will not be performed in the expected transformed frame");
472 };
473
474 // set the destination coordinate systems for each transform for the purposes of determining
475 // coordinate collapsing. For example if TO is XYZ and FROM is RZ, then TO will have its XYZ
476 // coordinates collapsed into RZ and FROM will have a no-op for coordinate collapsing
477
478 for (const auto i : index_range(_from_transforms))
479 {
480 auto & from_transform = _from_transforms[i];
481 from_transform->setDestinationCoordTransform(*_to_moose_app_transform);
482 if (i == 0)
483 check_transform_compatibility(*from_transform);
484 }
485 for (const auto i : index_range(_to_transforms))
486 {
487 auto & to_transform = _to_transforms[i];
488 to_transform->setDestinationCoordTransform(*_from_moose_app_transform);
489 if (i == 0)
490 check_transform_compatibility(*to_transform);
491 }
492}
493
494namespace
495{
496void
497fillInfo(MultiApp & multi_app,
498 std::vector<unsigned int> & map,
499 std::vector<FEProblemBase *> & problems,
500 std::vector<Point> & positions)
501{
502 for (unsigned int i_app = 0; i_app < multi_app.numGlobalApps(); i_app++)
503 {
504 if (!multi_app.hasLocalApp(i_app))
505 continue;
506
507 auto & subapp_problem = multi_app.appProblemBase(i_app);
508
509 map.push_back(i_app);
510 problems.push_back(&subapp_problem);
511 if (multi_app.usingPositions())
512 positions.push_back(multi_app.position(i_app));
513 }
514}
515}
516
517void
519{
520 if (!_to_multi_app)
521 mooseError("There is no to_multiapp to get info from");
522
524}
525
526void
528{
529 if (!_from_multi_app)
530 mooseError("There is no from_multiapp to get info from");
531
533}
534
535void
537{
538 MultiApp::transformBoundingBox(box, transform);
539}
540
541void
542MultiAppTransfer::extendBoundingBoxes(const Real factor, std::vector<BoundingBox> & bboxes) const
543{
544 const auto extension_factor = factor - 1;
545
546 // Extend (or contract if the extension factor is negative) bounding boxes along all the
547 // directions by the same length. Greater than zero values of this member may be necessary because
548 // the nearest bounding box does not necessarily give you the closest node/element. It will depend
549 // on the partition and geometry. A node/element will more likely find its nearest source
550 // element/node by extending bounding boxes. If each of the bounding boxes covers the entire
551 // domain, a node/element will be able to find its nearest source element/node for sure, but at
552 // the same time, more communication will be involved and can be expensive.
553 for (auto & box : bboxes)
554 {
555 // libmesh set an invalid bounding box using this code
556 // for (unsigned int i=0; i<LIBMESH_DIM; i++)
557 // {
558 // this->first(i) = std::numeric_limits<Real>::max();
559 // this->second(i) = -std::numeric_limits<Real>::max();
560 // }
561 // If it is an invalid box, we should skip it
562 if (box.first(0) == std::numeric_limits<Real>::max())
563 continue;
564
565 auto width = box.second - box.first;
566 box.second += width * extension_factor;
567 box.first -= width * extension_factor;
568 }
569}
570
571std::vector<BoundingBox>
573{
574 std::vector<std::pair<Point, Point>> bb_points(_from_meshes.size());
575 for (unsigned int i = 0; i < _from_meshes.size(); i++)
576 {
577 // Get a bounding box around the mesh elements that are local to the current
578 // processor.
580
581 // Translate the bounding box to the from domain's position. We may have rotations so we must
582 // be careful in constructing the new min and max (first and second)
583 const auto from_global_num = getGlobalSourceAppIndex(i);
584 transformBoundingBox(bbox, *_from_transforms[from_global_num]);
585
586 // Cast the bounding box into a pair of points (so it can be put through
587 // MPI communication).
588 bb_points[i] = static_cast<std::pair<Point, Point>>(bbox);
589 }
590
591 // Serialize the bounding box points.
592 _communicator.allgather(bb_points);
593
594 // Recast the points back into bounding boxes and return.
595 std::vector<BoundingBox> bboxes(bb_points.size());
596 for (unsigned int i = 0; i < bb_points.size(); i++)
597 bboxes[i] = static_cast<BoundingBox>(bb_points[i]);
598
599 // possibly extend bounding boxes
601
602 return bboxes;
603}
604
605std::vector<BoundingBox>
607{
608 std::vector<std::pair<Point, Point>> bb_points(_from_meshes.size());
609 const Real min_r = std::numeric_limits<Real>::lowest();
610 const Real max_r = std::numeric_limits<Real>::max();
611
612 for (unsigned int i = 0; i < _from_meshes.size(); i++)
613 {
614
615 Point min(max_r, max_r, max_r);
616 Point max(min_r, min_r, min_r);
617 bool at_least_one = false;
618
619 // TODO: Factor this into mesh_tools after adding new boundary bounding box routine.
620 const ConstBndNodeRange & bnd_nodes = *_from_meshes[i]->getBoundaryNodeRange();
621 for (const auto & bnode : bnd_nodes)
622 {
623 if (bnode->_bnd_id == boundary_id &&
624 bnode->_node->processor_id() == _from_meshes[i]->processor_id())
625 {
626 at_least_one = true;
627 const auto & node = *bnode->_node;
628 for (const auto i : make_range(Moose::dim))
629 {
630 min(i) = std::min(min(i), node(i));
631 max(i) = std::max(max(i), node(i));
632 }
633 }
634 }
635
636 BoundingBox bbox(min, max);
637 if (!at_least_one)
638 bbox.min() = max; // If we didn't hit any nodes, this will be _the_ minimum bbox
639 else
640 {
641 // Translate the bounding box to the from domain's position. We may have rotations so we must
642 // be careful in constructing the new min and max (first and second)
643 const auto from_global_num = getGlobalSourceAppIndex(i);
644 transformBoundingBox(bbox, *_from_transforms[from_global_num]);
645 }
646
647 // Cast the bounding box into a pair of points (so it can be put through
648 // MPI communication).
649 bb_points[i] = static_cast<std::pair<Point, Point>>(bbox);
650 }
651
652 // Serialize the bounding box points.
653 _communicator.allgather(bb_points);
654
655 // Recast the points back into bounding boxes and return.
656 std::vector<BoundingBox> bboxes(bb_points.size());
657 for (unsigned int i = 0; i < bb_points.size(); i++)
658 bboxes[i] = static_cast<BoundingBox>(bb_points[i]);
659
660 // possibly extend bounding boxes
662
663 return bboxes;
664}
665
666std::vector<unsigned int>
668{
669 std::vector<unsigned int> froms_per_proc;
670 if (_to_multi_app)
671 froms_per_proc.resize(n_processors(), 1);
672 if (_from_multi_app)
673 {
674 froms_per_proc.resize(n_processors());
675 _communicator.allgather(_from_multi_app->numLocalApps(), froms_per_proc);
676 }
677 return froms_per_proc;
678}
679
680NumericVector<Real> &
681MultiAppTransfer::getTransferVector(unsigned int i_local, std::string var_name)
682{
683 mooseAssert(_to_multi_app, "getTransferVector only works for transfers to multiapps");
684
685 return _to_multi_app->appTransferVector(_to_local2global_map[i_local], var_name);
686}
687
688void
690 const VariableName & var_name,
691 const std::string & param_name) const
692{
693 if (!fe_problem.hasVariable(var_name))
694 {
695 if (param_name.empty())
696 mooseError("The variable '", var_name, "' does not exist.");
697 else
698 paramError(param_name, "The variable '", var_name, "' does not exist.");
699 }
700}
701
702Point
704 const Point & p,
705 const std::string & phase) const
706{
707 if (transform.hasCoordinateSystemTypeChange())
708 {
710 mooseInfo(phase + " cannot use the point in the app frame due to the "
711 "non-uniqueness of the coordinate collapsing reverse mapping."
712 " Coordinate collapse is ignored for this operation");
713 transform.skipCoordinateCollapsing(true);
714 const auto pt = transform.mapBack(p);
715 transform.skipCoordinateCollapsing(false);
716 return pt;
717 }
718 else
719 return transform.mapBack(p);
720}
721
722Point
724 unsigned int local_i_from,
725 const std::string & phase) const
726{
728 *_from_transforms[getGlobalSourceAppIndex(local_i_from)], p, phase);
729}
730
731Point
733 unsigned int local_i_to,
734 const std::string & phase) const
735{
737}
738
739unsigned int
741{
742 mooseAssert(_current_direction == TO_MULTIAPP || i_from < _from_local2global_map.size(),
743 "Out of bounds local from-app index");
745}
746
747unsigned int
749{
750 mooseAssert(_current_direction == FROM_MULTIAPP || i_to < _to_local2global_map.size(),
751 "Out of bounds local to-app index");
753}
754
755unsigned int
757{
759 ? 0
761}
762
763void
764MultiAppTransfer::checkParentAppUserObjectExecuteOn(const std::string & object_name) const
765{
766 // Source app is not the parent, most execution schedules are fine since the transfer occurs after
767 // the app has run NOTE: not true for siblings transfer
768 if (hasFromMultiApp())
769 return;
770 // Get user object from parent. We don't know the type
771 const auto & uo = _fe_problem.getUserObject<UserObject>(object_name);
772 // If we are executing on transfers, every additional schedule is not a problem
773 if (uo.getExecuteOnEnum().contains(EXEC_TRANSFER))
774 return;
775 // If we are transferring on the same schedule as we are executing, we are lagging. Is it on
776 // purpose? We don't know, so we will give a warning unless silenced.
777 // The derived-classes offer the parameter to silence this warning
778 // Note: UOs execute before transfers on INITIAL so it's not a problem at this time
779 if (uo.getExecuteOnEnum().contains(_fe_problem.getCurrentExecuteOnFlag()) &&
781 if (!isParamValid("warn_source_object_execution_schedule") ||
782 getParam<bool>("warn_source_object_execution_schedule"))
783 uo.paramWarning("execute_on",
784 "This UserObject-derived class is being executed on '" +
786 "' and also providing values for the '" + name() +
787 "' transfer, on that same execution schedule. Because user objects are "
788 "executed after transfers are, this means the values provided by this "
789 "user object are lagged. If you are ok with this, then set the "
790 "'warn_source_object_execution_schedule' parameter to false in this "
791 "Transfer. If not, then execute '" +
792 uo.name() +
793 "' on TRANSFER by adding it to the 'execute_on' vector parameter.");
794}
795
796void
798{
799 // parent app is the source app, EXEC_TRANSFER is fine
800 if (!hasFromMultiApp())
801 return;
802 // Get the app and problem
803 const auto & app = getFromMultiApp();
804 if (!app->hasApp())
805 return;
806 const auto & problem = app->appProblemBase(app->firstLocalApp());
807 // Use the warehouse to find the object
808 std::vector<SetupInterface *> objects_with_exec_on;
809 problem.theWarehouse()
810 .query()
811 .template condition<AttribName>(object_name)
812 .template condition<AttribExecOns>(EXEC_TRANSFER)
813 .queryInto(objects_with_exec_on);
814 if (objects_with_exec_on.size())
815 mooseError("Object '" + object_name +
816 "' should not be executed on EXEC_TRANSFER, because this transfer has "
817 "indicated it does not support it.\nExecuting this object on TIMESTEP_END should be "
818 "sufficient to get updated values.");
819}
boundary_id_type BoundaryID
const ExecFlagType EXEC_TRANSFER
Definition Moose.C:58
const ExecFlagType EXEC_SAME_AS_MULTIAPP
Definition Moose.C:56
const ExecFlagType EXEC_POST_ADAPTIVITY
Definition Moose.C:61
const ExecFlagType EXEC_INITIAL
Definition Moose.C:31
A MultiMooseEnum object to hold "execute_on" flags.
void addAvailableFlags(const ExecFlagType &flag, Args... flags)
Add additional execute_on flags to the list of possible flags.
Specialization of SubProblem for solving nonlinear equations plus auxiliary equations.
T & getUserObject(const std::string &name, unsigned int tid=0) const
Get the user object by its name.
std::shared_ptr< MultiApp > getMultiApp(const std::string &multi_app_name) const
Get a MultiApp object by name.
virtual bool hasVariable(const std::string &var_name) const override
Whether or not this problem has the variable.
const ExecFlagType & getCurrentExecuteOnFlag() const
Return/set the current execution flag.
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
void addParamNamesToGroup(const std::string &space_delim_names, const std::string group_name)
This method takes a space delimited list of parameter names and adds them to the specified group name...
bool isParamSetByUser(const std::string &name) const
Method returns true if the parameter was set by the user.
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an optional parameter and a documentation string to the InputParameters object.
void addDeprecatedParam(const std::string &name, const T &value, const std::string &doc_string, const std::string &deprecation_message)
void setDocString(const std::string &name, const std::string &doc)
Set the doc string of a parameter.
T & set(const std::string &name, bool quiet_mode=false)
Returns a writable reference to the named parameters.
void addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
std::tuple< short int, Real, short int, std::array< Real, 3 >, int, unsigned int, unsigned int, short int, short int, short int > MinimalData
A typedef for conveniency that describes the minimal data necessary to broadcast and build a MooseApp...
const InputParameters & parameters() const
Get the parameters of the object.
Definition MooseBase.h:131
const std::string & type() const
Get the type of this class.
Definition MooseBase.h:93
const std::string & name() const
Get the name of the class.
Definition MooseBase.h:103
void paramError(const std::string &param, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
Definition MooseBase.h:457
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type and optionally a file path to the top-level block p...
Definition MooseBase.h:271
void mooseInfo(Args &&... args) const
Definition MooseBase.h:334
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
Definition MooseBase.h:199
This class contains transformation information that only exists in a context in which there are multi...
libMesh::Point mapBack(const libMesh::Point &point) const
Inverse transform from the reference space to our space.
void skipCoordinateCollapsing(bool skip_coordinate_collapsing)
set whether coordinate collapsing operations should be skipped
static void addSkipCoordCollapsingParam(InputParameters &params)
Add the option to skip coordinate collapsing in coordinate transformation operations Note: this is us...
std::unique_ptr< MooseAppCoordTransform > _to_moose_app_transform
The moose coordinate transformation object describing rotations, scaling, and coordinate system of th...
libMesh::NumericVector< Real > & getTransferVector(unsigned int i_local, std::string var_name)
If we are transferring to a multiapp, return the appropriate solution vector.
std::vector< unsigned int > _to_local2global_map
Given local app index, returns global app index.
void initialSetup() override
Method called at the beginning of the simulation for checking integrity or doing one-time setup.
unsigned int getGlobalSourceAppIndex(unsigned int i_from) const
Return the global app index from the local index in the "from-multiapp" transfer direction.
std::vector< Point > _from_positions
virtual bool usesMooseAppCoordTransform() const
Whether this transfer handles non-translation-based transformations, e.g.
void errorIfObjectExecutesOnTransferInSourceApp(const std::string &object_name) const
Error if executing this MooseObject on EXEC_TRANSFER in a source multiapp (from_multiapp,...
unsigned int getLocalSourceAppIndex(unsigned int i_from) const
Return the local app index from the global index in the "from-multiapp" transfer direction.
bool _displaced_source_mesh
True if displaced mesh is used for the source mesh, otherwise false.
std::vector< libMesh::EquationSystems * > _from_es
std::vector< unsigned int > _from_local2global_map
Given local app index, returns global app index.
std::vector< Point > _to_positions
virtual void checkSiblingsTransferSupported() const
Whether the transfer supports siblings transfer.
std::vector< MooseMesh * > _from_meshes
static void transformBoundingBox(libMesh::BoundingBox &box, const MultiAppCoordTransform &transform)
Transform a bounding box according to the transformations in the provided coordinate transformation o...
Point mapBackWithoutCollapsing(MultiAppCoordTransform &transform, const Point &p, const std::string &phase) const
Shared implementation for getPointInSourceAppFrame / getPointInTargetAppFrame.
static void addBBoxFactorParam(InputParameters &params)
Add the bounding box factor parameter to the supplied input parameters.
std::vector< FEProblemBase * > _from_problems
static void addUserObjectExecutionCheckParam(InputParameters &params)
Add the execution order check parameter (to skip the warning if needed)
std::vector< unsigned int > getFromsPerProc()
Return the number of "from" domains that each processor owns.
virtual void getAppInfo()
This method will fill information into the convenience member variables (_to_problems,...
Point getPointInTargetAppFrame(const Point &p, unsigned int local_i_to, const std::string &phase) const
Get the target app point from a point in the reference frame.
std::unique_ptr< MooseAppCoordTransform > _from_moose_app_transform
The moose coordinate transformation object describing rotations, scaling, and coordinate system of th...
void checkVariable(const FEProblemBase &fe_problem, const VariableName &var_name, const std::string &param_name="") const
Helper for checking a problem for a variable.
MultiAppTransfer(const InputParameters &parameters)
std::vector< libMesh::BoundingBox > getFromBoundingBoxes()
Return the bounding boxes of all the "from" domains, including all the domains not local to this proc...
std::vector< std::unique_ptr< MultiAppCoordTransform > > _from_transforms
unsigned int getGlobalTargetAppIndex(unsigned int i_to) const
Return the global app index from the local index in the "to-multiapp" transfer direction.
bool _displaced_target_mesh
True if displaced mesh is used for the target mesh, otherwise false.
std::vector< FEProblemBase * > _to_problems
void checkParentAppUserObjectExecuteOn(const std::string &object_name) const
Checks the execute_on flags for user object transfers with user objects on the source app which is al...
std::shared_ptr< MultiApp > _from_multi_app
The MultiApps this Transfer is transferring data to or from.
void extendBoundingBoxes(const Real factor, std::vector< libMesh::BoundingBox > &bboxes) const
Extends bounding boxes to avoid missing points.
void checkMultiAppExecuteOn()
Helper method for checking the 'check_multiapp_execute_on' flag.
std::shared_ptr< MultiApp > _to_multi_app
std::vector< MooseMesh * > _to_meshes
static InputParameters validParams()
Real _bbox_factor
Extend (or contract) bounding box by a factor in all directions Greater than one values of this membe...
const std::shared_ptr< MultiApp > getFromMultiApp() const
Get the MultiApp to transfer data from.
Point getPointInSourceAppFrame(const Point &p, unsigned int local_i_from, const std::string &phase) const
Get the source app point from a point in the reference frame.
std::vector< libMesh::EquationSystems * > _to_es
std::vector< std::unique_ptr< MultiAppCoordTransform > > _to_transforms
void variableIntegrityCheck(const AuxVariableName &var_name, bool is_from_multiapp) const
Utility to verify that the variable in the destination system exists.
std::shared_ptr< MultiApp > _multi_app
Deprecated class attribute for compatibility with the apps.
const bool _skip_coordinate_collapsing
Whether to skip coordinate collapsing (transformations of coordinates between applications using diff...
bool hasFromMultiApp() const
Whether the transfer owns a non-null from_multi_app.
A MultiApp represents one or more MOOSE applications that are running simultaneously.
Definition MultiApp.h:140
bool usingPositions() const
Whether or not this MultiApp is using positions to track the number and location of the child applica...
Definition MultiApp.h:396
FEProblemBase & appProblemBase(unsigned int app)
Get the FEProblemBase for the global app desired.
Definition MultiApp.C:1048
bool hasLocalApp(unsigned int global_app) const
Whether or not the given global app number is on this processor.
Definition MultiApp.C:1102
const Point & position(unsigned int app) const
The physical position of a global App number.
Definition MultiApp.C:1570
unsigned int numGlobalApps() const
Definition MultiApp.h:310
static void transformBoundingBox(libMesh::BoundingBox &box, const MultiAppCoordTransform &transform)
Transform a bounding box according to the transformations in the provided coordinate transformation o...
Definition MultiApp.C:934
void setAdditionalValue(const std::string &names)
Insert operators Operator to insert (push_back) values into the enum.
unsigned int get(unsigned int i) const
Indexing operator Operator to retrieve the id of an item from the MultiMooseEnum.
bool contains(const std::string &value) const
Methods for seeing if a value is set in the MultiMooseEnum.
unsigned int size() const
Return the number of active items in the MultiMooseEnum.
const ExecFlagEnum & getExecuteOnEnum() const
Return the execute on MultiMooseEnum for this object.
void mooseWarning(Args &&... args) const
void paramWarning(const std::string &param, Args... args) const
void max(const T &r, T &o, Request &req) const
processor_id_type rank() const
void broadcast(T &data, const unsigned int root_id=0, const bool identical_sizes=false) const
void allgather(const T &send_data, std::vector< T, A > &recv_data) const
Base class for all Transfer objects.
Definition Transfer.h:40
MooseEnum _direction
Definition Transfer.h:108
@ FROM_MULTIAPP
Definition Transfer.h:71
@ TO_MULTIAPP
Definition Transfer.h:70
@ BETWEEN_MULTIAPP
Definition Transfer.h:72
static InputParameters validParams()
Definition Transfer.C:25
MultiMooseEnum _directions
The directions this Transfer is to be executed on.
Definition Transfer.h:113
FEProblemBase & _fe_problem
Definition Transfer.h:100
MooseEnum _current_direction
Definition Transfer.h:109
const bool _exec_after_source_app_exec
Whether a transfer executing on BETWEEN_MULTIAPPS and on the same execute_on flag should execute befo...
Definition Transfer.h:118
Base class for user-specific data.
Definition UserObject.h:20
const Parallel::Communicator & _communicator
processor_id_type n_processors() const
MeshBase & mesh
static constexpr std::size_t dim
This is the dimension of all vector and tensor datastructures used in MOOSE.
Definition Moose.h:175
std::string stringify(const T &t)
conversion to string
Definition Conversion.h:65
libMesh::BoundingBox create_local_bounding_box(const MeshBase &mesh)