LCOV - code coverage report
Current view: top level - src/transfers - MultiAppGeneralFieldUserObjectTransfer.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 64 68 94.1 %
Date: 2025-07-17 01:28:37 Functions: 6 6 100.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             : #include "MultiAppGeneralFieldUserObjectTransfer.h"
      11             : 
      12             : // MOOSE includes
      13             : #include "DisplacedProblem.h"
      14             : #include "FEProblem.h"
      15             : #include "MooseMesh.h"
      16             : #include "MooseTypes.h"
      17             : #include "MooseVariableFE.h"
      18             : #include "UserObject.h"
      19             : #include "Positions.h"
      20             : 
      21             : #include "libmesh/system.h"
      22             : #include "libmesh/mesh_function.h"
      23             : 
      24             : registerMooseObject("MooseApp", MultiAppGeneralFieldUserObjectTransfer);
      25             : 
      26             : InputParameters
      27       16725 : MultiAppGeneralFieldUserObjectTransfer::validParams()
      28             : {
      29       16725 :   InputParameters params = MultiAppGeneralFieldTransfer::validParams();
      30       16725 :   params.addClassDescription(
      31             :       "Transfers user object spatial evaluations from an origin app onto a variable in the target "
      32             :       "application.");
      33             : 
      34       16725 :   params.set<std::vector<VariableName>>("source_variable") = std::vector<VariableName>{};
      35       16725 :   params.suppressParameter<std::vector<VariableName>>("source_variable");
      36       16725 :   params.addRequiredParam<UserObjectName>("source_user_object",
      37             :                                           "The UserObject you want to transfer values from. "
      38             :                                           "It must implement the SpatialValue() class routine");
      39             : 
      40             :   // Blanket ban on origin boundary restriction. User objects tend to extend beyond boundaries,
      41             :   // and be able to be evaluated within a volume rather than only on a boundary
      42             :   // This could be re-enabled for spatial user objects that are only defined on boundaries
      43       16725 :   params.suppressParameter<std::vector<BoundaryName>>("from_boundaries");
      44       16725 :   return params;
      45           0 : }
      46             : 
      47        1234 : MultiAppGeneralFieldUserObjectTransfer::MultiAppGeneralFieldUserObjectTransfer(
      48        1234 :     const InputParameters & parameters)
      49             :   : MultiAppGeneralFieldTransfer(parameters),
      50        1234 :     _user_object_name(getParam<UserObjectName>("source_user_object"))
      51             : {
      52        1222 :   if (_to_var_names.size() > 1)
      53           4 :     paramError("variable", "Only one variable at a time is supported by this transfer");
      54             : 
      55             :   // Block restriction does not make sense if we're ok with extrapolating
      56        2696 :   if (isParamValid("from_blocks") && !_source_app_must_contain_point &&
      57        1478 :       !parameters.isParamSetByUser("extrapolation_constant"))
      58           4 :     paramError("from_app_must_contain_point",
      59             :                "Source block restriction cannot be used at the same type as allowing extrapolation"
      60             :                " of values for a user object transfer (with 'from_app_must_contain_point=false') "
      61             :                " unless an extrapolation constant is provided (with 'extrapolation_constant')");
      62             : 
      63             :   // Nearest point isn't well defined for sending app-based data from main app to a multiapp
      64        1214 :   if (_nearest_positions_obj && isParamValid("to_multi_app") && !isParamValid("from_multi_app"))
      65           0 :     paramError("use_nearest_position",
      66             :                "Cannot use nearest-position algorithm when sending from the main application");
      67        1214 : }
      68             : 
      69             : void
      70        2294 : MultiAppGeneralFieldUserObjectTransfer::execute()
      71             : {
      72             :   // Execute the user object if it was specified to execute on TRANSFER
      73        2294 :   switch (_current_direction)
      74             :   {
      75         464 :     case TO_MULTIAPP:
      76             :     {
      77         464 :       _fe_problem.computeUserObjectByName(EXEC_TRANSFER, Moose::PRE_AUX, _user_object_name);
      78         464 :       _fe_problem.computeUserObjectByName(EXEC_TRANSFER, Moose::POST_AUX, _user_object_name);
      79         464 :       break;
      80             :     }
      81         510 :     case FROM_MULTIAPP:
      82         510 :       errorIfObjectExecutesOnTransferInSourceApp(_user_object_name);
      83             :   }
      84             : 
      85             :   // Perfom the actual transfer
      86        2294 :   MultiAppGeneralFieldTransfer::execute();
      87        2286 : }
      88             : 
      89             : void
      90        2294 : MultiAppGeneralFieldUserObjectTransfer::prepareEvaluationOfInterpValues(
      91             :     const unsigned int /* var_index */)
      92             : {
      93        2294 :   _local_bboxes.clear();
      94        2294 :   if (_use_bounding_boxes)
      95        2294 :     extractLocalFromBoundingBoxes(_local_bboxes);
      96        2294 : }
      97             : 
      98             : void
      99        3284 : MultiAppGeneralFieldUserObjectTransfer::evaluateInterpValues(
     100             :     const std::vector<std::pair<Point, unsigned int>> & incoming_points,
     101             :     std::vector<std::pair<Real, Real>> & outgoing_vals)
     102             : {
     103        3284 :   evaluateInterpValuesWithUserObjects(_local_bboxes, incoming_points, outgoing_vals);
     104        3284 : }
     105             : 
     106             : void
     107        3284 : MultiAppGeneralFieldUserObjectTransfer::evaluateInterpValuesWithUserObjects(
     108             :     const std::vector<BoundingBox> & local_bboxes,
     109             :     const std::vector<std::pair<Point, unsigned int>> & incoming_points,
     110             :     std::vector<std::pair<Real, Real>> & outgoing_vals)
     111             : {
     112        3284 :   dof_id_type i_pt = 0;
     113      728228 :   for (auto & [pt, mesh_div] : incoming_points)
     114             :   {
     115      724944 :     bool point_found = false;
     116      724944 :     outgoing_vals[i_pt].second = GeneralFieldTransfer::BetterOutOfMeshValue;
     117             : 
     118             :     // Loop on all local origin problems until:
     119             :     // - we've found the point in an app and the value at that point is valid
     120             :     // - or if looking for conflicts between apps, we must check them all
     121     1748729 :     for (MooseIndex(_from_problems.size()) i_from = 0;
     122     2780537 :          i_from < _from_problems.size() &&
     123     1031808 :          (!point_found || _search_value_conflicts || _nearest_positions_obj);
     124             :          ++i_from)
     125             :     {
     126             :       // User object spatialValue() evaluations do not provide a distance
     127     1023785 :       Real distance = 1;
     128             :       // Check spatial restrictions
     129     1023785 :       if (!acceptPointInOriginMesh(i_from, local_bboxes, pt, mesh_div, distance))
     130      911844 :         continue;
     131             :       else
     132             :       {
     133      111941 :         const auto from_global_num = getGlobalSourceAppIndex(i_from);
     134             : 
     135             :         // Get user object from the local problem
     136             :         const UserObject & user_object =
     137      111941 :             _from_problems[i_from]->getUserObjectBase(_user_object_name);
     138             : 
     139             :         // Use spatial value routine to compute the origin value to transfer
     140      111941 :         const auto local_pt = _from_transforms[from_global_num]->mapBack(pt);
     141      111941 :         auto val = user_object.spatialValue(local_pt);
     142             : 
     143             :         // Look for overlaps. The check is not active outside of overlap search because in that
     144             :         // case we accept the first value from the lowest ranked process
     145             :         // NOTE: There is no guarantee this will be the final value used among all problems
     146             :         //       but we register an overlap as soon as two values are possible from this rank
     147      111941 :         if (detectConflict(val, outgoing_vals[i_pt].first, distance, outgoing_vals[i_pt].second))
     148             :         {
     149          12 :           if (_nearest_positions_obj)
     150           0 :             registerConflict(i_from, 0, pt, distance, true);
     151             :           else
     152          12 :             registerConflict(i_from, 0, local_pt, distance, true);
     153             :         }
     154             : 
     155             :         // No need to consider decision factors if value is invalid
     156      111941 :         if (val == GeneralFieldTransfer::BetterOutOfMeshValue)
     157           0 :           continue;
     158             :         else
     159      111941 :           point_found = true;
     160             : 
     161             :         // Assign value
     162      111941 :         if (distance < outgoing_vals[i_pt].second)
     163             :         {
     164      111917 :           outgoing_vals[i_pt].first = val;
     165      111917 :           outgoing_vals[i_pt].second = distance;
     166             :         }
     167             :       }
     168             :     }
     169             : 
     170      724944 :     if (!point_found)
     171      613027 :       outgoing_vals[i_pt] = {GeneralFieldTransfer::BetterOutOfMeshValue,
     172     1226054 :                              GeneralFieldTransfer::BetterOutOfMeshValue};
     173             : 
     174             :     // Move to next point
     175      724944 :     i_pt++;
     176             :   }
     177        3284 : }

Generated by: LCOV version 1.14