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

Generated by: LCOV version 1.14