LCOV - code coverage report
Current view: top level - src/components - HSCoupler2D2DRadiation.C (source / functions) Hit Total Coverage
Test: idaholab/moose thermal_hydraulics: #30301 (3b550b) with base 2ad78d Lines: 89 92 96.7 %
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 "HSCoupler2D2DRadiation.h"
      11             : #include "HeatStructureCylindricalBase.h"
      12             : #include "THMMesh.h"
      13             : #include "MooseUtils.h"
      14             : 
      15             : registerMooseObject("ThermalHydraulicsApp", HSCoupler2D2DRadiation);
      16             : 
      17             : InputParameters
      18         116 : HSCoupler2D2DRadiation::validParams()
      19             : {
      20         116 :   InputParameters params = BoundaryBase::validParams();
      21             : 
      22         232 :   params.addRequiredParam<std::vector<std::string>>("heat_structures",
      23             :                                                     "The heat structures to couple");
      24         232 :   params.addRequiredParam<std::vector<BoundaryName>>(
      25             :       "boundaries", "The boundaries of the heat structures to couple");
      26         232 :   params.addRequiredRangeCheckedParam<std::vector<Real>>(
      27             :       "emissivities",
      28             :       "emissivities > 0 & emissivities < 1",
      29             :       "Emissivities of each heat structure surface");
      30         232 :   params.addRequiredRangeCheckedParam<std::vector<std::vector<Real>>>(
      31             :       "view_factors",
      32             :       "view_factors >= 0 & view_factors <= 1",
      33             :       "The view factors between each surface, as a matrix. The row/column ordering corresponds to "
      34             :       "the ordering in 'heat_structures', with an additional row and column if "
      35             :       "'include_environment' is set to 'true'. Each row must sum to one.");
      36         232 :   params.addRequiredParam<bool>(
      37             :       "include_environment",
      38             :       "Whether or not to include an environment surrounding all of the surfaces. If the heat "
      39             :       "structure surfaces themselves form an enclosure, then set this parameter to 'false'.");
      40         232 :   params.addParam<Real>(
      41             :       "T_environment",
      42             :       "Environment temperature [K]. Only set if 'include_environment' is set to true.");
      43             : 
      44         116 :   params.addClassDescription("Couples boundaries of multiple 2D heat structures via radiation");
      45             : 
      46         116 :   return params;
      47           0 : }
      48             : 
      49          58 : HSCoupler2D2DRadiation::HSCoupler2D2DRadiation(const InputParameters & parameters)
      50             :   : BoundaryBase(parameters),
      51             : 
      52          58 :     _hs_names(getParam<std::vector<std::string>>("heat_structures")),
      53         116 :     _hs_boundaries(getParam<std::vector<BoundaryName>>("boundaries")),
      54         116 :     _include_environment(getParam<bool>("include_environment")),
      55          58 :     _n_hs(_hs_names.size()),
      56          58 :     _n_surfaces(_include_environment ? _n_hs + 1 : _n_hs),
      57             : 
      58         116 :     _mesh_alignment(constMesh())
      59             : {
      60         210 :   for (unsigned int i = 0; i < _n_hs; ++i)
      61         152 :     addDependency(_hs_names[i]);
      62          58 : }
      63             : 
      64             : void
      65          58 : HSCoupler2D2DRadiation::setupMesh()
      66             : {
      67          58 :   BoundaryBase::setupMesh();
      68             : 
      69             :   // If there is more than one heat structure, initialize mesh alignment and
      70             :   // augment the sparsity pattern
      71          58 :   if (_n_hs >= 2)
      72             :   {
      73             :     // get boundary info vectors for all boundaries
      74             :     std::vector<std::vector<std::tuple<dof_id_type, unsigned short int>>> boundary_infos;
      75         210 :     for (const auto i : index_range(_hs_names))
      76             :     {
      77             :       if (hasComponentByName<HeatStructureBase>(_hs_names[i]))
      78             :       {
      79             :         const auto & hs = getComponentByName<HeatStructureBase>(_hs_names[i]);
      80         152 :         if (i < _hs_boundaries.size() && hs.hasBoundary(_hs_boundaries[i]))
      81         152 :           boundary_infos.push_back(hs.getBoundaryInfo(_hs_boundaries[i]));
      82             :       }
      83             :     }
      84             : 
      85             :     // Initialize the alignment mapping
      86             :     if (hasComponentByName<HeatStructureBase>(_hs_names[0]))
      87             :     {
      88             :       const auto & hs = getComponentByName<HeatStructureBase>(_hs_names[0]);
      89          58 :       _mesh_alignment.initialize(boundary_infos, hs.getPosition(), hs.getDirection());
      90             :     }
      91             : 
      92             :     // Add entries to sparsity pattern for coupling
      93          58 :     if (_mesh_alignment.meshesAreAligned())
      94         638 :       for (const auto & primary_elem_id : _mesh_alignment.getPrimaryElemIDs())
      95             :       {
      96         580 :         const auto & coupled_elem_ids = _mesh_alignment.getCoupledSecondaryElemIDs(primary_elem_id);
      97             :         std::vector<dof_id_type> elem_ids;
      98         580 :         elem_ids.push_back(primary_elem_id);
      99         580 :         elem_ids.insert(elem_ids.end(), coupled_elem_ids.begin(), coupled_elem_ids.end());
     100             : 
     101        2100 :         for (unsigned int i = 0; i < elem_ids.size(); ++i)
     102        3000 :           for (unsigned int j = i + 1; j < elem_ids.size(); ++j)
     103        1480 :             getTHMProblem().augmentSparsity(elem_ids[i], elem_ids[j]);
     104             :       }
     105          58 :   }
     106          58 : }
     107             : 
     108             : void
     109          58 : HSCoupler2D2DRadiation::check() const
     110             : {
     111          58 :   BoundaryBase::check();
     112             : 
     113         116 :   checkEqualSize<BoundaryName, std::string>("boundaries", "heat_structures");
     114         116 :   checkEqualSize<Real, std::string>("emissivities", "heat_structures");
     115             : 
     116             :   // check view factor matrix dimensions
     117         116 :   const auto & view_factors = getParam<std::vector<std::vector<Real>>>("view_factors");
     118             :   bool correct_size = true;
     119          58 :   if (view_factors.size() == _n_surfaces)
     120             :   {
     121         228 :     for (const auto i : index_range(view_factors))
     122         170 :       if (view_factors[i].size() != _n_surfaces)
     123             :         correct_size = false;
     124             :   }
     125             :   else
     126             :     correct_size = false;
     127          58 :   if (!correct_size)
     128           2 :     logError("The parameter 'view_factors' must be a square matrix of size ",
     129           2 :              _n_surfaces,
     130             :              ". For example, a size 2 matrix is provided as '0.2 0.8; 0.7 0.3'. The row/column "
     131             :              "ordering corresponds to the ordering in 'heat_structures', with an additional "
     132             :              "row/column if 'include_environment' is set to 'true'.");
     133             : 
     134             :   // check that all view factor matrix rows sum to one
     135             :   bool all_row_sums_unity = true;
     136         228 :   for (const auto i : index_range(view_factors))
     137         170 :     if (!MooseUtils::absoluteFuzzyEqual(
     138             :             std::accumulate(view_factors[i].begin(), view_factors[i].end(), 0.0), 1.0))
     139             :       all_row_sums_unity = false;
     140          58 :   if (!all_row_sums_unity)
     141           2 :     logError("All rows in 'view_factors' must sum to one.");
     142             : 
     143          58 :   if (_n_hs > 1 && !_mesh_alignment.meshesAreAligned())
     144           0 :     logError("The meshes of the heat structures are not aligned.");
     145             : 
     146         210 :   for (const auto i : index_range(_hs_names))
     147             :   {
     148             :     // for now we only allow cylindrical heat structures
     149         152 :     checkComponentOfTypeExistsByName<HeatStructureCylindricalBase>(_hs_names[i]);
     150             : 
     151             :     if (hasComponentByName<HeatStructureBase>(_hs_names[i]))
     152             :     {
     153             :       const auto & hs = getComponentByName<HeatStructureBase>(_hs_names[i]);
     154         152 :       if (i < _hs_boundaries.size() && !hs.hasBoundary(_hs_boundaries[i]))
     155           0 :         logError("The heat structure '",
     156             :                  _hs_names[i],
     157             :                  "' does not have the boundary '",
     158             :                  _hs_boundaries[i],
     159             :                  "'.");
     160             :     }
     161             :   }
     162          58 : }
     163             : 
     164             : void
     165          54 : HSCoupler2D2DRadiation::addMooseObjects()
     166             : {
     167             :   // add side UO on 2D boundary to cache temperature values by element ID
     168         108 :   const UserObjectName temperature_uo_name = genName(name(), "temperature_uo");
     169             :   {
     170          54 :     const std::string class_name = "StoreVariableByElemIDSideUserObject";
     171          54 :     InputParameters params = _factory.getValidParams(class_name);
     172         108 :     params.set<std::vector<BoundaryName>>("boundary") = _hs_boundaries;
     173         162 :     params.set<std::vector<VariableName>>("variable") = {HeatConductionModel::TEMPERATURE};
     174         270 :     params.set<ExecFlagEnum>("execute_on") = {EXEC_INITIAL, EXEC_LINEAR, EXEC_NONLINEAR};
     175             :     // This UO needs to execute before the UO below
     176          54 :     params.set<int>("execution_order_group") = -1;
     177          54 :     getTHMProblem().addUserObject(class_name, temperature_uo_name, params);
     178          54 :   }
     179             : 
     180             :   // add side UO to compute heat fluxes across each boundary
     181         108 :   const UserObjectName hs_coupler_2d2d_uo_name = genName(name(), "uo");
     182             :   {
     183          54 :     const std::string class_name = "HSCoupler2D2DRadiationUserObject";
     184          54 :     InputParameters params = _factory.getValidParams(class_name);
     185         162 :     params.set<std::vector<BoundaryName>>("boundary") = {_hs_boundaries[0]};
     186         270 :     params.applySpecificParameters(
     187             :         parameters(), {"emissivities", "view_factors", "include_environment", "T_environment"});
     188          54 :     params.set<UserObjectName>("temperature_uo") = temperature_uo_name;
     189          54 :     params.set<MeshAlignment2D2D *>("mesh_alignment") = &_mesh_alignment;
     190         270 :     params.set<ExecFlagEnum>("execute_on") = {EXEC_INITIAL, EXEC_LINEAR, EXEC_NONLINEAR};
     191          54 :     getTHMProblem().addUserObject(class_name, hs_coupler_2d2d_uo_name, params);
     192          54 :   }
     193             : 
     194             :   // BCs
     195         198 :   for (unsigned int i = 0; i < _n_hs; ++i)
     196             :   {
     197         144 :     const auto & hs = getComponentByName<HeatStructureCylindricalBase>(_hs_names[i]);
     198             : 
     199         144 :     const std::string class_name = "HSCoupler2D2DRadiationRZBC";
     200         144 :     InputParameters params = _factory.getValidParams(class_name);
     201         288 :     params.set<NonlinearVariableName>("variable") = HeatConductionModel::TEMPERATURE;
     202         432 :     params.set<std::vector<BoundaryName>>("boundary") = {_hs_boundaries[i]};
     203         144 :     params.set<UserObjectName>("hs_coupler_2d2d_uo") = hs_coupler_2d2d_uo_name;
     204         144 :     params.set<Point>("axis_point") = hs.getPosition();
     205         144 :     params.set<RealVectorValue>("axis_dir") = hs.getDirection();
     206         144 :     getTHMProblem().addBoundaryCondition(class_name, genName(name(), class_name, i), params);
     207         144 :   }
     208         270 : }

Generated by: LCOV version 1.14