https://mooseframework.inl.gov
GrayLambertSurfaceRadiationBase.C
Go to the documentation of this file.
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 
11 #include "MathUtils.h"
12 #include "Function.h"
13 #include "libmesh/quadrature.h"
14 
15 #include <cmath>
16 
19 {
21  params.addParam<Real>(
22  "stefan_boltzmann_constant",
23  5.670367e-8,
24  "The Stefan-Boltzmann constant. Default value is in units of [W / m^2 K^4].");
25  params.addRequiredCoupledVar("temperature", "The coupled temperature variable.");
26  params.addRequiredParam<std::vector<FunctionName>>("emissivity",
27  "Emissivities for each boundary.");
28  params.addParam<std::vector<BoundaryName>>(
29  "fixed_temperature_boundary",
30  {},
31  "The list of boundary IDs from the mesh with fixed temperatures.");
32  params.addParam<std::vector<FunctionName>>(
33  "fixed_boundary_temperatures", {}, "The temperatures of the fixed boundary.");
34  params.addParam<std::vector<BoundaryName>>(
35  "adiabatic_boundary", {}, "The list of boundary IDs from the mesh that are adiabatic.");
36 
37  params.addClassDescription(
38  "This object implements the exchange of heat by radiation between sidesets.");
39  return params;
40 }
41 
43  : SideUserObject(parameters),
44  _sigma_stefan_boltzmann(getParam<Real>("stefan_boltzmann_constant")),
45  _n_sides(boundaryIDs().size()),
46  _temperature(coupledValue("temperature")),
47  _radiosity(_n_sides),
48  _heat_flux_density(_n_sides),
49  _side_temperature(_n_sides),
50  _side_type(_n_sides),
51  _areas(_n_sides),
52  _beta(_n_sides),
53  _surface_irradiation(_n_sides)
54 {
55  // get emissivity functions
56  auto & eps_names = getParam<std::vector<FunctionName>>("emissivity");
57  _emissivity.resize(eps_names.size());
58  for (unsigned int j = 0; j < _emissivity.size(); ++j)
59  _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  std::vector<BoundaryName> boundary_names = getParam<std::vector<BoundaryName>>("boundary");
65 
66  for (unsigned int j = 0; j < boundary_names.size(); ++j)
67  {
68  if (boundary_names[j] == "ANY_BOUNDARY_ID")
69  paramError("boundary", "boundary must be explicitly provided.");
70 
71  _side_id_index[_mesh.getBoundaryID(boundary_names[j])] = j;
73  }
74 
75  // consistency check on emissivity, must be as many entries as boundary
76  if (boundary_names.size() != _emissivity.size())
77  paramError("emissivity", "The number of entries must match the number of boundary entries.");
78  }
79 
80  // get the fixed boundaries of the system if any are provided
81  if (isParamValid("fixed_temperature_boundary"))
82  {
83  // if fixed_temperature_boundary is valid, then fixed_side_temperatures must be
84  // valid, too
85  if (!isParamValid("fixed_boundary_temperatures"))
86  paramError("fixed_boundary_temperatures",
87  "fixed_temperature_boundary is provided, but fixed_boundary_temperatures is not.");
88 
89  auto fst_fn = getParam<std::vector<FunctionName>>("fixed_boundary_temperatures");
90  for (auto & fn : fst_fn)
92 
93  // get the fixed boundaries and temperatures
94  std::vector<BoundaryName> boundary_names =
95  getParam<std::vector<BoundaryName>>("fixed_temperature_boundary");
96 
97  if (boundary_names.size() != _fixed_side_temperature.size())
98  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  for (auto & name : boundary_names)
104  {
106  index++;
107  }
108 
109  // check that fixed side ids is a subset of boundary ids
110  // and update _side_type info
111  for (auto & p : _fixed_side_id_index)
112  {
113  if (_side_id_index.find(p.first) == _side_id_index.end())
114  paramError("fixed_temperature_boundary",
115  "fixed_temperature_boundary must be a subset of boundary.");
116  _side_type[_side_id_index.find(p.first)->second] = FIXED_TEMPERATURE;
117  }
118  }
119 
120  // get the fixed boundaries of the system if any are provided
121  if (isParamValid("adiabatic_boundary"))
122  {
123  // get the adiabatic boundaries and temperatures
124  std::vector<BoundaryName> boundary_names =
125  getParam<std::vector<BoundaryName>>("adiabatic_boundary");
126 
127  for (auto & name : boundary_names)
129 
130  // check that adiabatic side ids is a subset of boundary ids
131  // and update _side_type info
132  for (auto & id : _adiabatic_side_ids)
133  {
134  if (_side_id_index.find(id) == _side_id_index.end())
135  paramError("adiabatic_boundary", "adiabatic_boundary must be a subset of boundary.");
136  _side_type[_side_id_index.find(id)->second] = ADIABATIC;
137  }
138 
139  // make sure that adiabatic boundaries are not already fixed boundaries
140  for (auto & id : _adiabatic_side_ids)
141  if (_fixed_side_id_index.find(id) != _fixed_side_id_index.end())
142  paramError("adiabatic_boundary", "Isothermal boundary cannot also be adiabatic boundary.");
143  }
144 }
145 
146 void
148 {
149  mooseAssert(_side_id_index.find(_current_boundary_id) != _side_id_index.end(),
150  "Current boundary id not in _side_id_index.");
151  unsigned int index = _side_id_index.find(_current_boundary_id)->second;
152 
153  for (unsigned int qp = 0; qp < _qrule->n_points(); qp++)
154  {
155  _areas[index] += _JxW[qp] * _coord[qp];
156 
157  Real temp = 0;
158  if (_side_type[index] == ADIABATIC)
159  continue;
160  else if (_side_type[index] == VARIABLE_TEMPERATURE)
161  temp = _temperature[qp];
162  else if (_side_type[index] == FIXED_TEMPERATURE)
163  {
164  unsigned int iso_index = _fixed_side_id_index.find(_current_boundary_id)->second;
165  temp = _fixed_side_temperature[iso_index]->value(_t, _q_point[qp]);
166  }
167 
168  _beta[index] += _JxW[qp] * _coord[qp] * _sigma_stefan_boltzmann *
169  _emissivity[index]->value(temp, Point()) * MathUtils::pow(temp, 4);
170  _side_temperature[index] += _JxW[qp] * _coord[qp] * temp;
171  }
172 }
173 
174 void
176 {
177  // view factors are obtained here to make sure that another object had
178  // time to compute them on exec initial
180 
181  // initialize areas, beta, side temps
182  for (unsigned int j = 0; j < _n_sides; ++j)
183  {
184  _areas[j] = 0;
185  _beta[j] = 0;
186  _side_temperature[j] = 0;
187  }
188 }
189 
190 void
192 {
193  // need to do some parallel communiction here
194  gatherSum(_areas);
195  gatherSum(_beta);
197 
198  // first compute averages from the totals
199  for (unsigned int j = 0; j < _n_sides; ++j)
200  {
201  _beta[j] /= _areas[j];
203  }
204 
205  // matrix and rhs vector for the view factor calculation
207  DenseVector<Real> rhs(_n_sides);
208  DenseVector<Real> radiosity(_n_sides);
209  for (unsigned int i = 0; i < _n_sides; ++i)
210  {
211  rhs(i) = _beta[i];
212  matrix(i, i) = 1;
213  for (unsigned int j = 0; j < _n_sides; ++j)
214  {
215  if (_side_type[i] == ADIABATIC)
216  matrix(i, j) -= _view_factors[i][j];
217  else
218  matrix(i, j) -=
219  (1 - _emissivity[i]->value(_side_temperature[i], Point())) * _view_factors[i][j];
220  }
221  }
222 
223  // compute the radiosityes
224  matrix.lu_solve(rhs, radiosity);
225 
226  // store the radiosity, temperatures and heat flux density for each surface
227  for (unsigned int i = 0; i < _n_sides; ++i)
228  {
229  _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  _heat_flux_density[i] = radiosity(i);
235  for (unsigned int j = 0; j < _n_sides; ++j)
236  _heat_flux_density[i] -= _view_factors[i][j] * radiosity(j);
237 
238  if (_side_type[i] == ADIABATIC)
239  {
240  Real e = _emissivity[i]->value(_side_temperature[i], Point());
242  (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  _surface_irradiation[i] = 0;
247  for (unsigned int j = 0; j < _n_sides; ++j)
248  _surface_irradiation[i] += _view_factors[i][j] * radiosity(j);
249  }
250 }
251 
252 void
254 {
255  const auto & pps = static_cast<const GrayLambertSurfaceRadiationBase &>(y);
256 
257  for (unsigned int j = 0; j < _n_sides; ++j)
258  {
259  _areas[j] += pps._areas[j];
260  _side_temperature[j] += pps._side_temperature[j];
261  _beta[j] += pps._beta[j];
262  }
263 }
264 
265 std::set<BoundaryID>
267 {
268  std::set<BoundaryID> surface_ids;
269  for (auto & p : _side_id_index)
270  surface_ids.insert(p.first);
271  return surface_ids;
272 }
273 
274 Real
276 {
277  if (_side_id_index.find(id) == _side_id_index.end())
278  return 0;
279  return _surface_irradiation[_side_id_index.find(id)->second];
280 }
281 
282 Real
284 {
285  if (_side_id_index.find(id) == _side_id_index.end())
286  return 0;
287  return _heat_flux_density[_side_id_index.find(id)->second];
288 }
289 
290 Real
292 {
293  if (_side_id_index.find(id) == _side_id_index.end())
294  return 0;
295  return _side_temperature[_side_id_index.find(id)->second];
296 }
297 
298 Real
300 {
301  if (_side_id_index.find(id) == _side_id_index.end())
302  return 0;
303  return _radiosity[_side_id_index.find(id)->second];
304 }
305 
306 Real
308 {
309  auto p = _side_id_index.find(id);
310  if (p == _side_id_index.end())
311  return 1;
312  return _emissivity[p->second]->value(_side_temperature[p->second], Point());
313 }
314 
315 Real
317 {
318  if (_side_id_index.find(from_id) == _side_id_index.end())
319  return 0;
320  if (_side_id_index.find(to_id) == _side_id_index.end())
321  return 0;
322  return _view_factors[_side_id_index.find(from_id)->second][_side_id_index.find(to_id)->second];
323 }
virtual std::vector< std::vector< Real > > setViewFactors()=0
a purely virtual function that defines where view factors come from
static InputParameters validParams()
std::vector< const Function * > _fixed_side_temperature
side id to index map, side ids can have holes or be out of order
std::map< BoundaryID, unsigned int > _side_id_index
side id to index map, side ids can have holes or be out of order
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
std::vector< Real > _surface_irradiation
the irradiation into each surface
GrayLambertSurfaceRadiationBase computes the heat flux on a set of surfaces in radiative heat transfe...
const MooseArray< Point > & _q_point
const std::vector< double > y
std::vector< Real > _radiosity
the radiosity of each surface
virtual const std::string & name() const
void addRequiredParam(const std::string &name, const std::string &doc_string)
Real getSurfaceIrradiation(BoundaryID id) const
public interface of this UserObject
bool isParamValid(const std::string &name) const
const MooseArray< Real > & _JxW
GrayLambertSurfaceRadiationBase(const InputParameters &parameters)
const BoundaryID & _current_boundary_id
void gatherSum(T &value)
boundary_id_type BoundaryID
std::vector< const Function * > _emissivity
constant emissivity for each boundary
void paramError(const std::string &param, Args... args) const
const MooseArray< Real > & _coord
std::set< BoundaryID > getSurfaceIDs() const
void addRequiredCoupledVar(const std::string &name, const std::string &doc_string)
std::vector< Real > _beta
the average value of sigma * eps * T^4
std::vector< Real > _side_temperature
the average temperature: this could be important for adiabatic walls
void lu_solve(const DenseVector< Real > &b, DenseVector< Real > &x)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
unsigned int _n_sides
number of active boundary ids
std::map< unsigned int, unsigned int > _fixed_side_id_index
side id to index map for isothermal boundaries, side ids can have holes or be out of order ...
const Function & getFunctionByName(const FunctionName &name) const
MooseMesh & _mesh
std::vector< std::vector< Real > > _view_factors
the view factors which are set by setViewFactors by derived classes
const QBase *const & _qrule
const Real _sigma_stefan_boltzmann
Stefan-Boltzmann constant.
void addClassDescription(const std::string &doc_string)
std::vector< Real > _heat_flux_density
the heat flux density qdot
std::set< unsigned int > _adiabatic_side_ids
the set of adiabatic boundaries
std::vector< enum RAD_BND_TYPE > _side_type
the type of the side, allows lookup index -> type
const VariableValue & _temperature
the coupled temperature variable
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
Real getViewFactor(BoundaryID from_id, BoundaryID to_id) const
std::vector< Real > _areas
the area by participating side set
T pow(T x, int e)
MooseUnits pow(const MooseUnits &, int)
BoundaryID getBoundaryID(const BoundaryName &boundary_name) const
virtual void threadJoin(const UserObject &y) override