https://mooseframework.inl.gov
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 
58 void
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 
72 void
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 
85 void
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
154  _direction = _directions[0];
156  }
157 
158  // Handle deprecated parameters
159  if (parameters.isParamSetByUser("direction"))
160  {
161  if (!isParamValid("multi_app"))
162  paramError("direction",
163  "The deprecated 'direction' parameter is meant to be used in conjunction with the "
164  "'multi_app' parameter");
165  if (isParamValid("to_multi_app") || isParamValid("from_multi_app"))
166  paramError("direction",
167  "The deprecated 'direction' parameter is not meant to be used in conjunction with "
168  "the 'from_multi_app' or 'to_multi_app' parameters");
169  }
170 }
171 
172 void
174 {
176  if (getExecuteOnEnum() != _from_multi_app->getExecuteOnEnum())
177  mooseDoOnce(
178  mooseWarning("MultiAppTransfer execute_on flags do not match associated from_multi_app "
179  "execute_on flags"));
180 
182  if (getExecuteOnEnum() != _to_multi_app->getExecuteOnEnum())
183  mooseDoOnce(
184  mooseWarning("MultiAppTransfer execute_on flags do not match associated to_multi_app "
185  "execute_on flags"));
186 
187  // In the case of siblings transfer, the check will be looser
189  if (getExecuteOnEnum() != _from_multi_app->getExecuteOnEnum() &&
190  getExecuteOnEnum() != _to_multi_app->getExecuteOnEnum())
191  mooseDoOnce(
192  mooseWarning("MultiAppTransfer execute_on flags do not match associated to_multi_app "
193  "and from_multi_app execute_on flags"));
194 }
195 
196 void
197 MultiAppTransfer::variableIntegrityCheck(const AuxVariableName & var_name,
198  bool is_from_multiapp) const
199 {
200  bool variable_found = false;
201  bool has_an_app = false;
202 
203  // Check the from_multi_app for the variable
204  if (is_from_multiapp && _from_multi_app)
205  for (unsigned int i = 0; i < _from_multi_app->numGlobalApps(); i++)
206  if (_from_multi_app->hasLocalApp(i))
207  {
208  has_an_app = true;
209  if (_from_multi_app->appProblemBase(i).hasVariable(var_name))
210  variable_found = true;
211  }
212 
213  // Check the to_multi_app for the variable
214  if (!is_from_multiapp && _to_multi_app)
215  for (unsigned int i = 0; i < _to_multi_app->numGlobalApps(); i++)
216  if (_to_multi_app->hasLocalApp(i))
217  {
218  has_an_app = true;
219  if (_to_multi_app->appProblemBase(i).hasVariable(var_name))
220  variable_found = true;
221  }
222 
223  if (!variable_found && has_an_app)
224  mooseError("Cannot find variable ", var_name, " for ", name(), " Transfer");
225 }
226 
227 void
229 {
230  // Check for siblings transfer support
233 
234  getAppInfo();
235 
236  if (_from_multi_app)
237  _from_multi_app->addAssociatedTransfer(*this);
238  if (_to_multi_app)
239  _to_multi_app->addAssociatedTransfer(*this);
240 }
241 
242 void
244 {
245  // I would like to do all of this in initialSetup, but it will fail with
246  // multiapps that reset. A reset deletes and rebuilds the FEProblems so all
247  // of the pointers will be broken.
248 
249  // Clear the vectors since we've probably built them up from a previous call
250  _from_problems.clear();
251  _to_problems.clear();
252  _from_es.clear();
253  _to_es.clear();
254  _from_meshes.clear();
255  _to_meshes.clear();
256  _to_positions.clear();
257  _from_positions.clear();
258  _to_transforms.clear();
259  _from_transforms.clear();
260  // Clear this map since we build it from scratch every time we transfer
261  // Otherwise, this will cause two issues: 1) increasing memory usage
262  // for a simulation that requires many transfers, 2) producing wrong results
263  // when we do collective communication on this vector.
264  _to_local2global_map.clear();
265  _from_local2global_map.clear();
266 
267  // Build the vectors for to problems, from problems, and subapps positions.
269  {
270  _to_problems.push_back(&_from_multi_app->problemBase());
271  _to_positions.push_back(Point(0., 0., 0.));
273  }
274  else if (_current_direction == TO_MULTIAPP)
275  {
276  _from_problems.push_back(&_to_multi_app->problemBase());
277  _from_positions.push_back(Point(0., 0., 0.));
279  }
281  {
282  mooseAssert(&_from_multi_app->problemBase().coordTransform() ==
283  &_to_multi_app->problemBase().coordTransform(),
284  "I believe these should be the same. If not, then it will be difficult to define a "
285  "canonical reference frame.");
288  }
289 
290  // Build the from and to equation systems and mesh vectors.
291  for (unsigned int i = 0; i < _to_problems.size(); i++)
292  {
293  // TODO: Do I actually want es or displaced es?
294  _to_es.push_back(&_to_problems[i]->es());
295  if (_displaced_target_mesh && _to_problems[i]->getDisplacedProblem())
296  _to_meshes.push_back(&_to_problems[i]->getDisplacedProblem()->mesh());
297  else
298  _to_meshes.push_back(&_to_problems[i]->mesh());
299  }
300 
301  for (unsigned int i = 0; i < _from_problems.size(); i++)
302  {
303  _from_es.push_back(&_from_problems[i]->es());
304  if (_displaced_source_mesh && _from_problems[i]->getDisplacedProblem())
305  _from_meshes.push_back(&_from_problems[i]->getDisplacedProblem()->mesh());
306  else
307  _from_meshes.push_back(&_from_problems[i]->mesh());
308  }
309 
310  MooseAppCoordTransform::MinimalData from_app_transform_construction_data{};
311  if (_communicator.rank() == 0)
312  from_app_transform_construction_data =
314  ? _to_multi_app->problemBase().coordTransform().minimalDataDescription()
315  : _from_multi_app->appProblemBase(0).coordTransform().minimalDataDescription();
316  _communicator.broadcast(from_app_transform_construction_data);
318  std::make_unique<MooseAppCoordTransform>(from_app_transform_construction_data);
319 
320  MooseAppCoordTransform::MinimalData to_app_transform_construction_data{};
321  if (_communicator.rank() == 0)
322  to_app_transform_construction_data =
324  ? _from_multi_app->problemBase().coordTransform().minimalDataDescription()
325  : _to_multi_app->appProblemBase(0).coordTransform().minimalDataDescription();
326  _communicator.broadcast(to_app_transform_construction_data);
328  std::make_unique<MooseAppCoordTransform>(to_app_transform_construction_data);
329 
330  /*
331  * skip_coordinate_collapsing: whether to set the transform to skip coordinate collapsing
332  * (from XYZ to RZ for example)
333  * transforms: vector of transforms to add the new transforms to
334  * moose_app_transform: base for the new transform
335  * is_parent_app_transform: whether working on the transform for the parent app (this app, the
336  * one creating the transfer) or for child apps
337  * multiapp: pointer to the multiapp to obtain the position of the child apps
338  */
339  auto create_multiapp_transforms = [this](auto & transforms,
340  const auto & moose_app_transform,
341  const bool is_parent_app_transform,
342  const MultiApp * const multiapp = nullptr)
343  {
344  mooseAssert(is_parent_app_transform || multiapp,
345  "Coordinate transform must be created either for child app or parent app");
346  if (is_parent_app_transform)
347  {
348  transforms.push_back(std::make_unique<MultiAppCoordTransform>(moose_app_transform));
349  transforms.back()->skipCoordinateCollapsing(_skip_coordinate_collapsing);
350  // zero translation
351  }
352  else
353  {
354  mooseAssert(transforms.size() == 0, "transforms should not be initialized at this point");
355  for (const auto i : make_range(multiapp->numGlobalApps()))
356  {
357  transforms.push_back(std::make_unique<MultiAppCoordTransform>(moose_app_transform));
358  auto & transform = transforms[i];
359  transform->skipCoordinateCollapsing(_skip_coordinate_collapsing);
360  if (multiapp->usingPositions())
361  transform->setTranslationVector(multiapp->position(i));
362  }
363  }
364  };
365 
367  {
368  create_multiapp_transforms(
370  create_multiapp_transforms(_from_transforms, *_from_moose_app_transform, true);
371  }
373  {
374  create_multiapp_transforms(_to_transforms, *_to_moose_app_transform, true);
375  create_multiapp_transforms(
377  }
379  {
380  create_multiapp_transforms(
382  create_multiapp_transforms(
384  }
385 
386  auto check_transform_compatibility = [this](const MultiAppCoordTransform & transform)
387  {
388  if (transform.hasNonTranslationTransformation() && !usesMooseAppCoordTransform())
389  mooseWarning("Transfer '",
390  name(),
391  "' of type '",
392  type(),
393  "' has non-translation transformations but it does not implement coordinate "
394  "transformations using the 'MooseAppCoordTransform' class. Your data transfers "
395  "will not be performed in the expected transformed frame");
396  };
397 
398  // set the destination coordinate systems for each transform for the purposes of determining
399  // coordinate collapsing. For example if TO is XYZ and FROM is RZ, then TO will have its XYZ
400  // coordinates collapsed into RZ and FROM will have a no-op for coordinate collapsing
401 
402  for (const auto i : index_range(_from_transforms))
403  {
404  auto & from_transform = _from_transforms[i];
405  from_transform->setDestinationCoordTransform(*_to_moose_app_transform);
406  if (i == 0)
407  check_transform_compatibility(*from_transform);
408  }
409  for (const auto i : index_range(_to_transforms))
410  {
411  auto & to_transform = _to_transforms[i];
412  to_transform->setDestinationCoordTransform(*_from_moose_app_transform);
413  if (i == 0)
414  check_transform_compatibility(*to_transform);
415  }
416 }
417 
418 namespace
419 {
420 void
421 fillInfo(MultiApp & multi_app,
422  std::vector<unsigned int> & map,
423  std::vector<FEProblemBase *> & problems,
424  std::vector<Point> & positions)
425 {
426  for (unsigned int i_app = 0; i_app < multi_app.numGlobalApps(); i_app++)
427  {
428  if (!multi_app.hasLocalApp(i_app))
429  continue;
430 
431  auto & subapp_problem = multi_app.appProblemBase(i_app);
432 
433  map.push_back(i_app);
434  problems.push_back(&subapp_problem);
435  if (multi_app.usingPositions())
436  positions.push_back(multi_app.position(i_app));
437  }
438 }
439 }
440 
441 void
443 {
444  if (!_to_multi_app)
445  mooseError("There is no to_multiapp to get info from");
446 
448 }
449 
450 void
452 {
453  if (!_from_multi_app)
454  mooseError("There is no from_multiapp to get info from");
455 
457 }
458 
459 void
461 {
462  MultiApp::transformBoundingBox(box, transform);
463 }
464 
465 void
466 MultiAppTransfer::extendBoundingBoxes(const Real factor, std::vector<BoundingBox> & bboxes) const
467 {
468  const auto extension_factor = factor - 1;
469 
470  // Extend (or contract if the extension factor is negative) bounding boxes along all the
471  // directions by the same length. Greater than zero values of this member may be necessary because
472  // the nearest bounding box does not necessarily give you the closest node/element. It will depend
473  // on the partition and geometry. A node/element will more likely find its nearest source
474  // element/node by extending bounding boxes. If each of the bounding boxes covers the entire
475  // domain, a node/element will be able to find its nearest source element/node for sure, but at
476  // the same time, more communication will be involved and can be expensive.
477  for (auto & box : bboxes)
478  {
479  // libmesh set an invalid bounding box using this code
480  // for (unsigned int i=0; i<LIBMESH_DIM; i++)
481  // {
482  // this->first(i) = std::numeric_limits<Real>::max();
483  // this->second(i) = -std::numeric_limits<Real>::max();
484  // }
485  // If it is an invalid box, we should skip it
486  if (box.first(0) == std::numeric_limits<Real>::max())
487  continue;
488 
489  auto width = box.second - box.first;
490  box.second += width * extension_factor;
491  box.first -= width * extension_factor;
492  }
493 }
494 
495 std::vector<BoundingBox>
497 {
498  std::vector<std::pair<Point, Point>> bb_points(_from_meshes.size());
499  for (unsigned int i = 0; i < _from_meshes.size(); i++)
500  {
501  // Get a bounding box around the mesh elements that are local to the current
502  // processor.
503  BoundingBox bbox = MeshTools::create_local_bounding_box(*_from_meshes[i]);
504 
505  // Translate the bounding box to the from domain's position. We may have rotations so we must
506  // be careful in constructing the new min and max (first and second)
507  const auto from_global_num = getGlobalSourceAppIndex(i);
508  transformBoundingBox(bbox, *_from_transforms[from_global_num]);
509 
510  // Cast the bounding box into a pair of points (so it can be put through
511  // MPI communication).
512  bb_points[i] = static_cast<std::pair<Point, Point>>(bbox);
513  }
514 
515  // Serialize the bounding box points.
516  _communicator.allgather(bb_points);
517 
518  // Recast the points back into bounding boxes and return.
519  std::vector<BoundingBox> bboxes(bb_points.size());
520  for (unsigned int i = 0; i < bb_points.size(); i++)
521  bboxes[i] = static_cast<BoundingBox>(bb_points[i]);
522 
523  // possibly extend bounding boxes
525 
526  return bboxes;
527 }
528 
529 std::vector<BoundingBox>
531 {
532  std::vector<std::pair<Point, Point>> bb_points(_from_meshes.size());
533  const Real min_r = std::numeric_limits<Real>::lowest();
534  const Real max_r = std::numeric_limits<Real>::max();
535 
536  for (unsigned int i = 0; i < _from_meshes.size(); i++)
537  {
538 
539  Point min(max_r, max_r, max_r);
540  Point max(min_r, min_r, min_r);
541  bool at_least_one = false;
542 
543  // TODO: Factor this into mesh_tools after adding new boundary bounding box routine.
544  const ConstBndNodeRange & bnd_nodes = *_from_meshes[i]->getBoundaryNodeRange();
545  for (const auto & bnode : bnd_nodes)
546  {
547  if (bnode->_bnd_id == boundary_id &&
548  bnode->_node->processor_id() == _from_meshes[i]->processor_id())
549  {
550  at_least_one = true;
551  const auto & node = *bnode->_node;
552  for (const auto i : make_range(Moose::dim))
553  {
554  min(i) = std::min(min(i), node(i));
555  max(i) = std::max(max(i), node(i));
556  }
557  }
558  }
559 
560  BoundingBox bbox(min, max);
561  if (!at_least_one)
562  bbox.min() = max; // If we didn't hit any nodes, this will be _the_ minimum bbox
563  else
564  {
565  // Translate the bounding box to the from domain's position. We may have rotations so we must
566  // be careful in constructing the new min and max (first and second)
567  const auto from_global_num = getGlobalSourceAppIndex(i);
568  transformBoundingBox(bbox, *_from_transforms[from_global_num]);
569  }
570 
571  // Cast the bounding box into a pair of points (so it can be put through
572  // MPI communication).
573  bb_points[i] = static_cast<std::pair<Point, Point>>(bbox);
574  }
575 
576  // Serialize the bounding box points.
577  _communicator.allgather(bb_points);
578 
579  // Recast the points back into bounding boxes and return.
580  std::vector<BoundingBox> bboxes(bb_points.size());
581  for (unsigned int i = 0; i < bb_points.size(); i++)
582  bboxes[i] = static_cast<BoundingBox>(bb_points[i]);
583 
584  // possibly extend bounding boxes
586 
587  return bboxes;
588 }
589 
590 std::vector<unsigned int>
592 {
593  std::vector<unsigned int> froms_per_proc;
594  if (_to_multi_app)
595  froms_per_proc.resize(n_processors(), 1);
596  if (_from_multi_app)
597  {
598  froms_per_proc.resize(n_processors());
599  _communicator.allgather(_from_multi_app->numLocalApps(), froms_per_proc);
600  }
601  return froms_per_proc;
602 }
603 
604 NumericVector<Real> &
605 MultiAppTransfer::getTransferVector(unsigned int i_local, std::string var_name)
606 {
607  mooseAssert(_to_multi_app, "getTransferVector only works for transfers to multiapps");
608 
609  return _to_multi_app->appTransferVector(_to_local2global_map[i_local], var_name);
610 }
611 
612 void
614  const VariableName & var_name,
615  const std::string & param_name) const
616 {
617  if (!fe_problem.hasVariable(var_name))
618  {
619  if (param_name.empty())
620  mooseError("The variable '", var_name, "' does not exist.");
621  else
622  paramError(param_name, "The variable '", var_name, "' does not exist.");
623  }
624 }
625 
626 Point
628  unsigned int local_i_to,
629  const std::string & phase) const
630 {
631  const auto & to_transform = _to_transforms[getGlobalTargetAppIndex(local_i_to)];
632  if (to_transform->hasCoordinateSystemTypeChange())
633  {
635  mooseInfo(phase + " cannot use the point in the target app frame due to the "
636  "non-uniqueness of the coordinate collapsing reverse mapping."
637  " Coordinate collapse is ignored for this operation");
638  to_transform->skipCoordinateCollapsing(true);
639  const auto target_point = to_transform->mapBack(p);
640  to_transform->skipCoordinateCollapsing(false);
641  return target_point;
642  }
643  else
644  return to_transform->mapBack(p);
645 }
646 
647 unsigned int
649 {
650  mooseAssert(_current_direction == TO_MULTIAPP || i_from < _from_local2global_map.size(),
651  "Out of bounds local from-app index");
652  return _current_direction == TO_MULTIAPP ? 0 : _from_local2global_map[i_from];
653 }
654 
655 unsigned int
657 {
658  mooseAssert(_current_direction == FROM_MULTIAPP || i_to < _to_local2global_map.size(),
659  "Out of bounds local to-app index");
661 }
662 
663 unsigned int
665 {
667  ? 0
669 }
670 
671 void
672 MultiAppTransfer::checkParentAppUserObjectExecuteOn(const std::string & object_name) const
673 {
674  // Source app is not the parent, most execution schedules are fine since the transfer occurs after
675  // the app has run NOTE: not true for siblings transfer
676  if (hasFromMultiApp())
677  return;
678  // Get user object from parent. We don't know the type
679  const auto & uo = _fe_problem.getUserObject<UserObject>(object_name);
680  // If we are executing on transfers, every additional schedule is not a problem
681  if (uo.getExecuteOnEnum().contains(EXEC_TRANSFER))
682  return;
683  // If we are transferring on the same schedule as we are executing, we are lagging. Is it on
684  // purpose? We don't know, so we will give a warning unless silenced.
685  // The derived-classes offer the parameter to silence this warning
686  // Note: UOs execute before transfers on INITIAL so it's not a problem at this time
687  if (uo.getExecuteOnEnum().contains(_fe_problem.getCurrentExecuteOnFlag()) &&
689  if (!isParamValid("warn_source_object_execution_schedule") ||
690  getParam<bool>("warn_source_object_execution_schedule"))
691  uo.paramWarning("execute_on",
692  "This UserObject-derived class is being executed on '" +
694  "' and also providing values for the '" + name() +
695  "' transfer, on that same execution schedule. Because user objects are "
696  "executed after transfers are, this means the values provided by this "
697  "user object are lagged. If you are ok with this, then set the "
698  "'warn_source_object_execution_schedule' parameter to false in this "
699  "Transfer. If not, then execute '" +
700  uo.name() +
701  "' on TRANSFER by adding it to the 'execute_on' vector parameter.");
702 }
703 
704 void
706 {
707  // parent app is the source app, EXEC_TRANSFER is fine
708  if (!hasFromMultiApp())
709  return;
710  // Get the app and problem
711  const auto & app = getFromMultiApp();
712  if (!app->hasApp())
713  return;
714  const auto & problem = app->appProblemBase(app->firstLocalApp());
715  // Use the warehouse to find the object
716  std::vector<SetupInterface *> objects_with_exec_on;
717  problem.theWarehouse()
718  .query()
719  .template condition<AttribName>(object_name)
720  .template condition<AttribExecOns>(EXEC_TRANSFER)
721  .queryInto(objects_with_exec_on);
722  if (objects_with_exec_on.size())
723  mooseError("Object '" + object_name +
724  "' should not be executed on EXEC_TRANSFER, because this transfer has "
725  "indicated it does not support it.\nExecuting this object on TIMESTEP_END should be "
726  "sufficient to get updated values.");
727 }
libMesh::NumericVector< Real > & getTransferVector(unsigned int i_local, std::string var_name)
If we are transferring to a multiapp, return the appropriate solution vector.
virtual bool hasVariable(const std::string &var_name) const override
Whether or not this problem has the variable.
void mooseInfo(Args &&... args) const
Definition: MooseBase.h:317
std::vector< std::unique_ptr< MultiAppCoordTransform > > _to_transforms
bool hasLocalApp(unsigned int global_app) const
Whether or not the given global app number is on this processor.
Definition: MultiApp.C:1070
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 ExecFlagType EXEC_TRANSFER
Definition: Moose.C:55
void allgather(const T &send_data, std::vector< T, A > &recv_data) const
std::vector< libMesh::EquationSystems * > _to_es
A MultiMooseEnum object to hold "execute_on" flags.
Definition: ExecFlagEnum.h:21
std::unique_ptr< MooseAppCoordTransform > _to_moose_app_transform
The moose coordinate transformation object describing rotations, scaling, and coordinate system of th...
void addDeprecatedParam(const std::string &name, const T &value, const std::string &doc_string, const std::string &deprecation_message)
T & getUserObject(const std::string &name, unsigned int tid=0) const
Get the user object by its name.
const std::shared_ptr< MultiApp > getFromMultiApp() const
Get the MultiApp to transfer data from.
static void transformBoundingBox(libMesh::BoundingBox &box, const MultiAppCoordTransform &transform)
Transform a bounding box according to the transformations in the provided coordinate transformation o...
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:435
const bool _skip_coordinate_collapsing
Whether to skip coordinate collapsing (transformations of coordinates between applications using diff...
MooseEnum _current_direction
Definition: Transfer.h:106
void setDocString(const std::string &name, const std::string &doc)
Set the doc string of a parameter.
void variableIntegrityCheck(const AuxVariableName &var_name, bool is_from_multiapp) const
Utility to verify that the variable in the destination system exists.
void setAdditionalValue(const std::string &names)
Insert operators Operator to insert (push_back) values into the enum.
unsigned int getLocalSourceAppIndex(unsigned int i_from) const
Return the local app index from the global index in the "from-multiapp" transfer direction We use the...
const ExecFlagType & getCurrentExecuteOnFlag() const
Return/set the current execution flag.
static void addUserObjectExecutionCheckParam(InputParameters &params)
Add the execution order check parameter (to skip the warning if needed)
const InputParameters & parameters() const
Get the parameters of the object.
Definition: MooseBase.h:127
void checkMultiAppExecuteOn()
Helper method for checking the &#39;check_multiapp_execute_on&#39; flag.
std::shared_ptr< MultiApp > _from_multi_app
The MultiApps this Transfer is transferring data to or from.
T & set(const std::string &name, bool quiet_mode=false)
Returns a writable reference to the named parameters.
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...
MeshBase & mesh
std::vector< FEProblemBase * > _to_problems
processor_id_type rank() const
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
static constexpr std::size_t dim
This is the dimension of all vector and tensor datastructures used in MOOSE.
Definition: Moose.h:159
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...
FEProblemBase & _fe_problem
Definition: Transfer.h:97
void addAvailableFlags(const ExecFlagType &flag, Args... flags)
Add additional execute_on flags to the list of possible flags.
Definition: ExecFlagEnum.h:82
std::vector< Point > _from_positions
const Parallel::Communicator & _communicator
std::shared_ptr< MultiApp > _multi_app
Deprecated class attribute for compatibility with the apps.
bool hasFromMultiApp() const
Whether the transfer owns a non-null from_multi_app.
Specialization of SubProblem for solving nonlinear equations plus auxiliary equations.
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.
auto max(const L &left, const R &right)
std::shared_ptr< MultiApp > getMultiApp(const std::string &multi_app_name) const
Get a MultiApp object by name.
std::vector< unsigned int > _to_local2global_map
Given local app index, returns global app index.
void checkVariable(const FEProblemBase &fe_problem, const VariableName &var_name, const std::string &param_name="") const
Helper for checking a problem for a variable.
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.
virtual bool usesMooseAppCoordTransform() const
Whether this transfer handles non-translation-based transformations, e.g.
processor_id_type n_processors() const
const std::string & name() const
Get the name of the class.
Definition: MooseBase.h:99
std::vector< libMesh::EquationSystems * > _from_es
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...
Definition: MultiApp.C:902
void errorIfObjectExecutesOnTransferInSourceApp(const std::string &object_name) const
Error if executing this MooseObject on EXEC_TRANSFER in a source multiapp (from_multiapp, e.g.
unsigned int numGlobalApps() const
Definition: MultiApp.h:278
void initialSetup() override
Method called at the beginning of the simulation for checking integrity or doing one-time setup...
boundary_id_type BoundaryID
std::unique_ptr< MooseAppCoordTransform > _from_moose_app_transform
The moose coordinate transformation object describing rotations, scaling, and coordinate system of th...
const ExecFlagEnum & getExecuteOnEnum() const
Return the execute on MultiMooseEnum for this object.
std::vector< unsigned int > getFromsPerProc()
Return the number of "from" domains that each processor owns.
static InputParameters validParams()
Definition: Transfer.C:27
const std::string & type() const
Get the type of this class.
Definition: MooseBase.h:89
FEProblemBase & appProblemBase(unsigned int app)
Get the FEProblemBase for the global app desired.
Definition: MultiApp.C:1016
unsigned int getGlobalSourceAppIndex(unsigned int i_from) const
Return the global app index from the local index in the "from-multiapp" transfer direction.
std::shared_ptr< MultiApp > _to_multi_app
std::string stringify(const T &t)
conversion to string
Definition: Conversion.h:64
static InputParameters validParams()
void broadcast(T &data, const unsigned int root_id=0, const bool identical_sizes=false) const
bool isParamSetByUser(const std::string &name) const
Method returns true if the parameter was set by the user.
bool usingPositions() const
Whether or not this MultiApp is using positions or its own way for constructing sub-apps.
Definition: MultiApp.h:363
std::vector< Point > _to_positions
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
MultiMooseEnum _directions
The directions this Transfer is to be executed on.
Definition: Transfer.h:110
Real _bbox_factor
Extend (or contract) bounding box by a factor in all directions Greater than one values of this membe...
void mooseWarning(Args &&... args) const
Emits a warning prefixed with object name and type.
Definition: MooseBase.h:295
std::vector< std::unique_ptr< MultiAppCoordTransform > > _from_transforms
IntRange< T > make_range(T beg, T end)
bool _displaced_source_mesh
True if displaced mesh is used for the source mesh, otherwise false.
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:267
const ExecFlagType EXEC_SAME_AS_MULTIAPP
Definition: Moose.C:53
std::vector< unsigned int > _from_local2global_map
Given local app index, returns global app index.
static void addBBoxFactorParam(InputParameters &params)
Add the bounding box factor parameter to the supplied input parameters.
static void addSkipCoordCollapsingParam(InputParameters &params)
Add the option to skip coordinate collapsing in coordinate transformation operations Note: this is us...
void extendBoundingBoxes(const Real factor, std::vector< libMesh::BoundingBox > &bboxes) const
Extends bounding boxes to avoid missing points.
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...
MooseEnum _direction
Definition: Transfer.h:105
void addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
Definition: MooseBase.h:195
virtual void checkSiblingsTransferSupported() const
Whether the transfer supports siblings transfer.
void paramWarning(const std::string &param, Args... args) const
Emits a warning prefixed with the file and line number of the given param (from the input file) along...
Definition: MooseBase.h:442
A MultiApp represents one or more MOOSE applications that are running simultaneously.
Definition: MultiApp.h:112
virtual void getAppInfo()
This method will fill information into the convenience member variables (_to_problems, _from_meshes, etc.)
auto min(const L &left, const R &right)
std::vector< FEProblemBase * > _from_problems
auto index_range(const T &sizable)
Base class for user-specific data.
Definition: UserObject.h:40
const Point & position(unsigned int app) const
The physical position of a global App number.
Definition: MultiApp.C:1513
std::vector< MooseMesh * > _to_meshes
const ExecFlagType EXEC_POST_ADAPTIVITY
Definition: Moose.C:58
This class contains transformation information that only exists in a context in which there are multi...
Base class for all Transfer objects.
Definition: Transfer.h:36
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...
const ExecFlagType EXEC_INITIAL
Definition: Moose.C:30