LCOV - code coverage report
Current view: top level - src/components - FlowChannelBase.C (source / functions) Hit Total Coverage
Test: idaholab/moose thermal_hydraulics: #32971 (54bef8) with base c6cf66 Lines: 187 196 95.4 %
Date: 2026-05-29 20:41:18 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        4332 : FlowChannelBase::getConvHeatTransGeometry(const std::string & name)
      31             : {
      32        4332 :   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        4332 : FlowChannelBase::getPipeLocation(const std::string & name)
      43             : {
      44        4332 :   return THM::getMooseEnum<EPipeLocation>(name, _pipe_location_to_enum);
      45             : }
      46             : 
      47             : template <>
      48             : FlowChannelBase::EConvHeatTransGeom
      49        2165 : THM::stringToEnum(const std::string & s)
      50             : {
      51        2165 :   return stringToEnum<FlowChannelBase::EConvHeatTransGeom>(
      52        2165 :       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        2165 : THM::stringToEnum(const std::string & s)
      65             : {
      66        2165 :   return stringToEnum<FlowChannelBase::EPipeLocation>(s, FlowChannelBase::_pipe_location_to_enum);
      67             : }
      68             : 
      69             : InputParameters
      70        4332 : FlowChannelBase::validParams()
      71             : {
      72        4332 :   InputParameters params = Component1D::validParams();
      73        4332 :   params += GravityInterface::validParams();
      74             : 
      75        8664 :   params.addRequiredParam<UserObjectName>("fp", "Fluid properties user object");
      76        8664 :   params.addRequiredParam<FunctionName>(
      77             :       "A", "Area of the flow channel, can be a constant or a function");
      78        8664 :   params.addParam<Real>("roughness", 0.0, "Roughness [m]");
      79        8664 :   params.addParam<FunctionName>("f", "Wall friction factor [-]");
      80        8664 :   params.addParam<MooseEnum>("heat_transfer_geom",
      81       12996 :                              FlowChannelBase::getConvHeatTransGeometry("PIPE"),
      82             :                              "Convective heat transfer geometry");
      83        8664 :   params.addParam<MooseEnum>("pipe_location",
      84       12996 :                              FlowChannelBase::getPipeLocation("INTERIOR"),
      85             :                              "Pipe location within the bundle");
      86        8664 :   params.addParam<Real>("PoD", 1, "Pitch-to-diameter ratio for parallel bundle heat transfer [-]");
      87        8664 :   params.addParam<bool>(
      88             :       "pipe_pars_transferred",
      89        8664 :       false,
      90             :       "Set to true if Dh, P_hf and A are going to be transferred in from an external source");
      91        8664 :   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        8664 :   params.addParam<bool>("name_multiple_ht_by_index",
      97        8664 :                         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        8664 :   params.addParam<std::vector<VariableName>>(
     102             :       "vpp_vars", {}, "Variables to add in an ElementValueSampler");
     103             : 
     104        8664 :   params.setDocString(
     105             :       "orientation",
     106             :       "Direction of flow channel from start position to end position (no need to normalize). For "
     107             :       "curved flow channels, it is the (tangent) direction at the start position.");
     108             : 
     109        8664 :   params.addPrivateParam<std::string>("component_type", "pipe");
     110             : 
     111        4332 :   return params;
     112           0 : }
     113             : 
     114        2165 : FlowChannelBase::FlowChannelBase(const InputParameters & params)
     115             :   : Component1D(params),
     116             :     GravityInterface(params),
     117             : 
     118             :     _flow_model(nullptr),
     119        4330 :     _fp_name(getParam<UserObjectName>("fp")),
     120        2165 :     _gravity_angle(MooseUtils::absoluteFuzzyEqual(_gravity_magnitude, 0.0)
     121        2165 :                        ? 0.0
     122         623 :                        : std::acos(_dir * _gravity_vector / (_dir.norm() * _gravity_magnitude)) *
     123             :                              180 / M_PI),
     124        4330 :     _pipe_pars_transferred(getParam<bool>("pipe_pars_transferred")),
     125        4330 :     _roughness(getParam<Real>("roughness")),
     126        2165 :     _HT_geometry(getEnumParam<EConvHeatTransGeom>("heat_transfer_geom")),
     127        2165 :     _pipe_location(getEnumParam<EPipeLocation>("pipe_location")),
     128        4330 :     _PoD(getParam<Real>("PoD")),
     129        4330 :     _has_PoD(isParamValid("PoD")),
     130        2165 :     _temperature_mode(false),
     131        2165 :     _n_heat_transfer_connections(0)
     132             : {
     133        2165 : }
     134             : 
     135             : std::shared_ptr<const FlowModel>
     136        3386 : FlowChannelBase::getFlowModel() const
     137             : {
     138        3386 :   checkSetupStatus(INITIALIZED_PRIMARY);
     139             : 
     140        3384 :   return _flow_model;
     141             : }
     142             : 
     143             : const FunctionName &
     144        2480 : FlowChannelBase::getAreaFunctionName() const
     145             : {
     146        2480 :   checkSetupStatus(INITIALIZED_PRIMARY);
     147             : 
     148        2480 :   return _area_function;
     149             : }
     150             : 
     151             : FunctionName
     152        2142 : FlowChannelBase::createAreaFunctionAndGetName()
     153             : {
     154             :   // Area function has already been created; just need to return its name
     155        4284 :   return getParam<FunctionName>("A");
     156             : }
     157             : 
     158             : void
     159        2142 : FlowChannelBase::init()
     160             : {
     161             :   Component1D::init();
     162             : 
     163        2142 :   _area_function = createAreaFunctionAndGetName();
     164             : 
     165        4284 :   _flow_model = buildFlowModel();
     166        2142 :   if (_flow_model)
     167             :   {
     168        2142 :     _flow_model->init();
     169             : 
     170        4284 :     const auto & closures_names = getParam<std::vector<std::string>>("closures");
     171        4293 :     for (const auto & closures_name : closures_names)
     172        4302 :       _closures_objects.push_back(getTHMProblem().getClosures(closures_name));
     173             :   }
     174        2142 : }
     175             : 
     176             : void
     177        2142 : FlowChannelBase::initSecondary()
     178             : {
     179             :   Component1D::initSecondary();
     180             : 
     181             :   // Determine heat transfer mode based on connected heat transfer components;
     182             :   // if at least one heat transfer component of temperature component is
     183             :   // connected, then it's temperature mode. Otherwise, it's heat flux mode, even
     184             :   // if no heat transfer components at all were provided - in that case, a zero
     185             :   // heat flux is added.
     186        2681 :   for (unsigned int i = 0; i < _heat_transfer_names.size(); i++)
     187             :   {
     188             :     const HeatTransferBase & heat_transfer =
     189             :         getComponentByName<HeatTransferBase>(_heat_transfer_names[i]);
     190         539 :     if (heat_transfer.isTemperatureType())
     191         471 :       _temperature_mode = true;
     192             :   }
     193        2142 : }
     194             : 
     195             : void
     196        2088 : FlowChannelBase::check() const
     197             : {
     198        2088 :   Component1D::check();
     199             : 
     200        4185 :   for (const auto & closures : _closures_objects)
     201        2097 :     closures->checkFlowChannel(*this);
     202             : 
     203             :   // check types of heat transfer for all sources; must be all of same type
     204        2088 :   if (_temperature_mode)
     205         891 :     for (unsigned int i = 0; i < _heat_transfer_names.size(); i++)
     206             :     {
     207             :       const HeatTransferBase & heat_transfer =
     208             :           getComponentByName<HeatTransferBase>(_heat_transfer_names[i]);
     209         458 :       if (!heat_transfer.isTemperatureType())
     210           2 :         logError("Heat sources for a flow channel must be all of temperature type or all of heat "
     211             :                  "flux type");
     212             :     }
     213        2088 : }
     214             : 
     215             : void
     216        2046 : FlowChannelBase::addVariables()
     217             : {
     218             :   // This should be called after initSecondary() because it relies on the names
     219             :   // generated in initSecondary() of heat transfer components
     220        2046 :   getHeatTransferVariableNames();
     221             : 
     222        2046 :   _flow_model->addVariables();
     223             : 
     224             :   // total heat flux perimeter
     225        2046 :   if (_n_heat_transfer_connections > 1 && !_app.isRestarting())
     226             :   {
     227          48 :     const std::string class_name = "SumIC";
     228          48 :     InputParameters params = _factory.getValidParams(class_name);
     229          96 :     params.set<VariableName>("variable") = FlowModel::HEAT_FLUX_PERIMETER;
     230          48 :     params.set<std::vector<SubdomainName>>("block") = getSubdomainNames();
     231          48 :     params.set<std::vector<VariableName>>("values") = _P_hf_names;
     232          96 :     getTHMProblem().addSimInitialCondition(class_name, genName(name(), "P_hf_ic"), params);
     233          48 :   }
     234             : 
     235        2046 :   _flow_model->addInitialConditions();
     236        2046 : }
     237             : 
     238             : void
     239        2046 : FlowChannelBase::addCommonObjects()
     240             : {
     241        2046 :   ExecFlagEnum ts_execute_on(MooseUtils::getDefaultExecFlagEnum());
     242        8184 :   ts_execute_on = {EXEC_TIMESTEP_BEGIN, EXEC_INITIAL};
     243             : 
     244             :   {
     245        2046 :     std::string class_name = "DirectionMaterial";
     246        2046 :     InputParameters params = _factory.getValidParams(class_name);
     247        2046 :     params.set<std::vector<SubdomainName>>("block") = getSubdomainNames();
     248        4092 :     getTHMProblem().addMaterial(class_name, genName(name(), "dir_mat"), params);
     249        2046 :   }
     250             : 
     251        2046 :   if (!_pipe_pars_transferred)
     252             :   {
     253             :     // Area
     254             :     {
     255        2046 :       std::string class_name = "FunctionAux";
     256        2046 :       InputParameters params = _factory.getValidParams(class_name);
     257        4092 :       params.set<AuxVariableName>("variable") = FlowModel::AREA_LINEAR;
     258        2046 :       params.set<std::vector<SubdomainName>>("block") = getSubdomainNames();
     259        2046 :       params.set<FunctionName>("function") = _area_function;
     260        2046 :       params.set<ExecFlagEnum>("execute_on") = ts_execute_on;
     261        4092 :       const std::string aux_kernel_name = genName(name(), "area_linear_aux");
     262        2046 :       getTHMProblem().addAuxKernel(class_name, aux_kernel_name, params);
     263        2046 :     }
     264             :     {
     265        2046 :       const std::string class_name = "ProjectionAux";
     266        2046 :       InputParameters params = _factory.getValidParams(class_name);
     267        4092 :       params.set<AuxVariableName>("variable") = FlowModel::AREA;
     268        4092 :       params.set<std::vector<SubdomainName>>("block") = getSubdomainNames();
     269        6138 :       params.set<std::vector<VariableName>>("v") = {FlowModel::AREA_LINEAR};
     270        2046 :       params.set<ExecFlagEnum>("execute_on") = ts_execute_on;
     271        4092 :       const std::string aux_kernel_name = genName(name(), "area_aux");
     272        2046 :       getTHMProblem().addAuxKernel(class_name, aux_kernel_name, params);
     273        2046 :     }
     274             :   }
     275        4092 : }
     276             : 
     277             : void
     278        2046 : FlowChannelBase::addMooseObjects()
     279             : {
     280        2046 :   addCommonObjects();
     281             : 
     282        2046 :   ExecFlagEnum execute_on_initial_linear(MooseUtils::getDefaultExecFlagEnum());
     283        8184 :   execute_on_initial_linear = {EXEC_INITIAL, EXEC_LINEAR};
     284             : 
     285             :   // total heat flux perimeter aux kernel
     286        2046 :   if (_n_heat_transfer_connections > 1)
     287             :   {
     288          48 :     const std::string class_name = "SumAux";
     289          48 :     InputParameters params = _factory.getValidParams(class_name);
     290          96 :     params.set<AuxVariableName>("variable") = FlowModel::HEAT_FLUX_PERIMETER;
     291          48 :     params.set<std::vector<SubdomainName>>("block") = getSubdomainNames();
     292          48 :     params.set<std::vector<VariableName>>("values") = _P_hf_names;
     293          48 :     params.set<ExecFlagEnum>("execute_on") = execute_on_initial_linear;
     294          96 :     getTHMProblem().addAuxKernel(class_name, genName(name(), "P_hf_auxkernel"), params);
     295          48 :   }
     296             : 
     297             :   // weighted average wall heat flux aux kernel
     298        2046 :   if (!_temperature_mode)
     299             :   {
     300        1634 :     if (_n_heat_transfer_connections > 1)
     301             :     {
     302          25 :       const std::string class_name = "ADWeightedAverageMaterial";
     303          25 :       InputParameters params = _factory.getValidParams(class_name);
     304          50 :       params.set<MaterialPropertyName>("prop_name") = FlowModel::HEAT_FLUX_WALL;
     305          25 :       params.set<std::vector<SubdomainName>>("block") = getSubdomainNames();
     306          25 :       params.set<std::vector<MaterialPropertyName>>("values") = _q_wall_names;
     307          25 :       params.set<std::vector<VariableName>>("weights") = _P_hf_names;
     308          50 :       getTHMProblem().addMaterial(
     309          25 :           class_name, genName(name(), FlowModel::HEAT_FLUX_WALL, "w_avg_mat"), params);
     310          25 :     }
     311        1609 :     else if (_n_heat_transfer_connections == 0)
     312             :     {
     313        1593 :       const std::string class_name = "ADConstantMaterial";
     314        1593 :       InputParameters params = _factory.getValidParams(class_name);
     315        1593 :       params.set<std::string>("property_name") = FlowModel::HEAT_FLUX_WALL;
     316        1593 :       params.set<std::vector<SubdomainName>>("block") = getSubdomainNames();
     317        1593 :       params.set<Real>("value") = 0;
     318        3186 :       getTHMProblem().addMaterial(
     319        1593 :           class_name, genName(name(), FlowModel::HEAT_FLUX_WALL, "zero_mat"), params);
     320        1593 :     }
     321             :   }
     322             : 
     323        4092 :   const auto & vpp_vars = getParam<std::vector<VariableName>>("vpp_vars");
     324        2046 :   if (vpp_vars.size() > 0)
     325             :   {
     326          45 :     const std::string class_name = "ElementValueSampler";
     327          45 :     InputParameters params = _factory.getValidParams(class_name);
     328          45 :     params.set<std::vector<SubdomainName>>("block") = getSubdomainNames();
     329          45 :     params.set<std::vector<VariableName>>("variable") = vpp_vars;
     330          90 :     params.set<std::string>("sort_by") = sortBy();
     331         180 :     params.set<ExecFlagEnum>("execute_on") = {EXEC_INITIAL, EXEC_TIMESTEP_END};
     332          45 :     getTHMProblem().addVectorPostprocessor(class_name, name() + "_vars_vpp", params);
     333          45 :   }
     334             : 
     335        2046 :   _flow_model->addMooseObjects();
     336             : 
     337        4101 :   for (const auto & closures : _closures_objects)
     338        2055 :     closures->addMooseObjectsFlowChannel(*this);
     339        4137 : }
     340             : 
     341             : void
     342         539 : FlowChannelBase::addHeatTransferName(const std::string & name) const
     343             : {
     344         539 :   _heat_transfer_names.push_back(name);
     345         539 :   _n_heat_transfer_connections++;
     346         539 : }
     347             : 
     348             : void
     349        2046 : FlowChannelBase::getHeatTransferVariableNames()
     350             : {
     351        2547 :   for (unsigned int i = 0; i < _n_heat_transfer_connections; i++)
     352             :   {
     353             :     const HeatTransferBase & heat_transfer =
     354         501 :         getComponentByName<HeatTransferBase>(_heat_transfer_names[i]);
     355             : 
     356         501 :     _P_hf_names.push_back(heat_transfer.getHeatedPerimeterName());
     357         501 :     _T_wall_names.push_back(heat_transfer.getWallTemperatureName());
     358         501 :     _T_wall_mat_names.push_back(heat_transfer.getWallTemperatureMatName());
     359         501 :     _q_wall_names.push_back(heat_transfer.getWallHeatFluxName());
     360             :   }
     361        2046 : }
     362             : 
     363             : std::string
     364        1009 : FlowChannelBase::getHeatTransferNamesSuffix(const std::string & ht_name) const
     365             : {
     366        1009 :   checkSetupStatus(INITIALIZED_PRIMARY);
     367             : 
     368             :   // if there is more than one connected heat transfer component, then number them
     369        1009 :   if (_n_heat_transfer_connections > 1)
     370             :   {
     371             :     // determine index of heat transfer name based on when it was added
     372         200 :     auto it = std::find(_heat_transfer_names.begin(), _heat_transfer_names.end(), ht_name);
     373         200 :     if (it != _heat_transfer_names.end())
     374             :     {
     375         200 :       const unsigned int index = std::distance(_heat_transfer_names.begin(), it);
     376             : 
     377         200 :       std::string suffix = ":";
     378         400 :       if (getParam<bool>("name_multiple_ht_by_index"))
     379         336 :         suffix += std::to_string(index + 1);
     380             :       else
     381          32 :         suffix += _heat_transfer_names[index];
     382             : 
     383         200 :       return suffix;
     384             :     }
     385             :     else
     386           0 :       mooseError(
     387             :           "Heat transfer component '", ht_name, "' was not added to flow channel '", name(), "'");
     388             :   }
     389             :   // else, don't add a suffix; there is no need
     390             :   else
     391         809 :     return "";
     392             : }
     393             : 
     394             : std::vector<std::string>
     395           0 : FlowChannelBase::getHeatTransferNames() const
     396             : {
     397           0 :   checkSetupStatus(INITIALIZED_PRIMARY);
     398             : 
     399           0 :   return _heat_transfer_names;
     400             : }

Generated by: LCOV version 1.14