LCOV - code coverage report
Current view: top level - src/transfers - MultiAppGeneralFieldUserObjectTransfer.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 67 71 94.4 %
Date: 2026-05-29 20:35:17 Functions: 7 7 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        5485 : MultiAppGeneralFieldUserObjectTransfer::validParams()
      28             : {
      29        5485 :   InputParameters params = MultiAppGeneralFieldTransfer::validParams();
      30        5485 :   params.addClassDescription(
      31             :       "Transfers user object spatial evaluations from an origin app onto a variable in the target "
      32             :       "application.");
      33             : 
      34       16455 :   params.set<std::vector<VariableName>>("source_variable") = std::vector<VariableName>{};
      35       10970 :   params.suppressParameter<std::vector<VariableName>>("source_variable");
      36       16455 :   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        5485 :   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        5485 :   params.suppressParameter<std::vector<BoundaryName>>("from_boundaries");
      46        5485 :   return params;
      47           0 : }
      48             : 
      49        1215 : MultiAppGeneralFieldUserObjectTransfer::MultiAppGeneralFieldUserObjectTransfer(
      50        1215 :     const InputParameters & parameters)
      51             :   : MultiAppGeneralFieldTransfer(parameters),
      52        3627 :     _user_object_name(getParam<UserObjectName>("source_user_object"))
      53             : {
      54        1206 :   if (_to_var_names.size() > 1)
      55           6 :     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        5067 :   if (isParamValid("from_blocks") && !_source_app_must_contain_point &&
      59        1713 :       !parameters.isParamSetByUser("extrapolation_constant"))
      60           6 :     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        1500 :   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        1200 : }
      70             : 
      71             : void
      72        1212 : MultiAppGeneralFieldUserObjectTransfer::execute()
      73             : {
      74             :   // Execute the user object if it was specified to execute on TRANSFER
      75        1212 :   switch (_current_direction)
      76             :   {
      77         472 :     case TO_MULTIAPP:
      78             :     {
      79         472 :       checkParentAppUserObjectExecuteOn(_user_object_name);
      80         472 :       _fe_problem.computeUserObjectByName(EXEC_TRANSFER, Moose::PRE_AUX, _user_object_name);
      81         472 :       _fe_problem.computeUserObjectByName(EXEC_TRANSFER, Moose::POST_AUX, _user_object_name);
      82         472 :       break;
      83             :     }
      84         520 :     case FROM_MULTIAPP:
      85         520 :       errorIfObjectExecutesOnTransferInSourceApp(_user_object_name);
      86             :   }
      87             : 
      88             :   // Perfom the actual transfer
      89        1212 :   MultiAppGeneralFieldTransfer::execute();
      90        1206 : }
      91             : 
      92             : void
      93        1212 : MultiAppGeneralFieldUserObjectTransfer::prepareEvaluationOfInterpValues(
      94             :     const unsigned int /* var_index */)
      95             : {
      96        1212 :   _local_bboxes.clear();
      97        1212 :   if (_use_bounding_boxes)
      98        1212 :     extractLocalFromBoundingBoxes(_local_bboxes);
      99        1212 : }
     100             : 
     101             : void
     102        1762 : MultiAppGeneralFieldUserObjectTransfer::evaluateInterpValues(
     103             :     const unsigned int /*var_index*/,
     104             :     const std::vector<std::pair<Point, unsigned int>> & incoming_points,
     105             :     std::vector<std::pair<Real, Real>> & outgoing_vals)
     106             : {
     107        1762 :   evaluateInterpValuesWithUserObjects(_local_bboxes, incoming_points, outgoing_vals);
     108        1762 : }
     109             : 
     110             : void
     111        1762 : MultiAppGeneralFieldUserObjectTransfer::evaluateInterpValuesWithUserObjects(
     112             :     const std::vector<BoundingBox> & local_bboxes,
     113             :     const std::vector<std::pair<Point, unsigned int>> & incoming_points,
     114             :     std::vector<std::pair<Real, Real>> & outgoing_vals)
     115             : {
     116        1762 :   dof_id_type i_pt = 0;
     117      751567 :   for (auto & [pt, mesh_div] : incoming_points)
     118             :   {
     119      749805 :     bool point_found = false;
     120      749805 :     outgoing_vals[i_pt].second = GeneralFieldTransfer::OutOfMeshValue;
     121             : 
     122             :     // Loop on all local origin problems until:
     123             :     // - we've found the point in an app and the value at that point is valid
     124             :     // - or if looking for conflicts between apps, we must check them all
     125     1842708 :     for (MooseIndex(_from_problems.size()) i_from = 0;
     126     2944939 :          i_from < _from_problems.size() &&
     127     1102231 :          (!point_found || _search_value_conflicts || _nearest_positions_obj);
     128             :          ++i_from)
     129             :     {
     130             :       // User object spatialValue() evaluations do not provide a distance
     131     1092903 :       Real distance = 1;
     132             :       // Check spatial restrictions
     133     1092903 :       if (!acceptPointInOriginMesh(i_from, local_bboxes, pt, mesh_div, distance))
     134      990728 :         continue;
     135             :       else
     136             :       {
     137             :         // Get user object from the local problem
     138             :         const UserObject & user_object =
     139      102175 :             _from_problems[i_from]->getUserObjectBase(_user_object_name);
     140             : 
     141             :         // Use spatial value routine to compute the origin value to transfer
     142             :         const auto local_pt =
     143      204350 :             getPointInSourceAppFrame(pt, i_from, "User object spatial value evaluation");
     144      102175 :         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      102175 :         if (detectConflict(val, outgoing_vals[i_pt].first, distance, outgoing_vals[i_pt].second))
     151             :         {
     152           9 :           if (_nearest_positions_obj)
     153           0 :             registerConflict(i_from, 0, pt, distance, true);
     154             :           else
     155           9 :             registerConflict(i_from, 0, local_pt, distance, true);
     156             :         }
     157             : 
     158             :         // No need to consider decision factors if value is invalid
     159      102175 :         if (val == GeneralFieldTransfer::OutOfMeshValue)
     160           0 :           continue;
     161             :         else
     162      102175 :           point_found = true;
     163             : 
     164             :         // Assign value
     165      102175 :         if (distance < outgoing_vals[i_pt].second)
     166             :         {
     167      102157 :           outgoing_vals[i_pt].first = val;
     168      102157 :           outgoing_vals[i_pt].second = distance;
     169             :         }
     170             :       }
     171             :     }
     172             : 
     173      749805 :     if (!point_found)
     174      647648 :       outgoing_vals[i_pt] = {GeneralFieldTransfer::OutOfMeshValue,
     175     1295296 :                              GeneralFieldTransfer::OutOfMeshValue};
     176             : 
     177             :     // Move to next point
     178      749805 :     i_pt++;
     179             :   }
     180        1762 : }
     181             : 
     182             : std::string
     183           3 : MultiAppGeneralFieldUserObjectTransfer::getDataSourceName(unsigned int /*var_index*/) const
     184             : {
     185           3 :   return "user object '" + _user_object_name + "'";
     186             : }

Generated by: LCOV version 1.14