LCOV - code coverage report
Current view: top level - src/userobjects - GrayLambertSurfaceRadiationBase.C (source / functions) Hit Total Coverage
Test: idaholab/moose heat_transfer: #31405 (292dce) with base fef103 Lines: 145 149 97.3 %
Date: 2025-09-04 07:53:51 Functions: 13 13 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 "GrayLambertSurfaceRadiationBase.h"
      11             : #include "MathUtils.h"
      12             : #include "Function.h"
      13             : #include "libmesh/quadrature.h"
      14             : 
      15             : #include <cmath>
      16             : 
      17             : InputParameters
      18         417 : GrayLambertSurfaceRadiationBase::validParams()
      19             : {
      20         417 :   InputParameters params = SideUserObject::validParams();
      21         834 :   params.addParam<Real>(
      22             :       "stefan_boltzmann_constant",
      23         834 :       5.670367e-8,
      24             :       "The Stefan-Boltzmann constant. Default value is in units of [W / m^2 K^4].");
      25         834 :   params.addRequiredCoupledVar("temperature", "The coupled temperature variable.");
      26         834 :   params.addRequiredParam<std::vector<FunctionName>>("emissivity",
      27             :                                                      "Emissivities for each boundary.");
      28         834 :   params.addParam<std::vector<BoundaryName>>(
      29             :       "fixed_temperature_boundary",
      30             :       {},
      31             :       "The list of boundary IDs from the mesh with fixed temperatures.");
      32         834 :   params.addParam<std::vector<FunctionName>>(
      33             :       "fixed_boundary_temperatures", {}, "The temperatures of the fixed boundary.");
      34         834 :   params.addParam<std::vector<BoundaryName>>(
      35             :       "adiabatic_boundary", {}, "The list of boundary IDs from the mesh that are adiabatic.");
      36             : 
      37         417 :   params.addClassDescription(
      38             :       "This object implements the exchange of heat by radiation between sidesets.");
      39         417 :   return params;
      40           0 : }
      41             : 
      42         224 : GrayLambertSurfaceRadiationBase::GrayLambertSurfaceRadiationBase(const InputParameters & parameters)
      43             :   : SideUserObject(parameters),
      44         224 :     _sigma_stefan_boltzmann(getParam<Real>("stefan_boltzmann_constant")),
      45         224 :     _n_sides(boundaryIDs().size()),
      46         224 :     _temperature(coupledValue("temperature")),
      47         224 :     _radiosity(_n_sides),
      48         224 :     _heat_flux_density(_n_sides),
      49         224 :     _side_temperature(_n_sides),
      50         224 :     _side_type(_n_sides),
      51         224 :     _areas(_n_sides),
      52         224 :     _beta(_n_sides),
      53         448 :     _surface_irradiation(_n_sides)
      54             : {
      55             :   // get emissivity functions
      56         224 :   auto & eps_names = getParam<std::vector<FunctionName>>("emissivity");
      57         224 :   _emissivity.resize(eps_names.size());
      58        1636 :   for (unsigned int j = 0; j < _emissivity.size(); ++j)
      59        1412 :     _emissivity[j] = &getFunctionByName(eps_names[j]);
      60             : 
      61             :   // set up the map from the side id to the local index & check
      62             :   // note that boundaryIDs is not in the right order anymore!
      63             :   {
      64         448 :     std::vector<BoundaryName> boundary_names = getParam<std::vector<BoundaryName>>("boundary");
      65             : 
      66        1642 :     for (unsigned int j = 0; j < boundary_names.size(); ++j)
      67             :     {
      68        1418 :       if (boundary_names[j] == "ANY_BOUNDARY_ID")
      69           0 :         paramError("boundary", "boundary must be explicitly provided.");
      70             : 
      71        1418 :       _side_id_index[_mesh.getBoundaryID(boundary_names[j])] = j;
      72        1418 :       _side_type[j] = VARIABLE_TEMPERATURE;
      73             :     }
      74             : 
      75             :     // consistency check on emissivity, must be as many entries as boundary
      76         224 :     if (boundary_names.size() != _emissivity.size())
      77           2 :       paramError("emissivity", "The number of entries must match the number of boundary entries.");
      78         222 :   }
      79             : 
      80             :   // get the fixed boundaries of the system if any are provided
      81         444 :   if (isParamValid("fixed_temperature_boundary"))
      82             :   {
      83             :     // if fixed_temperature_boundary is valid, then fixed_side_temperatures must be
      84             :     // valid, too
      85         444 :     if (!isParamValid("fixed_boundary_temperatures"))
      86           0 :       paramError("fixed_boundary_temperatures",
      87             :                  "fixed_temperature_boundary is provided, but fixed_boundary_temperatures is not.");
      88             : 
      89         666 :     auto fst_fn = getParam<std::vector<FunctionName>>("fixed_boundary_temperatures");
      90         475 :     for (auto & fn : fst_fn)
      91         253 :       _fixed_side_temperature.push_back(&getFunctionByName(fn));
      92             : 
      93             :     // get the fixed boundaries and temperatures
      94             :     std::vector<BoundaryName> boundary_names =
      95         666 :         getParam<std::vector<BoundaryName>>("fixed_temperature_boundary");
      96             : 
      97         222 :     if (boundary_names.size() != _fixed_side_temperature.size())
      98           2 :       paramError(
      99             :           "fixed_boundary_temperatures",
     100             :           "fixed_boundary_temperatures and fixed_temperature_boundary must have the same length.");
     101             : 
     102             :     unsigned int index = 0;
     103         469 :     for (auto & name : boundary_names)
     104             :     {
     105         249 :       _fixed_side_id_index[_mesh.getBoundaryID(name)] = index;
     106         249 :       index++;
     107             :     }
     108             : 
     109             :     // check that fixed side ids is a subset of boundary ids
     110             :     // and update _side_type info
     111         467 :     for (auto & p : _fixed_side_id_index)
     112             :     {
     113         249 :       if (_side_id_index.find(p.first) == _side_id_index.end())
     114           2 :         paramError("fixed_temperature_boundary",
     115             :                    "fixed_temperature_boundary must be a subset of boundary.");
     116         247 :       _side_type[_side_id_index.find(p.first)->second] = FIXED_TEMPERATURE;
     117             :     }
     118         218 :   }
     119             : 
     120             :   // get the fixed boundaries of the system if any are provided
     121         436 :   if (isParamValid("adiabatic_boundary"))
     122             :   {
     123             :     // get the adiabatic boundaries and temperatures
     124             :     std::vector<BoundaryName> boundary_names =
     125         654 :         getParam<std::vector<BoundaryName>>("adiabatic_boundary");
     126             : 
     127         747 :     for (auto & name : boundary_names)
     128         529 :       _adiabatic_side_ids.insert(_mesh.getBoundaryID(name));
     129             : 
     130             :     // check that adiabatic side ids is a subset of boundary ids
     131             :     // and update _side_type info
     132         743 :     for (auto & id : _adiabatic_side_ids)
     133             :     {
     134         527 :       if (_side_id_index.find(id) == _side_id_index.end())
     135           2 :         paramError("adiabatic_boundary", "adiabatic_boundary must be a subset of boundary.");
     136         525 :       _side_type[_side_id_index.find(id)->second] = ADIABATIC;
     137             :     }
     138             : 
     139             :     // make sure that adiabatic boundaries are not already fixed boundaries
     140         741 :     for (auto & id : _adiabatic_side_ids)
     141         525 :       if (_fixed_side_id_index.find(id) != _fixed_side_id_index.end())
     142           0 :         paramError("adiabatic_boundary", "Isothermal boundary cannot also be adiabatic boundary.");
     143         216 :   }
     144         216 : }
     145             : 
     146             : void
     147      172776 : GrayLambertSurfaceRadiationBase::execute()
     148             : {
     149             :   mooseAssert(_side_id_index.find(_current_boundary_id) != _side_id_index.end(),
     150             :               "Current boundary id not in _side_id_index.");
     151      172776 :   unsigned int index = _side_id_index.find(_current_boundary_id)->second;
     152             : 
     153      597192 :   for (unsigned int qp = 0; qp < _qrule->n_points(); qp++)
     154             :   {
     155      424416 :     _areas[index] += _JxW[qp] * _coord[qp];
     156             : 
     157             :     Real temp = 0;
     158      424416 :     if (_side_type[index] == ADIABATIC)
     159      158484 :       continue;
     160      265932 :     else if (_side_type[index] == VARIABLE_TEMPERATURE)
     161      245380 :       temp = _temperature[qp];
     162       20552 :     else if (_side_type[index] == FIXED_TEMPERATURE)
     163             :     {
     164       20552 :       unsigned int iso_index = _fixed_side_id_index.find(_current_boundary_id)->second;
     165       20552 :       temp = _fixed_side_temperature[iso_index]->value(_t, _q_point[qp]);
     166             :     }
     167             : 
     168      265932 :     _beta[index] += _JxW[qp] * _coord[qp] * _sigma_stefan_boltzmann *
     169      265932 :                     _emissivity[index]->value(temp, Point()) * MathUtils::pow(temp, 4);
     170      265932 :     _side_temperature[index] += _JxW[qp] * _coord[qp] * temp;
     171             :   }
     172      172776 : }
     173             : 
     174             : void
     175       13250 : GrayLambertSurfaceRadiationBase::initialize()
     176             : {
     177             :   // view factors are obtained here to make sure that another object had
     178             :   // time to compute them on exec initial
     179       13250 :   _view_factors = setViewFactors();
     180             : 
     181             :   // initialize areas, beta, side temps
     182       99311 :   for (unsigned int j = 0; j < _n_sides; ++j)
     183             :   {
     184       86065 :     _areas[j] = 0;
     185       86065 :     _beta[j] = 0;
     186       86065 :     _side_temperature[j] = 0;
     187             :   }
     188       13246 : }
     189             : 
     190             : void
     191       11490 : GrayLambertSurfaceRadiationBase::finalize()
     192             : {
     193             :   // need to do some parallel communiction here
     194       11490 :   gatherSum(_areas);
     195       11490 :   gatherSum(_beta);
     196       11490 :   gatherSum(_side_temperature);
     197             : 
     198             :   // first compute averages from the totals
     199       87113 :   for (unsigned int j = 0; j < _n_sides; ++j)
     200             :   {
     201       75623 :     _beta[j] /= _areas[j];
     202       75623 :     _side_temperature[j] /= _areas[j];
     203             :   }
     204             : 
     205             :   // matrix and rhs vector for the view factor calculation
     206       11490 :   DenseMatrix<Real> matrix(_n_sides, _n_sides);
     207       11490 :   DenseVector<Real> rhs(_n_sides);
     208       11490 :   DenseVector<Real> radiosity(_n_sides);
     209       87113 :   for (unsigned int i = 0; i < _n_sides; ++i)
     210             :   {
     211       75623 :     rhs(i) = _beta[i];
     212       75623 :     matrix(i, i) = 1;
     213      634488 :     for (unsigned int j = 0; j < _n_sides; ++j)
     214             :     {
     215      558865 :       if (_side_type[i] == ADIABATIC)
     216      180388 :         matrix(i, j) -= _view_factors[i][j];
     217             :       else
     218      378477 :         matrix(i, j) -=
     219      378477 :             (1 - _emissivity[i]->value(_side_temperature[i], Point())) * _view_factors[i][j];
     220             :     }
     221             :   }
     222             : 
     223             :   // compute the radiosityes
     224       11490 :   matrix.lu_solve(rhs, radiosity);
     225             : 
     226             :   // store the radiosity, temperatures and heat flux density for each surface
     227       87113 :   for (unsigned int i = 0; i < _n_sides; ++i)
     228             :   {
     229       75623 :     _radiosity[i] = radiosity(i);
     230             : 
     231             :     // _heat_flux_density is obtained from a somewhat cumbersome relation
     232             :     // but it has the advantage that we do not divide by 1 - emissivity
     233             :     // which blows up for black bodies
     234       75623 :     _heat_flux_density[i] = radiosity(i);
     235      634488 :     for (unsigned int j = 0; j < _n_sides; ++j)
     236      558865 :       _heat_flux_density[i] -= _view_factors[i][j] * radiosity(j);
     237             : 
     238       75623 :     if (_side_type[i] == ADIABATIC)
     239             :     {
     240       26394 :       Real e = _emissivity[i]->value(_side_temperature[i], Point());
     241       26394 :       _side_temperature[i] = std::pow(
     242       26394 :           (radiosity(i) + (1 - e) / e * _heat_flux_density[i]) / _sigma_stefan_boltzmann, 0.25);
     243             :     }
     244             : 
     245             :     // compute the surface irradiation into i from the radiosities
     246       75623 :     _surface_irradiation[i] = 0;
     247      634488 :     for (unsigned int j = 0; j < _n_sides; ++j)
     248      558865 :       _surface_irradiation[i] += _view_factors[i][j] * radiosity(j);
     249             :   }
     250       11490 : }
     251             : 
     252             : void
     253        1756 : GrayLambertSurfaceRadiationBase::threadJoin(const UserObject & y)
     254             : {
     255             :   const auto & pps = static_cast<const GrayLambertSurfaceRadiationBase &>(y);
     256             : 
     257       12198 :   for (unsigned int j = 0; j < _n_sides; ++j)
     258             :   {
     259       10442 :     _areas[j] += pps._areas[j];
     260       10442 :     _side_temperature[j] += pps._side_temperature[j];
     261       10442 :     _beta[j] += pps._beta[j];
     262             :   }
     263        1756 : }
     264             : 
     265             : std::set<BoundaryID>
     266          30 : GrayLambertSurfaceRadiationBase::getSurfaceIDs() const
     267             : {
     268             :   std::set<BoundaryID> surface_ids;
     269         150 :   for (auto & p : _side_id_index)
     270         120 :     surface_ids.insert(p.first);
     271          30 :   return surface_ids;
     272             : }
     273             : 
     274             : Real
     275      768800 : GrayLambertSurfaceRadiationBase::getSurfaceIrradiation(BoundaryID id) const
     276             : {
     277      768800 :   if (_side_id_index.find(id) == _side_id_index.end())
     278             :     return 0;
     279      768800 :   return _surface_irradiation[_side_id_index.find(id)->second];
     280             : }
     281             : 
     282             : Real
     283      367725 : GrayLambertSurfaceRadiationBase::getSurfaceHeatFluxDensity(BoundaryID id) const
     284             : {
     285      367725 :   if (_side_id_index.find(id) == _side_id_index.end())
     286             :     return 0;
     287      367725 :   return _heat_flux_density[_side_id_index.find(id)->second];
     288             : }
     289             : 
     290             : Real
     291         126 : GrayLambertSurfaceRadiationBase::getSurfaceTemperature(BoundaryID id) const
     292             : {
     293         126 :   if (_side_id_index.find(id) == _side_id_index.end())
     294             :     return 0;
     295         126 :   return _side_temperature[_side_id_index.find(id)->second];
     296             : }
     297             : 
     298             : Real
     299         111 : GrayLambertSurfaceRadiationBase::getSurfaceRadiosity(BoundaryID id) const
     300             : {
     301         111 :   if (_side_id_index.find(id) == _side_id_index.end())
     302             :     return 0;
     303         111 :   return _radiosity[_side_id_index.find(id)->second];
     304             : }
     305             : 
     306             : Real
     307     1220060 : GrayLambertSurfaceRadiationBase::getSurfaceEmissivity(BoundaryID id) const
     308             : {
     309             :   auto p = _side_id_index.find(id);
     310     1220060 :   if (p == _side_id_index.end())
     311             :     return 1;
     312     1220060 :   return _emissivity[p->second]->value(_side_temperature[p->second], Point());
     313             : }
     314             : 
     315             : Real
     316         240 : GrayLambertSurfaceRadiationBase::getViewFactor(BoundaryID from_id, BoundaryID to_id) const
     317             : {
     318         240 :   if (_side_id_index.find(from_id) == _side_id_index.end())
     319             :     return 0;
     320         240 :   if (_side_id_index.find(to_id) == _side_id_index.end())
     321             :     return 0;
     322         240 :   return _view_factors[_side_id_index.find(from_id)->second][_side_id_index.find(to_id)->second];
     323             : }

Generated by: LCOV version 1.14