LCOV - code coverage report
Current view: top level - src/transfers - MultiAppGeneralFieldShapeEvaluationTransfer.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 66 69 95.7 %
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 "MultiAppGeneralFieldShapeEvaluationTransfer.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 "Positions.h"
      19             : 
      20             : #include "libmesh/system.h"
      21             : #include "libmesh/mesh_function.h"
      22             : 
      23             : registerMooseObject("MooseApp", MultiAppGeneralFieldShapeEvaluationTransfer);
      24             : 
      25             : InputParameters
      26       18413 : MultiAppGeneralFieldShapeEvaluationTransfer::validParams()
      27             : {
      28       18413 :   InputParameters params = MultiAppGeneralFieldTransfer::validParams();
      29       18413 :   params.addClassDescription(
      30             :       "Transfers field data at the MultiApp position using the finite element shape "
      31             :       "functions from the origin application.");
      32             : 
      33             :   // Blanket ban on origin boundary restriction. Most shape functions have their support extend
      34             :   // outside the boundary. For a true face variable, this parameter would make sense again
      35       18413 :   params.suppressParameter<std::vector<BoundaryName>>("from_boundaries");
      36             :   // Shape function evaluations return an invalid value outside an app's domain anyway
      37       18413 :   params.suppressParameter<bool>("from_app_must_contain_point");
      38             : 
      39       18413 :   return params;
      40           0 : }
      41             : 
      42        2076 : MultiAppGeneralFieldShapeEvaluationTransfer::MultiAppGeneralFieldShapeEvaluationTransfer(
      43        2076 :     const InputParameters & parameters)
      44        2076 :   : MultiAppGeneralFieldTransfer(parameters)
      45             : {
      46             :   // Nearest point isn't well defined for sending app-based data from main app to a multiapp
      47        2072 :   if (_nearest_positions_obj && isParamValid("to_multi_app") && !isParamValid("from_multi_app"))
      48           0 :     paramError("use_nearest_position",
      49             :                "Cannot use nearest-position algorithm when sending from the main application");
      50             : 
      51             :   // There's not much use for matching cell divisions when the locations have to match exactly
      52             :   // to get a valid source variable value anyway
      53        4144 :   if (_from_mesh_division_behavior == MeshDivisionTransferUse::MATCH_DIVISION_INDEX ||
      54        2072 :       _to_mesh_division_behavior == MeshDivisionTransferUse::MATCH_DIVISION_INDEX)
      55           0 :     paramError("from_mesh_division_usage",
      56             :                "Matching division index is disabled for shape evaluation transfers");
      57        2072 : }
      58             : 
      59             : void
      60        4620 : MultiAppGeneralFieldShapeEvaluationTransfer::prepareEvaluationOfInterpValues(
      61             :     const unsigned int var_index)
      62             : {
      63        4620 :   _local_bboxes.clear();
      64        4620 :   if (_use_bounding_boxes)
      65        4620 :     extractLocalFromBoundingBoxes(_local_bboxes);
      66             : 
      67        4620 :   _local_meshfuns.clear();
      68        4620 :   buildMeshFunctions(var_index, _local_meshfuns);
      69        4620 : }
      70             : 
      71             : void
      72        4620 : MultiAppGeneralFieldShapeEvaluationTransfer::buildMeshFunctions(
      73             :     const unsigned int var_index, std::vector<libMesh::MeshFunction> & local_meshfuns)
      74             : {
      75        4620 :   local_meshfuns.reserve(_from_problems.size());
      76             : 
      77             :   // Construct a local mesh function for each origin problem
      78       10396 :   for (unsigned int i_from = 0; i_from < _from_problems.size(); ++i_from)
      79             :   {
      80        5776 :     FEProblemBase & from_problem = *_from_problems[i_from];
      81             :     MooseVariableFieldBase & from_var =
      82        5776 :         from_problem.getVariable(0,
      83        5776 :                                  _from_var_names[var_index],
      84             :                                  Moose::VarKindType::VAR_ANY,
      85             :                                  Moose::VarFieldType::VAR_FIELD_ANY);
      86             : 
      87        5776 :     System & from_sys = from_var.sys().system();
      88        5776 :     unsigned int from_var_num = from_sys.variable_number(getFromVarName(var_index));
      89             : 
      90       11552 :     local_meshfuns.emplace_back(getEquationSystem(from_problem, _displaced_source_mesh),
      91        5776 :                                 *from_sys.current_local_solution,
      92             :                                 from_sys.get_dof_map(),
      93             :                                 from_var_num);
      94        5776 :     local_meshfuns.back().init();
      95        5776 :     local_meshfuns.back().enable_out_of_mesh_mode(GeneralFieldTransfer::BetterOutOfMeshValue);
      96             :   }
      97        4620 : }
      98             : 
      99             : void
     100        6772 : MultiAppGeneralFieldShapeEvaluationTransfer::evaluateInterpValues(
     101             :     const std::vector<std::pair<Point, unsigned int>> & incoming_points,
     102             :     std::vector<std::pair<Real, Real>> & outgoing_vals)
     103             : {
     104        6772 :   evaluateInterpValuesWithMeshFunctions(
     105        6772 :       _local_bboxes, _local_meshfuns, incoming_points, outgoing_vals);
     106        6772 : }
     107             : 
     108             : void
     109        6772 : MultiAppGeneralFieldShapeEvaluationTransfer::evaluateInterpValuesWithMeshFunctions(
     110             :     const std::vector<BoundingBox> & local_bboxes,
     111             :     std::vector<libMesh::MeshFunction> & local_meshfuns,
     112             :     const std::vector<std::pair<Point, unsigned int>> & incoming_points,
     113             :     std::vector<std::pair<Real, Real>> & outgoing_vals)
     114             : {
     115        6772 :   dof_id_type i_pt = 0;
     116      727030 :   for (auto & [pt, mesh_div] : incoming_points)
     117             :   {
     118      720258 :     bool point_found = false;
     119      720258 :     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             :     // - or if looking for the nearest app, we also check them all
     125     1532957 :     for (MooseIndex(_from_problems.size()) i_from = 0;
     126     2353927 :          i_from < _from_problems.size() &&
     127      820970 :          (!point_found || _search_value_conflicts || _nearest_positions_obj);
     128             :          ++i_from)
     129             :     {
     130             :       // Check spatial restrictions
     131      812699 :       Real distance = 0;
     132      812699 :       if (!acceptPointInOriginMesh(i_from, local_bboxes, pt, mesh_div, distance))
     133      565492 :         continue;
     134             :       else
     135             :       {
     136             :         // Use mesh function to compute interpolation values
     137      258558 :         const auto from_global_num = getGlobalSourceAppIndex(i_from);
     138      258558 :         const auto local_pt = _from_transforms[from_global_num]->mapBack(pt);
     139      258558 :         auto val = (local_meshfuns[i_from])(local_pt);
     140             : 
     141             :         // Look for overlaps. The check is not active outside of overlap search because in that
     142             :         // case we accept the first value from the lowest ranked process
     143             :         // NOTE: There is no guarantee this will be the final value used among all problems
     144             :         //       but for shape evaluation we really do expect only one value to even be valid
     145      258558 :         if (detectConflict(val, outgoing_vals[i_pt].first, distance, outgoing_vals[i_pt].second))
     146             :         {
     147             :           // In the nearest-position/app mode, we save conflicts in the reference frame
     148          74 :           if (_nearest_positions_obj)
     149          32 :             registerConflict(i_from, 0, pt, distance, true);
     150             :           else
     151          42 :             registerConflict(i_from, 0, local_pt, distance, true);
     152             :         }
     153             : 
     154             :         // No need to consider decision factors if value is invalid
     155      258558 :         if (val == GeneralFieldTransfer::BetterOutOfMeshValue)
     156       11351 :           continue;
     157             :         else
     158      247207 :           point_found = true;
     159             : 
     160             :         // Assign value and the distance from the target point to the origin data
     161             :         // distance only matters if multiple applications are providing a valid value
     162             :         // which would mean they overlap in the reference space. The distance can help
     163             :         // lift the indetermination on which value to select
     164      247207 :         if (distance < outgoing_vals[i_pt].second)
     165             :         {
     166      247137 :           outgoing_vals[i_pt].first = val;
     167      247137 :           outgoing_vals[i_pt].second = distance;
     168             :         }
     169             :       }
     170             :     }
     171             : 
     172      720258 :     if (!point_found)
     173      473125 :       outgoing_vals[i_pt] = {GeneralFieldTransfer::BetterOutOfMeshValue,
     174      946250 :                              GeneralFieldTransfer::BetterOutOfMeshValue};
     175             : 
     176             :     // Move to next point
     177      720258 :     i_pt++;
     178             :   }
     179        6772 : }

Generated by: LCOV version 1.14