LCOV - code coverage report
Current view: top level - src/transfers - MultiAppTransfer.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 302 324 93.2 %
Date: 2025-07-17 01:28:37 Functions: 24 25 96.0 %
Legend: Lines: hit not hit

          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             : // 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             : 
      19             : #include "libmesh/parallel_algebra.h"
      20             : #include "libmesh/mesh_tools.h"
      21             : 
      22             : InputParameters
      23      331339 : MultiAppTransfer::validParams()
      24             : {
      25      331339 :   InputParameters params = Transfer::validParams();
      26      331339 :   params.addDeprecatedParam<MultiAppName>("multi_app",
      27             :                                           "The name of the MultiApp to transfer data with",
      28             :                                           "Use to_multiapp & from_multiapp parameters now");
      29      331339 :   params.addParam<MultiAppName>("from_multi_app", "The name of the MultiApp to receive data from");
      30      331339 :   params.addParam<MultiAppName>("to_multi_app", "The name of the MultiApp to transfer the data to");
      31             : 
      32             :   // MultiAppTransfers by default will execute with their associated MultiApp. These flags will be
      33             :   // added by FEProblemBase when the transfer is added.
      34      331339 :   ExecFlagEnum & exec_enum = params.set<ExecFlagEnum>("execute_on", true);
      35      331339 :   exec_enum.addAvailableFlags(EXEC_SAME_AS_MULTIAPP);
      36             :   // Add the POST_ADAPTIVITY execution flag.
      37             : #ifdef LIBMESH_ENABLE_AMR
      38      331339 :   exec_enum.addAvailableFlags(EXEC_POST_ADAPTIVITY);
      39             : #endif
      40      331339 :   exec_enum = EXEC_SAME_AS_MULTIAPP;
      41      331339 :   params.setDocString("execute_on", exec_enum.getDocString());
      42             : 
      43      994017 :   params.addParam<bool>(
      44             :       "check_multiapp_execute_on",
      45      662678 :       true,
      46             :       "When false the check between the multiapp and transfer execute on flags is not performed.");
      47      994017 :   params.addParam<bool>("displaced_source_mesh",
      48      662678 :                         false,
      49             :                         "Whether or not to use the displaced mesh for the source mesh.");
      50      994017 :   params.addParam<bool>("displaced_target_mesh",
      51      662678 :                         false,
      52             :                         "Whether or not to use the displaced mesh for the target mesh.");
      53      331339 :   addSkipCoordCollapsingParam(params);
      54      331339 :   return params;
      55           0 : }
      56             : 
      57             : void
      58       59398 : MultiAppTransfer::addBBoxFactorParam(InputParameters & params)
      59             : {
      60      178194 :   params.addRangeCheckedParam<Real>(
      61             :       "bbox_factor",
      62      118796 :       1 + TOLERANCE,
      63             :       "bbox_factor>0",
      64             :       "Multiply bounding box width (in all directions) by the prescribed factor. Values less than "
      65             :       "1 will shrink the bounding box; values greater than 1 will enlarge the bounding box. It is "
      66             :       "generally not advised to ever shrink the bounding box. On the other hand it may be helpful "
      67             :       "to enlarge the bounding box. Larger bounding boxes will lead to more accurate determination "
      68             :       "of the closest node/element with the tradeoff of more communication.");
      69       59398 : }
      70             : 
      71             : void
      72      331339 : MultiAppTransfer::addSkipCoordCollapsingParam(InputParameters & params)
      73             : {
      74      994017 :   params.addParam<bool>(
      75             :       "skip_coordinate_collapsing",
      76      662678 :       true,
      77             :       "Whether to skip coordinate collapsing (translation and rotation are still performed, only "
      78             :       "XYZ, RZ etc collapsing is skipped) when performing mapping and inverse "
      79             :       "mapping coordinate transformation operations. This parameter should only "
      80             :       "be set by users who really know what they're doing.");
      81      331339 :   params.addParamNamesToGroup("skip_coordinate_collapsing", "Advanced");
      82      331339 : }
      83             : 
      84       11560 : MultiAppTransfer::MultiAppTransfer(const InputParameters & parameters)
      85             :   : Transfer(parameters),
      86       11560 :     _skip_coordinate_collapsing(getParam<bool>("skip_coordinate_collapsing")),
      87       11560 :     _displaced_source_mesh(getParam<bool>("displaced_source_mesh")),
      88       11560 :     _displaced_target_mesh(getParam<bool>("displaced_target_mesh")),
      89       23120 :     _bbox_factor(isParamValid("bbox_factor") ? getParam<Real>("bbox_factor") : 1)
      90             : {
      91             :   // Get the multiapps from their names
      92       11560 :   if (!isParamValid("multi_app"))
      93             :   {
      94       11508 :     if (isParamValid("from_multi_app"))
      95             :     {
      96        6571 :       _from_multi_app = _fe_problem.getMultiApp(getParam<MultiAppName>("from_multi_app"));
      97        6571 :       _multi_app = _from_multi_app;
      98             :     }
      99       11508 :     if (isParamValid("to_multi_app"))
     100             :     {
     101        6036 :       _to_multi_app = _fe_problem.getMultiApp(getParam<MultiAppName>("to_multi_app"));
     102        6036 :       _multi_app = _to_multi_app;
     103             :     }
     104       27949 :     if (!isParamValid("direction") && !isParamValid("from_multi_app") &&
     105       16441 :         !isParamValid("to_multi_app"))
     106           4 :       mooseError("from_multi_app and/or to_multi_app must be specified");
     107             :   }
     108             :   else
     109             :   {
     110             :     // Check deprecated direction parameter
     111         104 :     for (const auto & dir : _directions)
     112             :     {
     113          52 :       if (dir == FROM_MULTIAPP)
     114             :       {
     115          52 :         _from_multi_app = _fe_problem.getMultiApp(getParam<MultiAppName>("multi_app"));
     116          52 :         _multi_app = _from_multi_app;
     117             :       }
     118           0 :       else if (dir == TO_MULTIAPP)
     119             :       {
     120           0 :         _to_multi_app = _fe_problem.getMultiApp(getParam<MultiAppName>("multi_app"));
     121           0 :         _multi_app = _to_multi_app;
     122             :       }
     123             :       else
     124           0 :         paramError("direction",
     125             :                    "BETWEN_MULTIAPP transfers should be specified using to/from_multi_app");
     126             :     }
     127             :   }
     128             : 
     129       11556 :   if (getParam<bool>("check_multiapp_execute_on"))
     130       11436 :     checkMultiAppExecuteOn();
     131             : 
     132             :   // Fill direction attributes, for backward compatibility but also convenience
     133       11556 :   if (!isParamValid("direction"))
     134             :   {
     135       11500 :     if (_from_multi_app && (!_to_multi_app || _from_multi_app == _to_multi_app))
     136        5468 :       _directions.setAdditionalValue("from_multiapp");
     137       11500 :     if (_to_multi_app && (!_from_multi_app || _from_multi_app == _to_multi_app))
     138        4933 :       _directions.setAdditionalValue("to_multiapp");
     139       11500 :     if (_from_multi_app && _to_multi_app && _from_multi_app != _to_multi_app)
     140        1103 :       _directions.setAdditionalValue("between_multiapp");
     141             : 
     142             :     // So it's available in the next constructors
     143       11500 :     _direction = _directions[0];
     144       11500 :     _current_direction = _directions[0];
     145             :   }
     146             : 
     147             :   // Handle deprecated parameters
     148       11556 :   if (parameters.isParamSetByUser("direction"))
     149             :   {
     150          56 :     if (!isParamValid("multi_app"))
     151           4 :       paramError("direction",
     152             :                  "The deprecated 'direction' parameter is meant to be used in conjunction with the "
     153             :                  "'multi_app' parameter");
     154          52 :     if (isParamValid("to_multi_app") || isParamValid("from_multi_app"))
     155           4 :       paramError("direction",
     156             :                  "The deprecated 'direction' parameter is not meant to be used in conjunction with "
     157             :                  "the 'from_multi_app' or 'to_multi_app' parameters");
     158             :   }
     159       11548 : }
     160             : 
     161             : void
     162       11436 : MultiAppTransfer::checkMultiAppExecuteOn()
     163             : {
     164       11436 :   if (_from_multi_app && !_to_multi_app)
     165        5456 :     if (getExecuteOnEnum() != _from_multi_app->getExecuteOnEnum())
     166         241 :       mooseDoOnce(
     167             :           mooseWarning("MultiAppTransfer execute_on flags do not match associated from_multi_app "
     168             :                        "execute_on flags"));
     169             : 
     170       11436 :   if (_to_multi_app && !_from_multi_app)
     171        4869 :     if (getExecuteOnEnum() != _to_multi_app->getExecuteOnEnum())
     172         234 :       mooseDoOnce(
     173             :           mooseWarning("MultiAppTransfer execute_on flags do not match associated to_multi_app "
     174             :                        "execute_on flags"));
     175             : 
     176             :   // In the case of siblings transfer, the check will be looser
     177       11436 :   if (_from_multi_app && _to_multi_app)
     178        1114 :     if (getExecuteOnEnum() != _from_multi_app->getExecuteOnEnum() &&
     179           7 :         getExecuteOnEnum() != _to_multi_app->getExecuteOnEnum())
     180           7 :       mooseDoOnce(
     181             :           mooseWarning("MultiAppTransfer execute_on flags do not match associated to_multi_app "
     182             :                        "and from_multi_app execute_on flags"));
     183       11436 : }
     184             : 
     185             : void
     186        9198 : MultiAppTransfer::variableIntegrityCheck(const AuxVariableName & var_name,
     187             :                                          bool is_from_multiapp) const
     188             : {
     189        9198 :   bool variable_found = false;
     190        9198 :   bool has_an_app = false;
     191             : 
     192             :   // Check the from_multi_app for the variable
     193        9198 :   if (is_from_multiapp && _from_multi_app)
     194       12339 :     for (unsigned int i = 0; i < _from_multi_app->numGlobalApps(); i++)
     195        8063 :       if (_from_multi_app->hasLocalApp(i))
     196             :       {
     197        6674 :         has_an_app = true;
     198        6674 :         if (_from_multi_app->appProblemBase(i).hasVariable(var_name))
     199        6670 :           variable_found = true;
     200             :       }
     201             : 
     202             :   // Check the to_multi_app for the variable
     203        9198 :   if (!is_from_multiapp && _to_multi_app)
     204       14248 :     for (unsigned int i = 0; i < _to_multi_app->numGlobalApps(); i++)
     205        9326 :       if (_to_multi_app->hasLocalApp(i))
     206             :       {
     207        7753 :         has_an_app = true;
     208        7753 :         if (_to_multi_app->appProblemBase(i).hasVariable(var_name))
     209        7753 :           variable_found = true;
     210             :       }
     211             : 
     212        9198 :   if (!variable_found && has_an_app)
     213           4 :     mooseError("Cannot find variable ", var_name, " for ", name(), " Transfer");
     214        9194 : }
     215             : 
     216             : void
     217       11220 : MultiAppTransfer::initialSetup()
     218             : {
     219             :   // Check for siblings transfer support
     220       11220 :   if (_to_multi_app && _from_multi_app)
     221        1103 :     checkSiblingsTransferSupported();
     222             : 
     223       11220 :   getAppInfo();
     224             : 
     225       11212 :   if (_from_multi_app)
     226        6411 :     _from_multi_app->addAssociatedTransfer(*this);
     227       11212 :   if (_to_multi_app)
     228        5904 :     _to_multi_app->addAssociatedTransfer(*this);
     229       11212 : }
     230             : 
     231             : void
     232       69981 : MultiAppTransfer::getAppInfo()
     233             : {
     234             :   // I would like to do all of this in initialSetup, but it will fail with
     235             :   // multiapps that reset.  A reset deletes and rebuilds the FEProblems so all
     236             :   // of the pointers will be broken.
     237             : 
     238             :   // Clear the vectors since we've probably built them up from a previous call
     239       69981 :   _from_problems.clear();
     240       69981 :   _to_problems.clear();
     241       69981 :   _from_es.clear();
     242       69981 :   _to_es.clear();
     243       69981 :   _from_meshes.clear();
     244       69981 :   _to_meshes.clear();
     245       69981 :   _to_positions.clear();
     246       69981 :   _from_positions.clear();
     247       69981 :   _to_transforms.clear();
     248       69981 :   _from_transforms.clear();
     249             :   // Clear this map since we build it from scratch every time we transfer
     250             :   // Otherwise, this will cause two issues: 1) increasing memory usage
     251             :   // for a simulation that requires many transfers, 2) producing wrong results
     252             :   // when we do collective communication on this vector.
     253       69981 :   _to_local2global_map.clear();
     254       69981 :   _from_local2global_map.clear();
     255             : 
     256             :   // Build the vectors for to problems, from problems, and subapps positions.
     257       69981 :   if (_current_direction == FROM_MULTIAPP)
     258             :   {
     259       32739 :     _to_problems.push_back(&_from_multi_app->problemBase());
     260       32739 :     _to_positions.push_back(Point(0., 0., 0.));
     261       32739 :     getFromMultiAppInfo();
     262             :   }
     263       37242 :   else if (_current_direction == TO_MULTIAPP)
     264             :   {
     265       30586 :     _from_problems.push_back(&_to_multi_app->problemBase());
     266       30586 :     _from_positions.push_back(Point(0., 0., 0.));
     267       30586 :     getToMultiAppInfo();
     268             :   }
     269        6656 :   else if (_current_direction == BETWEEN_MULTIAPP)
     270             :   {
     271             :     mooseAssert(&_from_multi_app->problemBase().coordTransform() ==
     272             :                     &_to_multi_app->problemBase().coordTransform(),
     273             :                 "I believe these should be the same. If not, then it will be difficult to define a "
     274             :                 "canonical reference frame.");
     275        6656 :     getToMultiAppInfo();
     276        6656 :     getFromMultiAppInfo();
     277             :   }
     278             : 
     279             :   // Build the from and to equation systems and mesh vectors.
     280      147405 :   for (unsigned int i = 0; i < _to_problems.size(); i++)
     281             :   {
     282             :     // TODO: Do I actually want es or displaced es?
     283       77424 :     _to_es.push_back(&_to_problems[i]->es());
     284       77424 :     if (_displaced_target_mesh && _to_problems[i]->getDisplacedProblem())
     285         504 :       _to_meshes.push_back(&_to_problems[i]->getDisplacedProblem()->mesh());
     286             :     else
     287       76920 :       _to_meshes.push_back(&_to_problems[i]->mesh());
     288             :   }
     289             : 
     290      147058 :   for (unsigned int i = 0; i < _from_problems.size(); i++)
     291             :   {
     292       77077 :     _from_es.push_back(&_from_problems[i]->es());
     293       77077 :     if (_displaced_source_mesh && _from_problems[i]->getDisplacedProblem())
     294         849 :       _from_meshes.push_back(&_from_problems[i]->getDisplacedProblem()->mesh());
     295             :     else
     296       76228 :       _from_meshes.push_back(&_from_problems[i]->mesh());
     297             :   }
     298             : 
     299       69981 :   MooseAppCoordTransform::MinimalData from_app_transform_construction_data{};
     300       69981 :   if (_communicator.rank() == 0)
     301             :     from_app_transform_construction_data =
     302       51123 :         _current_direction == TO_MULTIAPP
     303      102246 :             ? _to_multi_app->problemBase().coordTransform().minimalDataDescription()
     304       51123 :             : _from_multi_app->appProblemBase(0).coordTransform().minimalDataDescription();
     305       69981 :   _communicator.broadcast(from_app_transform_construction_data);
     306             :   _from_moose_app_transform =
     307       69981 :       std::make_unique<MooseAppCoordTransform>(from_app_transform_construction_data);
     308             : 
     309       69981 :   MooseAppCoordTransform::MinimalData to_app_transform_construction_data{};
     310       69981 :   if (_communicator.rank() == 0)
     311             :     to_app_transform_construction_data =
     312       51123 :         _current_direction == FROM_MULTIAPP
     313      102246 :             ? _from_multi_app->problemBase().coordTransform().minimalDataDescription()
     314       51123 :             : _to_multi_app->appProblemBase(0).coordTransform().minimalDataDescription();
     315       69981 :   _communicator.broadcast(to_app_transform_construction_data);
     316             :   _to_moose_app_transform =
     317       69981 :       std::make_unique<MooseAppCoordTransform>(to_app_transform_construction_data);
     318             : 
     319             :   /*
     320             :    * skip_coordinate_collapsing: whether to set the transform to skip coordinate collapsing
     321             :    *                             (from XYZ to RZ for example)
     322             :    * transforms: vector of transforms to add the new transforms to
     323             :    * moose_app_transform: base for the new transform
     324             :    * is_parent_app_transform: whether working on the transform for the parent app (this app, the
     325             :    *                          one creating the transfer) or for child apps
     326             :    * multiapp: pointer to the multiapp to obtain the position of the child apps
     327             :    */
     328      139962 :   auto create_multiapp_transforms = [this](auto & transforms,
     329             :                                            const auto & moose_app_transform,
     330             :                                            const bool is_parent_app_transform,
     331      164288 :                                            const MultiApp * const multiapp = nullptr)
     332             :   {
     333             :     mooseAssert(is_parent_app_transform || multiapp,
     334             :                 "Coordinate transform must be created either for child app or parent app");
     335      139962 :     if (is_parent_app_transform)
     336             :     {
     337       63325 :       transforms.push_back(std::make_unique<MultiAppCoordTransform>(moose_app_transform));
     338       63325 :       transforms.back()->skipCoordinateCollapsing(_skip_coordinate_collapsing);
     339             :       // zero translation
     340             :     }
     341             :     else
     342             :     {
     343             :       mooseAssert(transforms.size() == 0, "transforms should not be initialized at this point");
     344      177600 :       for (const auto i : make_range(multiapp->numGlobalApps()))
     345             :       {
     346      100963 :         transforms.push_back(std::make_unique<MultiAppCoordTransform>(moose_app_transform));
     347      100963 :         auto & transform = transforms[i];
     348      100963 :         transform->skipCoordinateCollapsing(_skip_coordinate_collapsing);
     349      100963 :         if (multiapp->usingPositions())
     350      100963 :           transform->setTranslationVector(multiapp->position(i));
     351             :       }
     352             :     }
     353      139962 :   };
     354             : 
     355       69981 :   if (_current_direction == TO_MULTIAPP)
     356             :   {
     357       30586 :     create_multiapp_transforms(
     358       30586 :         _to_transforms, *_to_moose_app_transform, false, _to_multi_app.get());
     359       30586 :     create_multiapp_transforms(_from_transforms, *_from_moose_app_transform, true);
     360             :   }
     361       69981 :   if (_current_direction == FROM_MULTIAPP)
     362             :   {
     363       32739 :     create_multiapp_transforms(_to_transforms, *_to_moose_app_transform, true);
     364       32739 :     create_multiapp_transforms(
     365       32739 :         _from_transforms, *_from_moose_app_transform, false, _from_multi_app.get());
     366             :   }
     367       69981 :   if (_current_direction == BETWEEN_MULTIAPP)
     368             :   {
     369        6656 :     create_multiapp_transforms(
     370        6656 :         _to_transforms, *_to_moose_app_transform, false, _to_multi_app.get());
     371        6656 :     create_multiapp_transforms(
     372        6656 :         _from_transforms, *_from_moose_app_transform, false, _from_multi_app.get());
     373             :   }
     374             : 
     375      141288 :   auto check_transform_compatibility = [this](const MultiAppCoordTransform & transform)
     376             :   {
     377      139954 :     if (transform.hasNonTranslationTransformation() && !usesMooseAppCoordTransform())
     378          24 :       mooseWarning("Transfer '",
     379           8 :                    name(),
     380             :                    "' of type '",
     381           8 :                    type(),
     382             :                    "' has non-translation transformations but it does not implement coordinate "
     383             :                    "transformations using the 'MooseAppCoordTransform' class. Your data transfers "
     384             :                    "will not be performed in the expected transformed frame");
     385      209927 :   };
     386             : 
     387             :   // set the destination coordinate systems for each transform for the purposes of determining
     388             :   // coordinate collapsing. For example if TO is XYZ and FROM is RZ, then TO will have its XYZ
     389             :   // coordinates collapsed into RZ and FROM will have a no-op for coordinate collapsing
     390             : 
     391      152186 :   for (const auto i : index_range(_from_transforms))
     392             :   {
     393       82213 :     auto & from_transform = _from_transforms[i];
     394       82213 :     from_transform->setDestinationCoordTransform(*_to_moose_app_transform);
     395       82213 :     if (i == 0)
     396       69981 :       check_transform_compatibility(*from_transform);
     397             :   }
     398      151644 :   for (const auto i : index_range(_to_transforms))
     399             :   {
     400       81671 :     auto & to_transform = _to_transforms[i];
     401       81671 :     to_transform->setDestinationCoordTransform(*_from_moose_app_transform);
     402       81671 :     if (i == 0)
     403       69973 :       check_transform_compatibility(*to_transform);
     404             :   }
     405       69973 : }
     406             : 
     407             : namespace
     408             : {
     409             : void
     410       76637 : fillInfo(MultiApp & multi_app,
     411             :          std::vector<unsigned int> & map,
     412             :          std::vector<FEProblemBase *> & problems,
     413             :          std::vector<Point> & positions)
     414             : {
     415      177600 :   for (unsigned int i_app = 0; i_app < multi_app.numGlobalApps(); i_app++)
     416             :   {
     417      100963 :     if (!multi_app.hasLocalApp(i_app))
     418        9787 :       continue;
     419             : 
     420       91176 :     auto & subapp_problem = multi_app.appProblemBase(i_app);
     421             : 
     422       91176 :     map.push_back(i_app);
     423       91176 :     problems.push_back(&subapp_problem);
     424       91176 :     if (multi_app.usingPositions())
     425       91176 :       positions.push_back(multi_app.position(i_app));
     426             :   }
     427       76637 : }
     428             : }
     429             : 
     430             : void
     431       37242 : MultiAppTransfer::getToMultiAppInfo()
     432             : {
     433       37242 :   if (!_to_multi_app)
     434           0 :     mooseError("There is no to_multiapp to get info from");
     435             : 
     436       37242 :   fillInfo(*_to_multi_app, _to_local2global_map, _to_problems, _to_positions);
     437       37242 : }
     438             : 
     439             : void
     440       39395 : MultiAppTransfer::getFromMultiAppInfo()
     441             : {
     442       39395 :   if (!_from_multi_app)
     443           0 :     mooseError("There is no from_multiapp to get info from");
     444             : 
     445       39395 :   fillInfo(*_from_multi_app, _from_local2global_map, _from_problems, _from_positions);
     446       39395 : }
     447             : 
     448             : void
     449       63695 : MultiAppTransfer::transformBoundingBox(BoundingBox & box, const MultiAppCoordTransform & transform)
     450             : {
     451       63695 :   MultiApp::transformBoundingBox(box, transform);
     452       63695 : }
     453             : 
     454             : void
     455       60628 : MultiAppTransfer::extendBoundingBoxes(const Real factor, std::vector<BoundingBox> & bboxes) const
     456             : {
     457       60628 :   const auto extension_factor = factor - 1;
     458             : 
     459             :   // Extend (or contract if the extension factor is negative) bounding boxes along all the
     460             :   // directions by the same length. Greater than zero values of this member may be necessary because
     461             :   // the nearest bounding box does not necessarily give you the closest node/element. It will depend
     462             :   // on the partition and geometry. A node/element will more likely find its nearest source
     463             :   // element/node by extending bounding boxes. If each of the bounding boxes covers the entire
     464             :   // domain, a node/element will be able to find its nearest source element/node for sure, but at
     465             :   // the same time, more communication will be involved and can be expensive.
     466      157936 :   for (auto & box : bboxes)
     467             :   {
     468             :     // libmesh set an invalid bounding box using this code
     469             :     // for (unsigned int i=0; i<LIBMESH_DIM; i++)
     470             :     // {
     471             :     //   this->first(i)  =  std::numeric_limits<Real>::max();
     472             :     //   this->second(i) = -std::numeric_limits<Real>::max();
     473             :     // }
     474             :     // If it is an invalid box, we should skip it
     475       97308 :     if (box.first(0) == std::numeric_limits<Real>::max())
     476           0 :       continue;
     477             : 
     478       97308 :     auto width = box.second - box.first;
     479       97308 :     box.second += width * extension_factor;
     480       97308 :     box.first -= width * extension_factor;
     481             :   }
     482       60628 : }
     483             : 
     484             : std::vector<BoundingBox>
     485        2333 : MultiAppTransfer::getFromBoundingBoxes()
     486             : {
     487        2333 :   std::vector<std::pair<Point, Point>> bb_points(_from_meshes.size());
     488        5114 :   for (unsigned int i = 0; i < _from_meshes.size(); i++)
     489             :   {
     490             :     // Get a bounding box around the mesh elements that are local to the current
     491             :     // processor.
     492        2781 :     BoundingBox bbox = MeshTools::create_local_bounding_box(*_from_meshes[i]);
     493             : 
     494             :     // Translate the bounding box to the from domain's position. We may have rotations so we must
     495             :     // be careful in constructing the new min and max (first and second)
     496        2781 :     const auto from_global_num = getGlobalSourceAppIndex(i);
     497        2781 :     transformBoundingBox(bbox, *_from_transforms[from_global_num]);
     498             : 
     499             :     // Cast the bounding box into a pair of points (so it can be put through
     500             :     // MPI communication).
     501        2781 :     bb_points[i] = static_cast<std::pair<Point, Point>>(bbox);
     502             :   }
     503             : 
     504             :   // Serialize the bounding box points.
     505        2333 :   _communicator.allgather(bb_points);
     506             : 
     507             :   // Recast the points back into bounding boxes and return.
     508        2333 :   std::vector<BoundingBox> bboxes(bb_points.size());
     509        6542 :   for (unsigned int i = 0; i < bb_points.size(); i++)
     510        4209 :     bboxes[i] = static_cast<BoundingBox>(bb_points[i]);
     511             : 
     512             :   // possibly extend bounding boxes
     513        2333 :   extendBoundingBoxes(_bbox_factor, bboxes);
     514             : 
     515        4666 :   return bboxes;
     516        2333 : }
     517             : 
     518             : std::vector<BoundingBox>
     519          85 : MultiAppTransfer::getFromBoundingBoxes(BoundaryID boundary_id)
     520             : {
     521          85 :   std::vector<std::pair<Point, Point>> bb_points(_from_meshes.size());
     522          85 :   const Real min_r = std::numeric_limits<Real>::lowest();
     523          85 :   const Real max_r = std::numeric_limits<Real>::max();
     524             : 
     525         184 :   for (unsigned int i = 0; i < _from_meshes.size(); i++)
     526             :   {
     527             : 
     528          99 :     Point min(max_r, max_r, max_r);
     529          99 :     Point max(min_r, min_r, min_r);
     530          99 :     bool at_least_one = false;
     531             : 
     532             :     // TODO: Factor this into mesh_tools after adding new boundary bounding box routine.
     533          99 :     const ConstBndNodeRange & bnd_nodes = *_from_meshes[i]->getBoundaryNodeRange();
     534        5893 :     for (const auto & bnode : bnd_nodes)
     535             :     {
     536        7242 :       if (bnode->_bnd_id == boundary_id &&
     537        1448 :           bnode->_node->processor_id() == _from_meshes[i]->processor_id())
     538             :       {
     539        1404 :         at_least_one = true;
     540        1404 :         const auto & node = *bnode->_node;
     541        5616 :         for (const auto i : make_range(Moose::dim))
     542             :         {
     543        4212 :           min(i) = std::min(min(i), node(i));
     544        4212 :           max(i) = std::max(max(i), node(i));
     545             :         }
     546             :       }
     547             :     }
     548             : 
     549          99 :     BoundingBox bbox(min, max);
     550          99 :     if (!at_least_one)
     551           9 :       bbox.min() = max; // If we didn't hit any nodes, this will be _the_ minimum bbox
     552             :     else
     553             :     {
     554             :       // Translate the bounding box to the from domain's position. We may have rotations so we must
     555             :       // be careful in constructing the new min and max (first and second)
     556          90 :       const auto from_global_num = getGlobalSourceAppIndex(i);
     557          90 :       transformBoundingBox(bbox, *_from_transforms[from_global_num]);
     558             :     }
     559             : 
     560             :     // Cast the bounding box into a pair of points (so it can be put through
     561             :     // MPI communication).
     562          99 :     bb_points[i] = static_cast<std::pair<Point, Point>>(bbox);
     563             :   }
     564             : 
     565             :   // Serialize the bounding box points.
     566          85 :   _communicator.allgather(bb_points);
     567             : 
     568             :   // Recast the points back into bounding boxes and return.
     569          85 :   std::vector<BoundingBox> bboxes(bb_points.size());
     570         226 :   for (unsigned int i = 0; i < bb_points.size(); i++)
     571         141 :     bboxes[i] = static_cast<BoundingBox>(bb_points[i]);
     572             : 
     573             :   // possibly extend bounding boxes
     574          85 :   extendBoundingBoxes(_bbox_factor, bboxes);
     575             : 
     576         170 :   return bboxes;
     577          85 : }
     578             : 
     579             : std::vector<unsigned int>
     580       60628 : MultiAppTransfer::getFromsPerProc()
     581             : {
     582       60628 :   std::vector<unsigned int> froms_per_proc;
     583       60628 :   if (_to_multi_app)
     584       32340 :     froms_per_proc.resize(n_processors(), 1);
     585       60628 :   if (_from_multi_app)
     586             :   {
     587       33841 :     froms_per_proc.resize(n_processors());
     588       33841 :     _communicator.allgather(_from_multi_app->numLocalApps(), froms_per_proc);
     589             :   }
     590       60628 :   return froms_per_proc;
     591           0 : }
     592             : 
     593             : NumericVector<Real> &
     594        1391 : MultiAppTransfer::getTransferVector(unsigned int i_local, std::string var_name)
     595             : {
     596             :   mooseAssert(_to_multi_app, "getTransferVector only works for transfers to multiapps");
     597             : 
     598        1391 :   return _to_multi_app->appTransferVector(_to_local2global_map[i_local], var_name);
     599             : }
     600             : 
     601             : void
     602        3768 : MultiAppTransfer::checkVariable(const FEProblemBase & fe_problem,
     603             :                                 const VariableName & var_name,
     604             :                                 const std::string & param_name) const
     605             : {
     606        3768 :   if (!fe_problem.hasVariable(var_name))
     607             :   {
     608           4 :     if (param_name.empty())
     609           4 :       mooseError("The variable '", var_name, "' does not exist.");
     610             :     else
     611           0 :       paramError(param_name, "The variable '", var_name, "' does not exist.");
     612             :   }
     613        3764 : }
     614             : 
     615             : Point
     616         394 : MultiAppTransfer::getPointInTargetAppFrame(const Point & p,
     617             :                                            unsigned int local_i_to,
     618             :                                            const std::string & phase) const
     619             : {
     620         394 :   const auto & to_transform = _to_transforms[getGlobalTargetAppIndex(local_i_to)];
     621         394 :   if (to_transform->hasCoordinateSystemTypeChange())
     622             :   {
     623           0 :     if (!_skip_coordinate_collapsing)
     624           0 :       mooseInfo(phase + " cannot use the point in the target app frame due to the "
     625             :                         "non-uniqueness of the coordinate collapsing reverse mapping."
     626             :                         " Coordinate collapse is ignored for this operation");
     627           0 :     to_transform->skipCoordinateCollapsing(true);
     628           0 :     const auto target_point = to_transform->mapBack(p);
     629           0 :     to_transform->skipCoordinateCollapsing(false);
     630           0 :     return target_point;
     631             :   }
     632             :   else
     633         394 :     return to_transform->mapBack(p);
     634             : }
     635             : 
     636             : unsigned int
     637     5265251 : MultiAppTransfer::getGlobalSourceAppIndex(unsigned int i_from) const
     638             : {
     639             :   mooseAssert(_current_direction == TO_MULTIAPP || i_from < _from_local2global_map.size(),
     640             :               "Out of bounds local from-app index");
     641     5265251 :   return _current_direction == TO_MULTIAPP ? 0 : _from_local2global_map[i_from];
     642             : }
     643             : 
     644             : unsigned int
     645      434155 : MultiAppTransfer::getGlobalTargetAppIndex(unsigned int i_to) const
     646             : {
     647             :   mooseAssert(_current_direction == FROM_MULTIAPP || i_to < _to_local2global_map.size(),
     648             :               "Out of bounds local to-app index");
     649      434155 :   return _current_direction == FROM_MULTIAPP ? 0 : _to_local2global_map[i_to];
     650             : }
     651             : 
     652             : unsigned int
     653           0 : MultiAppTransfer::getLocalSourceAppIndex(unsigned int i_from) const
     654             : {
     655           0 :   return _current_direction == TO_MULTIAPP
     656           0 :              ? 0
     657           0 :              : _from_local2global_map[i_from] - _from_local2global_map[0];
     658             : }
     659             : 
     660             : void
     661       27741 : MultiAppTransfer::errorIfObjectExecutesOnTransferInSourceApp(const std::string & object_name) const
     662             : {
     663             :   // parent app is the source app, EXEC_TRANSFER is fine
     664       27741 :   if (!hasFromMultiApp())
     665           0 :     return;
     666             :   // Get the app and problem
     667       27741 :   const auto & app = getFromMultiApp();
     668       27741 :   if (!app->hasApp())
     669           0 :     return;
     670       27741 :   const auto & problem = app->appProblemBase(app->firstLocalApp());
     671             :   // Use the warehouse to find the object
     672       27741 :   std::vector<SetupInterface *> objects_with_exec_on;
     673       27741 :   problem.theWarehouse()
     674       55482 :       .query()
     675       27741 :       .template condition<AttribName>(object_name)
     676       27741 :       .template condition<AttribExecOns>(EXEC_TRANSFER)
     677       27741 :       .queryInto(objects_with_exec_on);
     678       27741 :   if (objects_with_exec_on.size())
     679           4 :     mooseError("Object '" + object_name +
     680             :                "' should not be executed on EXEC_TRANSFER, because this transfer has "
     681             :                "indicated it does not support it.\nExecuting this object on TIMESTEP_END should be "
     682             :                "sufficient to get updated values.");
     683       27737 : }

Generated by: LCOV version 1.14