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

Generated by: LCOV version 1.14