LCOV - code coverage report
Current view: top level - src/actions - CoupledHeatTransferAction.C (source / functions) Hit Total Coverage
Test: idaholab/moose thermal_hydraulics: #32971 (54bef8) with base c6cf66 Lines: 142 153 92.8 %
Date: 2026-05-29 20:41:18 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 "CoupledHeatTransferAction.h"
      11             : #include "DiscreteLineSegmentInterface.h"
      12             : #include "FEProblem.h"
      13             : 
      14             : registerMooseAction("ThermalHydraulicsApp", CoupledHeatTransferAction, "add_bc");
      15             : registerMooseAction("ThermalHydraulicsApp", CoupledHeatTransferAction, "add_user_object");
      16             : registerMooseAction("ThermalHydraulicsApp", CoupledHeatTransferAction, "add_transfer");
      17             : 
      18             : InputParameters
      19          74 : CoupledHeatTransferAction::validParams()
      20             : {
      21          74 :   InputParameters params = Action::validParams();
      22             : 
      23          74 :   params.addClassDescription(
      24             :       "Action that creates the necessary objects, for the solid side, to couple a "
      25             :       "solid heat conduction region to a 1-D flow channel via convective heat transfer");
      26             : 
      27         148 :   params.addRequiredParam<std::vector<BoundaryName>>("boundary",
      28             :                                                      "Boundary name(s) on the solid side");
      29         148 :   params.addRequiredParam<VariableName>("T", "Solid side temperature variable");
      30         148 :   params.addRequiredParam<VariableName>(
      31             :       "T_wall", "Variable on the flow channel side into which to transfer the solid temperature");
      32         148 :   params.addRequiredParam<std::vector<VariableName>>(
      33             :       "T_fluid", "Variable(s) on the solid side into which to transfer the fluid temperature(s)");
      34         148 :   params.addRequiredParam<std::vector<VariableName>>(
      35             :       "htc",
      36             :       "Variable(s) on the solid side into which to transfer the heat transfer coefficient(s)");
      37         148 :   params.addParam<std::vector<VariableName>>(
      38             :       "kappa", "Variables on the solid side into which to transfer the wall contact fractions");
      39         148 :   params.addRequiredParam<std::vector<UserObjectName>>(
      40             :       "T_fluid_user_objects", "Spatial user object(s) holding the fluid temperature values");
      41         148 :   params.addRequiredParam<std::vector<UserObjectName>>(
      42             :       "htc_user_objects", "Spatial user object(s) holding the heat transfer coefficient values");
      43         148 :   params.addParam<std::vector<UserObjectName>>(
      44             :       "kappa_user_objects", "Spatial user object(s) holding the wall contact fraction values");
      45             : 
      46         148 :   params.addRequiredParam<Point>("position", "Start position of axis in 3-D space [m]");
      47         148 :   params.addRequiredParam<RealVectorValue>(
      48             :       "orientation",
      49             :       "Direction of axis from start position to end position (no need to normalize)");
      50         148 :   params.addParam<Real>("rotation", 0.0, "Angle of rotation about the x-axis [degrees]");
      51         148 :   params.addRequiredParam<std::vector<Real>>("length", "Length of each axial section [m]");
      52         148 :   params.addRequiredParam<std::vector<unsigned int>>("n_elems",
      53             :                                                      "Number of elements in each axial section");
      54             : 
      55         148 :   params.addRequiredParam<std::string>("multi_app", "The name of the multi-app.");
      56             : 
      57         148 :   params.addRangeCheckedParam<std::vector<Real>>(
      58             :       "fixed_bounding_box_size",
      59             :       "fixed_bounding_box_size >= 0",
      60             :       "The 'fixed_bounding_box_size' value to use for each MultiAppGeneralFieldUserObjectTransfer. "
      61             :       "If this parameter is not provided, a greedy search will be used instead of bounding boxes, "
      62             :       "which may be slower.");
      63             : 
      64         148 :   params.addParam<std::vector<Point>>(
      65             :       "positions", "Sub-app positions. Each set of 3 values represents a Point.");
      66         148 :   params.addParam<FileName>(
      67             :       "positions_file",
      68             :       "Name of file containing sub-app positions. Each set of 3 values represents a Point.");
      69          74 :   MultiAppTransfer::addSkipCoordCollapsingParam(params);
      70          74 :   return params;
      71           0 : }
      72             : 
      73          74 : CoupledHeatTransferAction::CoupledHeatTransferAction(const InputParameters & params)
      74             :   : Action(params),
      75             : 
      76          74 :     _boundary(getParam<std::vector<BoundaryName>>("boundary")),
      77             : 
      78          74 :     _T_solid_var_name(getParam<VariableName>("T")),
      79          74 :     _T_wall_var_name(getParam<VariableName>("T_wall")),
      80         148 :     _T_fluid_var_names(getParam<std::vector<VariableName>>("T_fluid")),
      81         222 :     _htc_var_names(getParam<std::vector<VariableName>>("htc")),
      82             : 
      83          74 :     _n_phases(_T_fluid_var_names.size()),
      84             : 
      85          74 :     _T_wall_user_object_name(name() + "_T_avg_uo"),
      86         148 :     _T_fluid_user_object_names(getParam<std::vector<UserObjectName>>("T_fluid_user_objects")),
      87         222 :     _htc_user_object_names(getParam<std::vector<UserObjectName>>("htc_user_objects")),
      88             : 
      89         222 :     _multi_app_name(getParam<std::string>("multi_app"))
      90             : {
      91          74 :   if (_htc_var_names.size() != _n_phases || _T_fluid_user_object_names.size() != _n_phases ||
      92             :       _htc_user_object_names.size() != _n_phases)
      93           0 :     mooseError("The parameters 'T_fluid', 'htc', 'T_fluid_user_objects', and 'htc_user_objects' "
      94             :                "must have the same numbers of elements.");
      95             : 
      96          74 :   if (_n_phases == 1)
      97             :   {
      98         200 :     if (isParamValid("kappa") || isParamValid("kappa_user_objects"))
      99           0 :       mooseError("If there is only one phase (e.g., only one element in 'T_fluid'), then the "
     100             :                  "parameters 'kappa' and 'kappa_user_objects' must not be provided.");
     101             :   }
     102             :   else
     103             :   {
     104          96 :     if (!isParamValid("kappa") || !isParamValid("kappa_user_objects"))
     105           0 :       mooseError("If there is more than one phase (e.g., more than one element in 'T_fluid'), then "
     106             :                  "the parameters 'kappa' and 'kappa_user_objects' must be provided.");
     107             :     else
     108             :     {
     109          48 :       _kappa_var_names = getParam<std::vector<VariableName>>("kappa");
     110          72 :       _kappa_user_object_names = getParam<std::vector<UserObjectName>>("kappa_user_objects");
     111          24 :       if (_kappa_var_names.size() != _n_phases || _kappa_user_object_names.size() != _n_phases)
     112           0 :         mooseError("The parameters 'kappa' and 'kappa_user_objects' must have the same number of "
     113             :                    "elements as 'T_fluid'.");
     114             :     }
     115             :   }
     116             : 
     117          74 :     const auto & orientation = getParam<RealVectorValue>("orientation");
     118          74 :     if (!DiscreteLineSegmentInterface::getAlignmentAxis(orientation).isValid())
     119           2 :       mooseError("The direction given by the parameter 'orientation' must be aligned with the x, "
     120             :                  "y, or z axis.");
     121          72 : }
     122             : 
     123             : void
     124          72 : CoupledHeatTransferAction::act()
     125             : {
     126          72 :   if (_current_task == "add_bc")
     127          24 :     addBCs();
     128          48 :   else if (_current_task == "add_user_object")
     129          24 :     addUserObjects();
     130          24 :   else if (_current_task == "add_transfer")
     131          24 :     addTransfers();
     132          72 : }
     133             : 
     134             : void
     135          24 : CoupledHeatTransferAction::addBCs()
     136             : {
     137          56 :   for (unsigned int k = 0; k < _n_phases; k++)
     138             :   {
     139          32 :     const std::string class_name = "CoupledConvectiveHeatFluxBC";
     140          32 :     InputParameters params = _factory.getValidParams(class_name);
     141          64 :     params.set<NonlinearVariableName>("variable") = _T_solid_var_name;
     142          32 :     params.set<std::vector<BoundaryName>>("boundary") = {_boundary};
     143          96 :     params.set<std::vector<VariableName>>("T_infinity") = {_T_fluid_var_names[k]};
     144          96 :     params.set<std::vector<VariableName>>("htc") = {_htc_var_names[k]};
     145          32 :     if (_n_phases > 1)
     146          48 :       params.set<std::vector<VariableName>>("scale_factor") = {_kappa_var_names[k]};
     147          64 :     _problem->addBoundaryCondition(class_name, name() + "_bc" + std::to_string(k), params);
     148          32 :   }
     149          24 : }
     150             : 
     151             : void
     152          24 : CoupledHeatTransferAction::addUserObjects()
     153             : {
     154             :   // Solid temperature spatial user object
     155             :   {
     156          24 :     const std::string class_name = "NearestPointLayeredSideAverage";
     157          24 :     InputParameters params = _factory.getValidParams(class_name);
     158          72 :     params.set<std::vector<VariableName>>("variable") = {_T_solid_var_name};
     159          24 :     params.set<std::vector<BoundaryName>>("boundary") = {_boundary};
     160             : 
     161             :     // set sub-app positions
     162          48 :     if (isParamValid("positions"))
     163          24 :       params.set<std::vector<Point>>("points") = getParam<std::vector<Point>>("positions");
     164          32 :     else if (isParamValid("positions_file"))
     165           0 :       params.set<FileName>("points_file") = getParam<FileName>("positions_file");
     166             :     else
     167          32 :       params.set<std::vector<Point>>("points") = {Point(0, 0, 0)};
     168             : 
     169          24 :     const auto & position = getParam<Point>("position");
     170          24 :     const auto & orientation = getParam<RealVectorValue>("orientation");
     171          24 :     const auto & rotation = getParam<Real>("rotation");
     172          24 :     const auto & lengths = getParam<std::vector<Real>>("length");
     173          24 :     const auto & n_elems = getParam<std::vector<unsigned int>>("n_elems");
     174             : 
     175          24 :     params.set<MooseEnum>("direction") =
     176          72 :         DiscreteLineSegmentInterface::getAlignmentAxis(orientation);
     177          24 :     params.set<std::vector<Real>>("bounds") =
     178          48 :         DiscreteLineSegmentInterface::getElementBoundaryCoordinates(
     179             :             position, orientation, rotation, lengths, n_elems);
     180             : 
     181          24 :     _problem->addUserObject(class_name, _T_wall_user_object_name, params);
     182          24 :   }
     183          24 : }
     184             : 
     185             : void
     186          24 : CoupledHeatTransferAction::addTransfers()
     187             : {
     188             :   // Transfers to the flow channel application
     189             : 
     190          48 :   const bool skip_coordinate_collapsing = getParam<bool>("skip_coordinate_collapsing");
     191             : 
     192          48 :   const bool use_bounding_boxes = isParamValid("fixed_bounding_box_size");
     193             :   std::vector<Real> fixed_bounding_box_size;
     194          24 :   if (use_bounding_boxes)
     195           0 :     fixed_bounding_box_size = getParam<std::vector<Real>>("fixed_bounding_box_size");
     196             : 
     197             :   {
     198          24 :     const std::string class_name = "MultiAppGeneralFieldUserObjectTransfer";
     199          24 :     InputParameters params = _factory.getValidParams(class_name);
     200          24 :     params.set<MultiAppName>("to_multi_app") = _multi_app_name;
     201          24 :     params.set<UserObjectName>("source_user_object") = {_T_wall_user_object_name};
     202          72 :     params.set<std::vector<AuxVariableName>>("variable") = {_T_wall_var_name};
     203          24 :     params.set<bool>("skip_coordinate_collapsing") = skip_coordinate_collapsing;
     204          24 :     params.set<bool>("error_on_miss") = true;
     205          24 :     if (use_bounding_boxes)
     206           0 :       params.set<std::vector<Real>>("fixed_bounding_box_size") = fixed_bounding_box_size;
     207             :     else
     208             :     {
     209          24 :       params.set<bool>("use_bounding_boxes") = false;
     210          24 :       params.set<bool>("greedy_search") = true;
     211             :     }
     212          24 :     _problem->addTransfer(class_name, name() + "_T_solid_transfer", params);
     213          24 :   }
     214             : 
     215             :   // Transfers from the flow channel application. Note that
     216             :   // Note that MultiAppGeneralFieldNearestLocationTransfer should be more optimal
     217             :   // choice in parallel calculations, while MultiAppGeneralFieldUserObjectTransfer should
     218             :   // be more optimal in serial calculations. If these transfers prove to be a significant time
     219             :   // burden, we may want to provide an option to switch these transfer classes.
     220          56 :   for (unsigned int k = 0; k < _n_phases; k++)
     221             :   {
     222             :     {
     223          32 :       const std::string class_name = "MultiAppGeneralFieldUserObjectTransfer";
     224          32 :       InputParameters params = _factory.getValidParams(class_name);
     225          32 :       params.set<MultiAppName>("from_multi_app") = _multi_app_name;
     226          64 :       params.set<UserObjectName>("source_user_object") = _T_fluid_user_object_names[k];
     227          96 :       params.set<std::vector<AuxVariableName>>("variable") = {_T_fluid_var_names[k]};
     228          32 :       params.set<bool>("skip_coordinate_collapsing") = skip_coordinate_collapsing;
     229          32 :       params.set<bool>("error_on_miss") = true;
     230          32 :       if (use_bounding_boxes)
     231           0 :         params.set<std::vector<Real>>("fixed_bounding_box_size") = fixed_bounding_box_size;
     232             :       else
     233             :       {
     234          32 :         params.set<bool>("use_bounding_boxes") = false;
     235          32 :         params.set<bool>("greedy_search") = true;
     236             :       }
     237          64 :       _problem->addTransfer(class_name, name() + "_T_fluid_transfer" + std::to_string(k), params);
     238          32 :     }
     239             :     {
     240          32 :       const std::string class_name = "MultiAppGeneralFieldUserObjectTransfer";
     241          32 :       InputParameters params = _factory.getValidParams(class_name);
     242          64 :       params.set<MultiAppName>("from_multi_app") = _multi_app_name;
     243          64 :       params.set<UserObjectName>("source_user_object") = _htc_user_object_names[k];
     244          96 :       params.set<std::vector<AuxVariableName>>("variable") = {_htc_var_names[k]};
     245          32 :       params.set<bool>("skip_coordinate_collapsing") = skip_coordinate_collapsing;
     246          32 :       params.set<bool>("error_on_miss") = true;
     247          32 :       if (use_bounding_boxes)
     248           0 :         params.set<std::vector<Real>>("fixed_bounding_box_size") = fixed_bounding_box_size;
     249             :       else
     250             :       {
     251          32 :         params.set<bool>("use_bounding_boxes") = false;
     252          32 :         params.set<bool>("greedy_search") = true;
     253             :       }
     254          64 :       _problem->addTransfer(class_name, name() + "_htc_transfer" + std::to_string(k), params);
     255          32 :     }
     256          32 :     if (_n_phases > 1)
     257             :     {
     258          16 :       const std::string class_name = "MultiAppGeneralFieldUserObjectTransfer";
     259          16 :       InputParameters params = _factory.getValidParams(class_name);
     260          32 :       params.set<MultiAppName>("from_multi_app") = _multi_app_name;
     261          32 :       params.set<UserObjectName>("source_user_object") = _kappa_user_object_names[k];
     262          48 :       params.set<std::vector<AuxVariableName>>("variable") = {_kappa_var_names[k]};
     263          16 :       params.set<bool>("skip_coordinate_collapsing") = skip_coordinate_collapsing;
     264          16 :       params.set<bool>("error_on_miss") = true;
     265          16 :       if (use_bounding_boxes)
     266           0 :         params.set<std::vector<Real>>("fixed_bounding_box_size") = fixed_bounding_box_size;
     267             :       else
     268             :       {
     269          16 :         params.set<bool>("use_bounding_boxes") = false;
     270          16 :         params.set<bool>("greedy_search") = true;
     271             :       }
     272          32 :       _problem->addTransfer(class_name, name() + "_kappa_transfer" + std::to_string(k), params);
     273          16 :     }
     274             :   }
     275         128 : }

Generated by: LCOV version 1.14