LCOV - code coverage report
Current view: top level - src/components - FlowChannelBase.C (source / functions) Hit Total Coverage
Test: idaholab/moose thermal_hydraulics: #30301 (3b550b) with base 2ad78d Lines: 180 190 94.7 %
Date: 2025-07-30 13:02:48 Functions: 18 21 85.7 %
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 "FlowChannelBase.h"
      11             : #include "HeatTransferBase.h"
      12             : #include "ClosuresBase.h"
      13             : #include "ThermalHydraulicsApp.h"
      14             : #include "THMMesh.h"
      15             : 
      16             : #include "libmesh/edge_edge2.h"
      17             : #include "libmesh/edge_edge3.h"
      18             : 
      19             : const std::map<std::string, FlowChannelBase::EConvHeatTransGeom>
      20             :     FlowChannelBase::_heat_transfer_geom_to_enum{
      21             :         {"PIPE", PIPE}, {"ROD_BUNDLE", ROD_BUNDLE}, {"HEX_ROD_BUNDLE", HEX_ROD_BUNDLE}};
      22             : 
      23             : const std::map<std::string, FlowChannelBase::EPipeType> FlowChannelBase::_pipe_type_to_enum{
      24             :     {"STRAIGHT", STRAIGHT}, {"CURVED", CURVED}, {"DOWNCOMER", DOWNCOMER}};
      25             : 
      26             : const std::map<std::string, FlowChannelBase::EPipeLocation> FlowChannelBase::_pipe_location_to_enum{
      27             :     {"INTERIOR", INTERIOR}, {"EDGE", EDGE}, {"CORNER", CORNER}};
      28             : 
      29             : MooseEnum
      30        8380 : FlowChannelBase::getConvHeatTransGeometry(const std::string & name)
      31             : {
      32        8380 :   return THM::getMooseEnum<EConvHeatTransGeom>(name, _heat_transfer_geom_to_enum);
      33             : }
      34             : 
      35             : MooseEnum
      36           0 : FlowChannelBase::getPipeType(const std::string & name)
      37             : {
      38           0 :   return THM::getMooseEnum<EPipeType>(name, _pipe_type_to_enum);
      39             : }
      40             : 
      41             : MooseEnum
      42        8380 : FlowChannelBase::getPipeLocation(const std::string & name)
      43             : {
      44        8380 :   return THM::getMooseEnum<EPipeLocation>(name, _pipe_location_to_enum);
      45             : }
      46             : 
      47             : template <>
      48             : FlowChannelBase::EConvHeatTransGeom
      49        4189 : THM::stringToEnum(const std::string & s)
      50             : {
      51        4189 :   return stringToEnum<FlowChannelBase::EConvHeatTransGeom>(
      52        4189 :       s, FlowChannelBase::_heat_transfer_geom_to_enum);
      53             : }
      54             : 
      55             : template <>
      56             : FlowChannelBase::EPipeType
      57           0 : THM::stringToEnum(const std::string & s)
      58             : {
      59           0 :   return stringToEnum<FlowChannelBase::EPipeType>(s, FlowChannelBase::_pipe_type_to_enum);
      60             : }
      61             : 
      62             : template <>
      63             : FlowChannelBase::EPipeLocation
      64        4189 : THM::stringToEnum(const std::string & s)
      65             : {
      66        4189 :   return stringToEnum<FlowChannelBase::EPipeLocation>(s, FlowChannelBase::_pipe_location_to_enum);
      67             : }
      68             : 
      69             : InputParameters
      70        8380 : FlowChannelBase::validParams()
      71             : {
      72        8380 :   InputParameters params = Component1D::validParams();
      73        8380 :   params += GravityInterface::validParams();
      74             : 
      75       16760 :   params.addRequiredParam<UserObjectName>("fp", "Fluid properties user object");
      76       16760 :   params.addRequiredParam<FunctionName>(
      77             :       "A", "Area of the flow channel, can be a constant or a function");
      78       16760 :   params.addParam<Real>("roughness", 0.0, "Roughness [m]");
      79       16760 :   params.addParam<FunctionName>("f", "Wall friction factor [-]");
      80       16760 :   params.addParam<MooseEnum>("heat_transfer_geom",
      81       25140 :                              FlowChannelBase::getConvHeatTransGeometry("PIPE"),
      82             :                              "Convective heat transfer geometry");
      83       16760 :   params.addParam<MooseEnum>("pipe_location",
      84       25140 :                              FlowChannelBase::getPipeLocation("INTERIOR"),
      85             :                              "Pipe location within the bundle");
      86       16760 :   params.addParam<Real>("PoD", 1, "Pitch-to-diameter ratio for parallel bundle heat transfer [-]");
      87       16760 :   params.addParam<bool>(
      88             :       "pipe_pars_transferred",
      89       16760 :       false,
      90             :       "Set to true if Dh, P_hf and A are going to be transferred in from an external source");
      91       16760 :   params.addParam<std::vector<std::string>>(
      92             :       "closures",
      93             :       {},
      94             :       "Closures object(s). This is optional since closure relations can be supplied directly by "
      95             :       "Materials as well.");
      96       16760 :   params.addParam<bool>("name_multiple_ht_by_index",
      97       16760 :                         true,
      98             :                         "If true, when there are multiple heat transfer components connected to "
      99             :                         "this flow channel, use their index for naming related quantities; "
     100             :                         "otherwise, use the name of the heat transfer component.");
     101             : 
     102       16760 :   params.setDocString(
     103             :       "orientation",
     104             :       "Direction of flow channel from start position to end position (no need to normalize). For "
     105             :       "curved flow channels, it is the (tangent) direction at the start position.");
     106             : 
     107       16760 :   params.addPrivateParam<std::string>("component_type", "pipe");
     108       16760 :   params.declareControllable("A f");
     109             : 
     110        8380 :   return params;
     111           0 : }
     112             : 
     113        4189 : FlowChannelBase::FlowChannelBase(const InputParameters & params)
     114             :   : Component1D(params),
     115             :     GravityInterface(params),
     116             : 
     117             :     _flow_model(nullptr),
     118        8378 :     _fp_name(getParam<UserObjectName>("fp")),
     119        4189 :     _gravity_angle(MooseUtils::absoluteFuzzyEqual(_gravity_magnitude, 0.0)
     120        4189 :                        ? 0.0
     121        1089 :                        : std::acos(_dir * _gravity_vector / (_dir.norm() * _gravity_magnitude)) *
     122             :                              180 / M_PI),
     123        8378 :     _pipe_pars_transferred(getParam<bool>("pipe_pars_transferred")),
     124        8378 :     _roughness(getParam<Real>("roughness")),
     125        4189 :     _HT_geometry(getEnumParam<EConvHeatTransGeom>("heat_transfer_geom")),
     126        4189 :     _pipe_location(getEnumParam<EPipeLocation>("pipe_location")),
     127        8378 :     _PoD(getParam<Real>("PoD")),
     128        8378 :     _has_PoD(isParamValid("PoD")),
     129        4189 :     _temperature_mode(false),
     130        8378 :     _n_heat_transfer_connections(0)
     131             : {
     132        4189 : }
     133             : 
     134             : std::shared_ptr<const FlowModel>
     135        6447 : FlowChannelBase::getFlowModel() const
     136             : {
     137        6447 :   checkSetupStatus(INITIALIZED_PRIMARY);
     138             : 
     139        6445 :   return _flow_model;
     140             : }
     141             : 
     142             : const FunctionName &
     143        4966 : FlowChannelBase::getAreaFunctionName() const
     144             : {
     145        4966 :   checkSetupStatus(INITIALIZED_PRIMARY);
     146             : 
     147        4966 :   return _area_function;
     148             : }
     149             : 
     150             : FunctionName
     151        4160 : FlowChannelBase::createAreaFunctionAndGetName()
     152             : {
     153             :   // Area function has already been created; just need to return its name
     154        8320 :   return getParam<FunctionName>("A");
     155             : }
     156             : 
     157             : void
     158        4160 : FlowChannelBase::init()
     159             : {
     160        4160 :   Component1D::init();
     161             : 
     162        4160 :   _area_function = createAreaFunctionAndGetName();
     163             : 
     164        8320 :   _flow_model = buildFlowModel();
     165        4160 :   if (_flow_model)
     166             :   {
     167        4160 :     _flow_model->init();
     168             : 
     169        8320 :     const auto & closures_names = getParam<std::vector<std::string>>("closures");
     170        8339 :     for (const auto & closures_name : closures_names)
     171        8358 :       _closures_objects.push_back(getTHMProblem().getClosures(closures_name));
     172             :   }
     173        4160 : }
     174             : 
     175             : void
     176        4160 : FlowChannelBase::initSecondary()
     177             : {
     178             :   Component1D::initSecondary();
     179             : 
     180             :   // Determine heat transfer mode based on connected heat transfer components;
     181             :   // if at least one heat transfer component of temperature component is
     182             :   // connected, then it's temperature mode. Otherwise, it's heat flux mode, even
     183             :   // if no heat transfer components at all were provided - in that case, a zero
     184             :   // heat flux is added.
     185        5209 :   for (unsigned int i = 0; i < _heat_transfer_names.size(); i++)
     186             :   {
     187             :     const HeatTransferBase & heat_transfer =
     188             :         getComponentByName<HeatTransferBase>(_heat_transfer_names[i]);
     189        1049 :     if (heat_transfer.isTemperatureType())
     190         939 :       _temperature_mode = true;
     191             :   }
     192        4160 : }
     193             : 
     194             : void
     195        4050 : FlowChannelBase::check() const
     196             : {
     197        4050 :   Component1D::check();
     198             : 
     199        8119 :   for (const auto & closures : _closures_objects)
     200        4069 :     closures->checkFlowChannel(*this);
     201             : 
     202             :   // check types of heat transfer for all sources; must be all of same type
     203        4050 :   if (_temperature_mode)
     204        1785 :     for (unsigned int i = 0; i < _heat_transfer_names.size(); i++)
     205             :     {
     206             :       const HeatTransferBase & heat_transfer =
     207             :           getComponentByName<HeatTransferBase>(_heat_transfer_names[i]);
     208         916 :       if (!heat_transfer.isTemperatureType())
     209           2 :         logError("Heat sources for a flow channel must be all of temperature type or all of heat "
     210             :                  "flux type");
     211             :     }
     212        4050 : }
     213             : 
     214             : void
     215        4048 : FlowChannelBase::addVariables()
     216             : {
     217             :   // This should be called after initSecondary() because it relies on the names
     218             :   // generated in initSecondary() of heat transfer components
     219        4048 :   getHeatTransferVariableNames();
     220             : 
     221        4048 :   _flow_model->addVariables();
     222             : 
     223             :   // total heat flux perimeter
     224        4048 :   if (_n_heat_transfer_connections > 1 && !_app.isRestarting())
     225             :   {
     226          81 :     const std::string class_name = "SumIC";
     227          81 :     InputParameters params = _factory.getValidParams(class_name);
     228         162 :     params.set<VariableName>("variable") = FlowModel::HEAT_FLUX_PERIMETER;
     229          81 :     params.set<std::vector<SubdomainName>>("block") = getSubdomainNames();
     230          81 :     params.set<std::vector<VariableName>>("values") = _P_hf_names;
     231         162 :     getTHMProblem().addSimInitialCondition(class_name, genName(name(), "P_hf_ic"), params);
     232          81 :   }
     233             : 
     234        4048 :   _flow_model->addInitialConditions();
     235        4048 : }
     236             : 
     237             : void
     238        4048 : FlowChannelBase::addCommonObjects()
     239             : {
     240        4048 :   ExecFlagEnum ts_execute_on(MooseUtils::getDefaultExecFlagEnum());
     241       16192 :   ts_execute_on = {EXEC_TIMESTEP_BEGIN, EXEC_INITIAL};
     242             : 
     243             :   {
     244        4048 :     std::string class_name = "DirectionMaterial";
     245        4048 :     InputParameters params = _factory.getValidParams(class_name);
     246        4048 :     params.set<std::vector<SubdomainName>>("block") = getSubdomainNames();
     247        8096 :     getTHMProblem().addMaterial(class_name, genName(name(), "dir_mat"), params);
     248        4048 :   }
     249             : 
     250        4048 :   if (!_pipe_pars_transferred)
     251             :   {
     252             :     // Area
     253             :     {
     254        4048 :       std::string class_name = "FunctionAux";
     255        4048 :       InputParameters params = _factory.getValidParams(class_name);
     256        8096 :       params.set<AuxVariableName>("variable") = FlowModel::AREA_LINEAR;
     257        4048 :       params.set<std::vector<SubdomainName>>("block") = getSubdomainNames();
     258        4048 :       params.set<FunctionName>("function") = _area_function;
     259        4048 :       params.set<ExecFlagEnum>("execute_on") = ts_execute_on;
     260        8096 :       const std::string aux_kernel_name = genName(name(), "area_linear_aux");
     261        4048 :       getTHMProblem().addAuxKernel(class_name, aux_kernel_name, params);
     262        8096 :       makeFunctionControllableIfConstant(_area_function, "Area");
     263        4048 :     }
     264             :     {
     265        4048 :       const std::string class_name = "ProjectionAux";
     266        4048 :       InputParameters params = _factory.getValidParams(class_name);
     267        8096 :       params.set<AuxVariableName>("variable") = FlowModel::AREA;
     268        8096 :       params.set<std::vector<SubdomainName>>("block") = getSubdomainNames();
     269       12144 :       params.set<std::vector<VariableName>>("v") = {FlowModel::AREA_LINEAR};
     270        4048 :       params.set<ExecFlagEnum>("execute_on") = ts_execute_on;
     271        8096 :       const std::string aux_kernel_name = genName(name(), "area_aux");
     272        4048 :       getTHMProblem().addAuxKernel(class_name, aux_kernel_name, params);
     273        8096 :       makeFunctionControllableIfConstant(_area_function, "Area");
     274        4048 :     }
     275             :   }
     276        8096 : }
     277             : 
     278             : void
     279        4048 : FlowChannelBase::addMooseObjects()
     280             : {
     281        4048 :   addCommonObjects();
     282             : 
     283        4048 :   ExecFlagEnum execute_on_initial_linear(MooseUtils::getDefaultExecFlagEnum());
     284       16192 :   execute_on_initial_linear = {EXEC_INITIAL, EXEC_LINEAR};
     285             : 
     286             :   // total heat flux perimeter aux kernel
     287        4048 :   if (_n_heat_transfer_connections > 1)
     288             :   {
     289          81 :     const std::string class_name = "SumAux";
     290          81 :     InputParameters params = _factory.getValidParams(class_name);
     291         162 :     params.set<AuxVariableName>("variable") = FlowModel::HEAT_FLUX_PERIMETER;
     292          81 :     params.set<std::vector<SubdomainName>>("block") = getSubdomainNames();
     293          81 :     params.set<std::vector<VariableName>>("values") = _P_hf_names;
     294          81 :     params.set<ExecFlagEnum>("execute_on") = execute_on_initial_linear;
     295         162 :     getTHMProblem().addAuxKernel(class_name, genName(name(), "P_hf_auxkernel"), params);
     296          81 :   }
     297             : 
     298             :   // weighted average wall heat flux aux kernel
     299        4048 :   if (!_temperature_mode)
     300             :   {
     301        3190 :     if (_n_heat_transfer_connections > 1)
     302             :     {
     303          36 :       const std::string class_name = "ADWeightedAverageMaterial";
     304          36 :       InputParameters params = _factory.getValidParams(class_name);
     305          72 :       params.set<MaterialPropertyName>("prop_name") = FlowModel::HEAT_FLUX_WALL;
     306          36 :       params.set<std::vector<SubdomainName>>("block") = getSubdomainNames();
     307          36 :       params.set<std::vector<MaterialPropertyName>>("values") = _q_wall_names;
     308          36 :       params.set<std::vector<VariableName>>("weights") = _P_hf_names;
     309          72 :       getTHMProblem().addMaterial(
     310          36 :           class_name, genName(name(), FlowModel::HEAT_FLUX_WALL, "w_avg_mat"), params);
     311          36 :     }
     312        3154 :     else if (_n_heat_transfer_connections == 0)
     313             :     {
     314        3118 :       const std::string class_name = "ADConstantMaterial";
     315        3118 :       InputParameters params = _factory.getValidParams(class_name);
     316        3118 :       params.set<std::string>("property_name") = FlowModel::HEAT_FLUX_WALL;
     317        3118 :       params.set<std::vector<SubdomainName>>("block") = getSubdomainNames();
     318        3118 :       params.set<Real>("value") = 0;
     319        6236 :       getTHMProblem().addMaterial(
     320        3118 :           class_name, genName(name(), FlowModel::HEAT_FLUX_WALL, "zero_mat"), params);
     321        3118 :     }
     322             :   }
     323             : 
     324        4048 :   _flow_model->addMooseObjects();
     325             : 
     326        8115 :   for (const auto & closures : _closures_objects)
     327        4067 :     closures->addMooseObjectsFlowChannel(*this);
     328        8096 : }
     329             : 
     330             : void
     331        1049 : FlowChannelBase::addHeatTransferName(const std::string & name) const
     332             : {
     333        1049 :   _heat_transfer_names.push_back(name);
     334        1049 :   _n_heat_transfer_connections++;
     335        1049 : }
     336             : 
     337             : void
     338        4048 : FlowChannelBase::getHeatTransferVariableNames()
     339             : {
     340        5059 :   for (unsigned int i = 0; i < _n_heat_transfer_connections; i++)
     341             :   {
     342             :     const HeatTransferBase & heat_transfer =
     343        1011 :         getComponentByName<HeatTransferBase>(_heat_transfer_names[i]);
     344             : 
     345        1011 :     _P_hf_names.push_back(heat_transfer.getHeatedPerimeterName());
     346        1011 :     _T_wall_names.push_back(heat_transfer.getWallTemperatureName());
     347        1011 :     _T_wall_mat_names.push_back(heat_transfer.getWallTemperatureMatName());
     348        1011 :     _q_wall_names.push_back(heat_transfer.getWallHeatFluxName());
     349             :   }
     350        4048 : }
     351             : 
     352             : std::string
     353        2015 : FlowChannelBase::getHeatTransferNamesSuffix(const std::string & ht_name) const
     354             : {
     355        2015 :   checkSetupStatus(INITIALIZED_PRIMARY);
     356             : 
     357             :   // if there is more than one connected heat transfer component, then number them
     358        2015 :   if (_n_heat_transfer_connections > 1)
     359             :   {
     360             :     // determine index of heat transfer name based on when it was added
     361         332 :     auto it = std::find(_heat_transfer_names.begin(), _heat_transfer_names.end(), ht_name);
     362         332 :     if (it != _heat_transfer_names.end())
     363             :     {
     364         332 :       const unsigned int index = std::distance(_heat_transfer_names.begin(), it);
     365             : 
     366         332 :       std::string suffix = ":";
     367         664 :       if (getParam<bool>("name_multiple_ht_by_index"))
     368         520 :         suffix += std::to_string(index + 1);
     369             :       else
     370          72 :         suffix += _heat_transfer_names[index];
     371             : 
     372         332 :       return suffix;
     373             :     }
     374             :     else
     375           0 :       mooseError(
     376           0 :           "Heat transfer component '", ht_name, "' was not added to flow channel '", name(), "'");
     377             :   }
     378             :   // else, don't add a suffix; there is no need
     379             :   else
     380        1683 :     return "";
     381             : }
     382             : 
     383             : std::vector<std::string>
     384           0 : FlowChannelBase::getHeatTransferNames() const
     385             : {
     386           0 :   checkSetupStatus(INITIALIZED_PRIMARY);
     387             : 
     388           0 :   return _heat_transfer_names;
     389             : }

Generated by: LCOV version 1.14