LCOV - code coverage report
Current view: top level - src/components - HSCoupler2D3D.C (source / functions) Hit Total Coverage
Test: idaholab/moose thermal_hydraulics: #30301 (3b550b) with base 2ad78d Lines: 108 109 99.1 %
Date: 2025-07-30 13:02:48 Functions: 5 5 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 "HSCoupler2D3D.h"
      11             : #include "HeatStructureCylindricalBase.h"
      12             : #include "HeatStructureFromFile3D.h"
      13             : #include "MeshAlignment2D3D.h"
      14             : #include "THMMesh.h"
      15             : 
      16             : registerMooseObject("ThermalHydraulicsApp", HSCoupler2D3D);
      17             : 
      18             : InputParameters
      19         138 : HSCoupler2D3D::validParams()
      20             : {
      21         138 :   InputParameters params = BoundaryBase::validParams();
      22             : 
      23         276 :   params.addRequiredParam<std::string>("heat_structure_2d", "The 2D heat structure to couple");
      24         276 :   params.addRequiredParam<std::string>("heat_structure_3d", "The 3D heat structure to couple");
      25         276 :   params.addRequiredParam<BoundaryName>("boundary_2d",
      26             :                                         "The boundary of the 2D heat structure to couple");
      27         276 :   params.addRequiredParam<BoundaryName>("boundary_3d",
      28             :                                         "The boundary of the 3D heat structure to couple");
      29             : 
      30         276 :   params.addParam<bool>("include_radiation", true, "Include radiation component of heat flux");
      31         276 :   params.addParam<FunctionName>(
      32             :       "emissivity_2d",
      33             :       "Emissivity of the 2D heat structure boundary as a function of temperature [K]");
      34         276 :   params.addParam<FunctionName>(
      35             :       "emissivity_3d",
      36             :       "Emissivity of the 3D heat structure boundary as a function of temperature [K]");
      37         276 :   params.addRequiredParam<FunctionName>("gap_thickness",
      38             :                                         "Gap thickness [m] as a function of temperature [K]");
      39         276 :   params.addRequiredParam<FunctionName>(
      40             :       "gap_thermal_conductivity",
      41             :       "Gap thermal conductivity [W/(m-K)] as a function of temperature [K]");
      42         276 :   params.addParam<FunctionName>(
      43         276 :       "gap_htc", 0, "Gap heat transfer coefficient [W/(m^2-K)] as a function of temperature [K]");
      44             : 
      45         138 :   params.addClassDescription("Couples a 2D heat structure boundary to a 3D heat structure boundary "
      46             :                              "using gap heat transfer.");
      47             : 
      48         138 :   return params;
      49           0 : }
      50             : 
      51          69 : HSCoupler2D3D::HSCoupler2D3D(const InputParameters & parameters)
      52             :   : BoundaryBase(parameters),
      53             : 
      54          69 :     _hs_name_2d(getParam<std::string>("heat_structure_2d")),
      55         138 :     _hs_name_3d(getParam<std::string>("heat_structure_3d")),
      56         138 :     _boundary_2d(getParam<BoundaryName>("boundary_2d")),
      57         138 :     _boundary_3d(getParam<BoundaryName>("boundary_3d")),
      58             : 
      59         138 :     _mesh_alignment(constMesh())
      60             : {
      61          69 :   addDependency(_hs_name_2d);
      62          69 :   addDependency(_hs_name_3d);
      63          69 : }
      64             : 
      65             : void
      66          69 : HSCoupler2D3D::setupMesh()
      67             : {
      68          69 :   BoundaryBase::setupMesh();
      69             : 
      70          69 :   if (hasComponentByName<HeatStructureCylindricalBase>(_hs_name_2d) &&
      71          67 :       hasComponentByName<HeatStructureFromFile3D>(_hs_name_3d))
      72             :   {
      73             :     const auto & hs_2d = getComponentByName<HeatStructureCylindricalBase>(_hs_name_2d);
      74          65 :     const auto & hs_3d = getComponentByName<HeatStructureFromFile3D>(_hs_name_3d);
      75             : 
      76          65 :     if (hs_2d.hasBoundary(_boundary_2d) && hs_3d.hasBoundary(_boundary_3d))
      77             :     {
      78             :       // Initialize the alignment mapping
      79          61 :       _mesh_alignment.initialize(hs_2d.getBoundaryInfo(_boundary_2d),
      80             :                                  hs_3d.getBoundaryInfo(_boundary_3d),
      81          61 :                                  hs_2d.getPosition(),
      82         122 :                                  hs_2d.getDirection());
      83             : 
      84             :       // Add entries to sparsity pattern for coupling
      85          61 :       if (_mesh_alignment.meshesAreAligned())
      86        5959 :         for (const auto & elem_id : _mesh_alignment.getSecondaryElemIDs())
      87             :         {
      88        5900 :           if (_mesh_alignment.hasCoupledPrimaryElemID(elem_id))
      89        5900 :             getTHMProblem().augmentSparsity(elem_id,
      90        5900 :                                             _mesh_alignment.getCoupledPrimaryElemID(elem_id));
      91             :         }
      92             :     }
      93             :   }
      94          69 : }
      95             : 
      96             : void
      97          69 : HSCoupler2D3D::check() const
      98             : {
      99          69 :   BoundaryBase::check();
     100             : 
     101         138 :   if (getParam<bool>("include_radiation"))
     102             :   {
     103          76 :     if (!(isParamValid("emissivity_2d") && isParamValid("emissivity_3d")))
     104           2 :       logError("If 'include_radiation' is 'true', then 'emissivity_2d' and 'emissivity_3d' are "
     105             :                "required.");
     106             :   }
     107             :   else
     108             :   {
     109         192 :     if (isParamValid("emissivity_2d") || isParamValid("emissivity_3d"))
     110           2 :       logError("If 'include_radiation' is 'false', then neither 'emissivity_2d' nor "
     111             :                "'emissivity_3d' can be specified.");
     112             :   }
     113             : 
     114          69 :   if (hasComponentByName<HeatStructureCylindricalBase>(_hs_name_2d))
     115             :   {
     116             :     const auto & hs = getComponentByName<HeatStructureCylindricalBase>(_hs_name_2d);
     117          67 :     if (!hs.hasBoundary(_boundary_2d))
     118           2 :       logError("The heat structure '",
     119           2 :                _hs_name_2d,
     120             :                "' does not have the boundary '",
     121             :                _boundary_2d,
     122             :                "'.");
     123             :   }
     124             :   else
     125           2 :     logError("There is no 2D cylindrical heat structure with the name '", _hs_name_2d, "'.");
     126             : 
     127          69 :   if (hasComponentByName<HeatStructureFromFile3D>(_hs_name_3d))
     128             :   {
     129             :     const auto & hs = getComponentByName<HeatStructureFromFile3D>(_hs_name_3d);
     130          67 :     if (!hs.hasBoundary(_boundary_3d))
     131           2 :       logError("The heat structure '",
     132           2 :                _hs_name_3d,
     133             :                "' does not have the boundary '",
     134             :                _boundary_3d,
     135             :                "'.");
     136             :   }
     137             :   else
     138           2 :     logError("There is no 3D heat structure with the name '", _hs_name_3d, "'.");
     139             : 
     140          69 :   if (hasComponentByName<HeatStructureCylindricalBase>(_hs_name_2d) &&
     141          67 :       hasComponentByName<HeatStructureFromFile3D>(_hs_name_3d) &&
     142             :       !_mesh_alignment.meshesAreAligned())
     143           6 :     logError("The meshes of the heat structures are not aligned.");
     144             : 
     145          69 :   const unsigned int needed_ad_container_size = 4 * _mesh_alignment.getMaxCouplingSize() + 6;
     146          69 :   if (MOOSE_AD_MAX_DOFS_PER_ELEM < needed_ad_container_size)
     147           2 :     logError("MOOSE must be configured with a larger AD container size (>= ",
     148             :              needed_ad_container_size,
     149             :              "). See HSCoupler2D3D's documentation for more information.");
     150          69 : }
     151             : 
     152             : void
     153          55 : HSCoupler2D3D::addMooseObjects()
     154             : {
     155             :   // add side UO on 2D boundary to cache temperature values by element ID
     156         110 :   const UserObjectName temperature_2d_uo_name = genName(name(), "2d_uo");
     157             :   {
     158          55 :     const std::string class_name = "StoreVariableByElemIDSideUserObject";
     159          55 :     InputParameters params = _factory.getValidParams(class_name);
     160         165 :     params.set<std::vector<BoundaryName>>("boundary") = {_boundary_2d};
     161         165 :     params.set<std::vector<VariableName>>("variable") = {HeatConductionModel::TEMPERATURE};
     162         275 :     params.set<ExecFlagEnum>("execute_on") = {EXEC_INITIAL, EXEC_LINEAR, EXEC_NONLINEAR};
     163             :     // This UO needs to execute before the UO on the 3D boundary
     164          55 :     params.set<int>("execution_order_group") = -1;
     165          55 :     getTHMProblem().addUserObject(class_name, temperature_2d_uo_name, params);
     166          55 :   }
     167             : 
     168             :   // get the radius of the 2D heat structure boundary
     169          55 :   const auto & hs_2d = getComponentByName<HeatStructureCylindricalBase>(_hs_name_2d);
     170          55 :   const auto radius_2d = hs_2d.getInnerRadius() + hs_2d.getTotalWidth();
     171             : 
     172             :   // add side UO on 3D boundary to compute heat fluxes across each 3D boundary
     173         110 :   const UserObjectName hs_coupler_2d3d_uo_name = genName(name(), "3d_uo");
     174             :   {
     175          55 :     const std::string class_name = "HSCoupler2D3DUserObject";
     176          55 :     InputParameters params = _factory.getValidParams(class_name);
     177         165 :     params.set<std::vector<BoundaryName>>("boundary") = {_boundary_3d};
     178         165 :     params.set<std::vector<VariableName>>("temperature") = {HeatConductionModel::TEMPERATURE};
     179          55 :     params.set<Real>("radius_2d") = radius_2d;
     180         110 :     if (getParam<bool>("include_radiation"))
     181             :     {
     182          54 :       params.set<FunctionName>("emissivity_2d") = getParam<FunctionName>("emissivity_2d");
     183          54 :       params.set<FunctionName>("emissivity_3d") = getParam<FunctionName>("emissivity_3d");
     184             :     }
     185         165 :     params.set<FunctionName>("gap_thickness") = getParam<FunctionName>("gap_thickness");
     186         110 :     params.set<FunctionName>("gap_thermal_conductivity") =
     187          55 :         getParam<FunctionName>("gap_thermal_conductivity");
     188         165 :     params.set<FunctionName>("gap_htc") = getParam<FunctionName>("gap_htc");
     189          55 :     params.set<UserObjectName>("temperature_2d_uo") = temperature_2d_uo_name;
     190          55 :     params.set<MeshAlignment2D3D *>("mesh_alignment") = &_mesh_alignment;
     191         275 :     params.set<ExecFlagEnum>("execute_on") = {EXEC_INITIAL, EXEC_LINEAR, EXEC_NONLINEAR};
     192          55 :     getTHMProblem().addUserObject(class_name, hs_coupler_2d3d_uo_name, params);
     193          55 :   }
     194             : 
     195             :   // add BC on 2D boundary
     196             :   {
     197          55 :     const std::string class_name = "HSCoupler2D3DBC";
     198          55 :     InputParameters params = _factory.getValidParams(class_name);
     199         110 :     params.set<NonlinearVariableName>("variable") = HeatConductionModel::TEMPERATURE;
     200         165 :     params.set<std::vector<BoundaryName>>("boundary") = {_boundary_2d};
     201          55 :     params.set<UserObjectName>("hs_coupler_2d3d_uo") = hs_coupler_2d3d_uo_name;
     202          55 :     getTHMProblem().addBoundaryCondition(class_name, genName(name(), class_name, "2d"), params);
     203          55 :   }
     204             : 
     205             :   // add BC on 3D boundary
     206             :   {
     207          55 :     const std::string class_name = "HSCoupler2D3DBC";
     208          55 :     InputParameters params = _factory.getValidParams(class_name);
     209         110 :     params.set<NonlinearVariableName>("variable") = HeatConductionModel::TEMPERATURE;
     210         165 :     params.set<std::vector<BoundaryName>>("boundary") = {_boundary_3d};
     211          55 :     params.set<UserObjectName>("hs_coupler_2d3d_uo") = hs_coupler_2d3d_uo_name;
     212          55 :     getTHMProblem().addBoundaryCondition(class_name, genName(name(), class_name, "3d"), params);
     213          55 :   }
     214         385 : }

Generated by: LCOV version 1.14