LCOV - code coverage report
Current view: top level - src/components - HeatTransferFromHeatStructure3D1Phase.C (source / functions) Hit Total Coverage
Test: idaholab/moose thermal_hydraulics: #32971 (54bef8) with base c6cf66 Lines: 164 167 98.2 %
Date: 2026-05-29 20:41:18 Functions: 9 10 90.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 "HeatTransferFromHeatStructure3D1Phase.h"
      11             : #include "FlowChannel1Phase.h"
      12             : #include "HeatStructureFromFile3D.h"
      13             : #include "FlowModelSinglePhase.h"
      14             : #include "THMMesh.h"
      15             : #include "MooseMesh.h"
      16             : #include "ClosuresBase.h"
      17             : #include "HeatConductionModel.h"
      18             : 
      19             : registerMooseObject("ThermalHydraulicsApp", HeatTransferFromHeatStructure3D1Phase);
      20             : 
      21             : InputParameters
      22          86 : HeatTransferFromHeatStructure3D1Phase::validParams()
      23             : {
      24          86 :   InputParameters params = HeatTransferFromTemperature1Phase::validParams();
      25             : 
      26          86 :   params.makeParamRequired<FunctionName>("P_hf");
      27          86 :   params.makeParamNotRequired<std::string>("flow_channel");
      28          86 :   params.suppressParameter<std::string>("flow_channel");
      29          86 :   params.set<std::string>("flow_channel", true) = "";
      30         172 :   params.addRequiredParam<std::vector<std::string>>(
      31             :       "flow_channels", "List of flow channel component names to connect to");
      32         172 :   params.addRequiredParam<BoundaryName>(
      33             :       "boundary", "The name of the heat structure boundary this heat transfer is applied on.");
      34         172 :   params.addRequiredParam<std::string>("hs", "Heat structure name");
      35          86 :   params.addClassDescription("Connects multiple 1-phase flow channels and a 3D heat structure");
      36             : 
      37          86 :   return params;
      38           0 : }
      39             : 
      40          43 : HeatTransferFromHeatStructure3D1Phase::HeatTransferFromHeatStructure3D1Phase(
      41          43 :     const InputParameters & parameters)
      42             :   : HeatTransferFromTemperature1Phase(parameters),
      43          43 :     _flow_channel_names(getParam<std::vector<std::string>>("flow_channels")),
      44          86 :     _boundary(getParam<BoundaryName>("boundary")),
      45          86 :     _hs_name(getParam<std::string>("hs")),
      46          43 :     _mesh_alignment(constMesh()),
      47         129 :     _layered_average_uo_direction(MooseEnum("x y z"))
      48             : {
      49         114 :   for (const auto & fch_name : _flow_channel_names)
      50          71 :     addDependency(fch_name);
      51          43 :   addDependency(_hs_name);
      52          43 : }
      53             : 
      54             : const libMesh::FEType &
      55           0 : HeatTransferFromHeatStructure3D1Phase::getFEType()
      56             : {
      57           0 :   return HeatConductionModel::feType();
      58             : }
      59             : 
      60             : void
      61          43 : HeatTransferFromHeatStructure3D1Phase::setupMesh()
      62             : {
      63          43 :   if (hasComponentByName<HeatStructureFromFile3D>(_hs_name))
      64             :   {
      65             :     std::vector<dof_id_type> fchs_elem_ids;
      66         110 :     for (unsigned int i = 0; i < _flow_channel_names.size(); i++)
      67             :     {
      68          69 :       auto fch_name = _flow_channel_names[i];
      69             :       if (hasComponentByName<FlowChannel1Phase>(fch_name))
      70             :       {
      71             :         const FlowChannel1Phase & flow_channel = getComponentByName<FlowChannel1Phase>(fch_name);
      72          67 :         fchs_elem_ids.insert(fchs_elem_ids.end(),
      73          67 :                              flow_channel.getElementIDs().begin(),
      74          67 :                              flow_channel.getElementIDs().end());
      75             :       }
      76             :     }
      77             : 
      78          41 :     const auto & hs = getComponentByName<HeatStructureFromFile3D>(_hs_name);
      79          41 :     if (hs.hasBoundary(_boundary))
      80             :     {
      81          39 :       _mesh_alignment.initialize(fchs_elem_ids, hs.getBoundaryInfo(_boundary));
      82             : 
      83         587 :       for (const auto & fc_elem_id : fchs_elem_ids)
      84             :       {
      85         548 :         if (_mesh_alignment.hasCoupledSecondaryElemIDs(fc_elem_id))
      86             :         {
      87         502 :           const auto & hs_elem_ids = _mesh_alignment.getCoupledSecondaryElemIDs(fc_elem_id);
      88        2274 :           for (const auto & hs_elem_id : hs_elem_ids)
      89        1772 :             getTHMProblem().augmentSparsity(fc_elem_id, hs_elem_id);
      90             :         }
      91             :       }
      92             :     }
      93          41 :   }
      94          43 : }
      95             : 
      96             : HeatTransferFromHeatStructure3D1Phase::EAxisAlignment
      97          69 : HeatTransferFromHeatStructure3D1Phase::getFlowChannelAxisAlignment(
      98             :     const std::string & flow_channel_name) const
      99             : {
     100             :   const FlowChannel1Phase & flow_channel = getComponentByName<FlowChannel1Phase>(flow_channel_name);
     101          69 :   RealVectorValue direction = flow_channel.getDirection().unit();
     102             :   Real x_dir_norm = std::abs(direction * RealVectorValue(1, 0, 0));
     103             :   Real y_dir_norm = std::abs(direction * RealVectorValue(0, 1, 0));
     104             :   Real z_dir_norm = std::abs(direction * RealVectorValue(0, 0, 1));
     105          69 :   if (x_dir_norm == 1 && y_dir_norm == 0 && z_dir_norm == 0)
     106             :     return EAxisAlignment::X;
     107          61 :   else if (x_dir_norm == 0 && y_dir_norm == 1 && z_dir_norm == 0)
     108             :     return EAxisAlignment::Y;
     109          59 :   else if (x_dir_norm == 0 && y_dir_norm == 0 && z_dir_norm == 1)
     110             :     return EAxisAlignment::Z;
     111             :   else
     112             :   {
     113           2 :     logError(
     114             :         "The flow channel '", flow_channel_name, "' must be aligned with the x-, y-, or z- axis.");
     115           2 :     return EAxisAlignment::INVALID;
     116             :   }
     117             : }
     118             : 
     119             : void
     120          43 : HeatTransferFromHeatStructure3D1Phase::init()
     121             : {
     122             :   ConnectorBase::init();
     123             : 
     124             :   std::vector<EAxisAlignment> fch_axis_alignment;
     125             :   std::vector<unsigned int> fch_num_elems;
     126             :   std::vector<Real> fch_lengths;
     127         114 :   for (const auto & fch_name : _flow_channel_names)
     128             :   {
     129          71 :     checkComponentOfTypeExistsByName<FlowChannel1Phase>(fch_name);
     130             : 
     131             :     if (hasComponentByName<FlowChannel1Phase>(fch_name))
     132             :     {
     133             :       const FlowChannel1Phase & flow_channel = getComponentByName<FlowChannel1Phase>(fch_name);
     134             : 
     135          69 :       flow_channel.addHeatTransferName(name());
     136          69 :       fch_axis_alignment.push_back(getFlowChannelAxisAlignment(fch_name));
     137             : 
     138          69 :       const auto subdomain_names = flow_channel.getSubdomainNames();
     139          69 :       _flow_channel_subdomains.insert(
     140             :           _flow_channel_subdomains.end(), subdomain_names.begin(), subdomain_names.end());
     141             : 
     142             :       const auto & closures = flow_channel.getClosuresObjects();
     143          69 :       _flow_channel_closures.insert(_flow_channel_closures.end(), closures.begin(), closures.end());
     144             : 
     145          69 :       fch_num_elems.push_back(flow_channel.getNumElems());
     146             : 
     147          69 :       fch_lengths.push_back(flow_channel.getLength());
     148          69 :     }
     149             :   }
     150             : 
     151             :   // check that all flow channels have the same axis alignment
     152          43 :   if (fch_axis_alignment.size() > 1)
     153             :   {
     154          56 :     for (unsigned int i = 1; i < fch_axis_alignment.size(); i++)
     155          28 :       if (fch_axis_alignment[i] != fch_axis_alignment[0])
     156           4 :         logError("Flow channel '",
     157           4 :                  _flow_channel_names[i],
     158             :                  "' has a different axis alignment (",
     159             :                  fch_axis_alignment[i],
     160             :                  "). Make sure all flow channels are aligned with the same axis.");
     161             :   }
     162          43 :   if (fch_axis_alignment.size() > 0 && fch_axis_alignment[0] != EAxisAlignment::INVALID)
     163          39 :     _layered_average_uo_direction = fch_axis_alignment[0];
     164             : 
     165             :   // check that all flow channels have the same number of elements
     166          43 :   if (fch_num_elems.size() > 1)
     167             :   {
     168          56 :     for (unsigned int i = 1; i < fch_num_elems.size(); i++)
     169          28 :       if (fch_num_elems[i] != fch_num_elems[0])
     170           2 :         logError("Flow channel '",
     171           2 :                  _flow_channel_names[i],
     172             :                  "' has ",
     173             :                  fch_num_elems[i],
     174             :                  " elements which is inconsistent with the rest of the flow channels. Make sure "
     175             :                  "all flow channels have the same number of elements.");
     176             :   }
     177          43 :   if (fch_num_elems.size() > 0)
     178          41 :     _num_layers = fch_num_elems[0];
     179             : 
     180             :   // check that all flow channels have the same length
     181          43 :   if (fch_lengths.size() > 1)
     182             :   {
     183          56 :     for (unsigned int i = 1; i < fch_lengths.size(); i++)
     184          28 :       if (fch_lengths[i] != fch_lengths[0])
     185           2 :         logError("Flow channel '",
     186           2 :                  _flow_channel_names[i],
     187             :                  "' has length equal to ",
     188             :                  fch_lengths[i],
     189             :                  " which is inconsistent with the rest of the flow channels. Make sure all flow "
     190             :                  "channels have the length.");
     191             :   }
     192          43 : }
     193             : 
     194             : void
     195          43 : HeatTransferFromHeatStructure3D1Phase::initSecondary()
     196             : {
     197             :   ConnectorBase::initSecondary();
     198             : 
     199         114 :   for (const auto & fch_name : _flow_channel_names)
     200             :   {
     201             :     if (hasComponentByName<FlowChannel1Phase>(fch_name))
     202             :     {
     203             :       const FlowChannel1Phase & flow_channel = getComponentByName<FlowChannel1Phase>(fch_name);
     204          69 :       const std::string suffix = flow_channel.getHeatTransferNamesSuffix(name());
     205          69 :       _P_hf_name = FlowModel::HEAT_FLUX_PERIMETER + suffix;
     206          69 :       _T_wall_name = FlowModel::TEMPERATURE_WALL + suffix;
     207          69 :       _q_wall_name = FlowModel::HEAT_FLUX_WALL + suffix;
     208         138 :       _Hw_1phase_name = FlowModelSinglePhase::HEAT_TRANSFER_COEFFICIENT_WALL + suffix;
     209             :     }
     210             :   }
     211          43 : }
     212             : 
     213             : void
     214          40 : HeatTransferFromHeatStructure3D1Phase::check() const
     215             : {
     216             :   ConnectorBase::check();
     217             : 
     218         106 :   for (unsigned int i = 0; i < _flow_channel_closures.size(); i++)
     219             :   {
     220             :     auto & clsr = _flow_channel_closures[i];
     221          66 :     if (clsr != nullptr && hasComponentByName<FlowChannel1Phase>(_flow_channel_names[i]))
     222          66 :       clsr->checkHeatTransfer(*this, getComponentByName<FlowChannel1Phase>(_flow_channel_names[i]));
     223             :   }
     224             : 
     225          40 :   if (hasComponentByName<HeatStructureFromFile3D>(_hs_name))
     226             :   {
     227             :     const auto & hs = getComponentByName<HeatStructureFromFile3D>(_hs_name);
     228          38 :     if (!hs.hasBoundary(_boundary))
     229           2 :       logError("The boundary '", _boundary, "' does not exist on the component '", _hs_name, "'.");
     230             :   }
     231             :   else
     232           2 :     logError("The component '", _hs_name, "' is not a HeatStructureFromFile3D component.");
     233          40 : }
     234             : 
     235             : void
     236          29 : HeatTransferFromHeatStructure3D1Phase::addVariables()
     237             : {
     238          29 :   getTHMProblem().addSimVariable(
     239          29 :       false, _P_hf_name, getTHMProblem().getFlowFEType(), _flow_channel_subdomains);
     240             : 
     241          29 :   _P_hf_fn_name = getParam<FunctionName>("P_hf");
     242             : 
     243          29 :   if (!_app.isRestarting())
     244          29 :     getTHMProblem().addFunctionIC(_P_hf_name, _P_hf_fn_name, _flow_channel_subdomains);
     245             : 
     246          29 :   getTHMProblem().addSimVariable(false,
     247             :                                  FlowModel::TEMPERATURE_WALL,
     248             :                                  libMesh::FEType(CONSTANT, MONOMIAL),
     249             :                                  _flow_channel_subdomains);
     250          29 :   getTHMProblem().addSimVariable(
     251          29 :       false, _T_wall_name, libMesh::FEType(CONSTANT, MONOMIAL), _flow_channel_subdomains);
     252             : 
     253             :   // wall temperature initial condition
     254          29 :   if (!getTHMProblem().hasInitialConditionsFromFile() && !_app.isRestarting())
     255             :   {
     256          25 :     const HeatStructureFromFile3D & hs = getComponentByName<HeatStructureFromFile3D>(_hs_name);
     257          50 :     getTHMProblem().addFunctionIC(_T_wall_name, hs.getInitialT(), _flow_channel_subdomains);
     258             :   }
     259          29 : }
     260             : 
     261             : void
     262          29 : HeatTransferFromHeatStructure3D1Phase::addMooseObjects()
     263             : {
     264          29 :   HeatTransferBase::addMooseObjects();
     265             : 
     266          76 :   for (unsigned int i = 0; i < _flow_channel_closures.size(); i++)
     267             :   {
     268          47 :     _flow_channel_closures[i]->addMooseObjectsHeatTransfer(
     269          47 :         *this, getComponentByName<FlowChannel1Phase>(_flow_channel_names[i]));
     270             :   }
     271             : 
     272          29 :   ExecFlagEnum execute_on(MooseUtils::getDefaultExecFlagEnum());
     273         145 :   execute_on = {EXEC_INITIAL, EXEC_LINEAR, EXEC_NONLINEAR};
     274             : 
     275             :   std::vector<Point> fch_positions;
     276          76 :   for (const auto & fch_name : _flow_channel_names)
     277             :   {
     278             :     const FlowChannel1Phase & flow_channel = getComponentByName<FlowChannel1Phase>(fch_name);
     279          94 :     fch_positions.push_back(flow_channel.getPosition());
     280             :   }
     281             : 
     282          58 :   const UserObjectName T_wall_avg_uo_name = genName(name(), "T_wall_avg_uo");
     283             :   {
     284          29 :     const std::string class_name = "NearestPointLayeredSideAverage";
     285          29 :     InputParameters params = _factory.getValidParams(class_name);
     286          87 :     params.set<std::vector<VariableName>>("variable") = {HeatConductionModel::TEMPERATURE};
     287          87 :     params.set<std::vector<BoundaryName>>("boundary") = {_boundary};
     288          29 :     params.set<ExecFlagEnum>("execute_on") = execute_on;
     289          29 :     params.set<MooseEnum>("direction") = _layered_average_uo_direction;
     290          29 :     params.set<unsigned int>("num_layers") = _num_layers;
     291          29 :     params.set<std::vector<Point>>("points") = fch_positions;
     292          29 :     getTHMProblem().addUserObject(class_name, T_wall_avg_uo_name, params);
     293          29 :   }
     294             :   {
     295          29 :     std::string class_name = "SpatialUserObjectAux";
     296          29 :     InputParameters params = _factory.getValidParams(class_name);
     297          29 :     params.set<std::vector<SubdomainName>>("block") = _flow_channel_subdomains;
     298          58 :     params.set<AuxVariableName>("variable") = _T_wall_name;
     299          29 :     params.set<ExecFlagEnum>("execute_on") = execute_on;
     300          29 :     params.set<UserObjectName>("user_object") = T_wall_avg_uo_name;
     301          58 :     getTHMProblem().addAuxKernel(class_name, genName(name(), "T_wall_transfer"), params);
     302          29 :   }
     303             :   {
     304          29 :     const std::string class_name = "ADOneD3EqnEnergyHeatFluxFromHeatStructure3D";
     305          29 :     InputParameters params = _factory.getValidParams(class_name);
     306          58 :     params.set<std::vector<SubdomainName>>("block") = _flow_channel_subdomains;
     307          87 :     params.set<std::vector<VariableName>>("P_hf") = {_P_hf_name};
     308          29 :     params.set<MaterialPropertyName>("Hw") = _Hw_1phase_name;
     309          58 :     params.set<UserObjectName>("user_object") = T_wall_avg_uo_name;
     310          58 :     params.set<MaterialPropertyName>("T") = FlowModelSinglePhase::TEMPERATURE;
     311          58 :     params.set<NonlinearVariableName>("variable") = FlowModelSinglePhase::RHOEA;
     312          58 :     getTHMProblem().addKernel(class_name, genName(name(), "heat_flux_kernel"), params);
     313          29 :   }
     314             : 
     315          58 :   const UserObjectName heat_transfer_uo_name = genName(name(), "heat_flux_uo");
     316             :   {
     317          29 :     const std::string class_name = "ADHeatTransferFromHeatStructure3D1PhaseUserObject";
     318          29 :     InputParameters params = _factory.getValidParams(class_name);
     319          29 :     params.set<std::vector<SubdomainName>>("block") = _flow_channel_subdomains;
     320          29 :     params.set<MeshAlignment1D3D *>("_mesh_alignment") = &_mesh_alignment;
     321          87 :     params.set<std::vector<VariableName>>("P_hf") = {_P_hf_name};
     322          58 :     params.set<MaterialPropertyName>("Hw") = _Hw_1phase_name;
     323          58 :     params.set<MaterialPropertyName>("T") = FlowModelSinglePhase::TEMPERATURE;
     324          29 :     params.set<ExecFlagEnum>("execute_on") = execute_on;
     325          29 :     getTHMProblem().addUserObject(class_name, heat_transfer_uo_name, params);
     326          29 :   }
     327             :   {
     328          29 :     const std::string class_name = "ADConvectionHeatTransfer3DBC";
     329          29 :     InputParameters params = _factory.getValidParams(class_name);
     330          87 :     params.set<std::vector<BoundaryName>>("boundary") = {_boundary};
     331          58 :     params.set<NonlinearVariableName>("variable") = HeatConductionModel::TEMPERATURE;
     332          29 :     params.set<UserObjectName>("ht_uo") = heat_transfer_uo_name;
     333          58 :     getTHMProblem().addBoundaryCondition(class_name, genName(name(), "heat_flux_bc"), params);
     334          29 :   }
     335         145 : }

Generated by: LCOV version 1.14