https://mooseframework.inl.gov
Loading...
Searching...
No Matches
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
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())
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
146void
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
174void
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
190void
192{
193 // need to do some parallel communiction here
197
198 // first compute averages from the totals
199 for (unsigned int j = 0; j < _n_sides; ++j)
200 {
201 _beta[j] /= _areas[j];
202 _side_temperature[j] /= _areas[j];
203 }
204
205 // matrix and rhs vector for the view factor calculation
206 DenseMatrix<Real> matrix(_n_sides, _n_sides);
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());
241 _side_temperature[i] = std::pow(
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
247 for (unsigned int j = 0; j < _n_sides; ++j)
248 _surface_irradiation[i] += _view_factors[i][j] * radiosity(j);
249 }
250}
251
252void
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
265std::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
274unsigned int
276{
277 const auto it = _side_id_index.find(id);
278 if (it == _side_id_index.end())
279 mooseError("Sideset ID ", id, " (", _mesh.getBoundaryName(id), ") not found in map.");
280 return it->second;
281}
282
283Real
288
289Real
294
295Real
300
301Real
306
307Real
309{
310 const auto ind = getSideIDIndex(id);
311 return _emissivity[ind]->value(_side_temperature[ind], Point());
312}
313
314Real
boundary_id_type BoundaryID
const std::vector< double > y
const Real p
const Function & getFunctionByName(const FunctionName &name) const
GrayLambertSurfaceRadiationBase computes the heat flux on a set of surfaces in radiative heat transfe...
std::set< unsigned int > _adiabatic_side_ids
the set of adiabatic boundaries
const VariableValue & _temperature
the coupled temperature variable
unsigned int _n_sides
number of active boundary ids
std::vector< Real > _surface_irradiation
the irradiation into each surface
Real getSurfaceIrradiation(BoundaryID id) const
public interface of this UserObject
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
std::vector< const Function * > _emissivity
constant emissivity for each boundary
unsigned int getSideIDIndex(BoundaryID id) const
Gets the index within _side_id_index of the given boundary ID.
std::map< BoundaryID, unsigned int > _side_id_index
side id to index map, side ids can have holes or be out of order
std::vector< Real > _heat_flux_density
the heat flux density qdot
std::vector< Real > _side_temperature
the average temperature: this could be important for adiabatic walls
std::vector< Real > _areas
the area by participating side set
std::vector< Real > _beta
the average value of sigma * eps * T^4
std::vector< std::vector< Real > > _view_factors
the view factors which are set by setViewFactors by derived classes
GrayLambertSurfaceRadiationBase(const InputParameters &parameters)
const Real _sigma_stefan_boltzmann
Stefan-Boltzmann constant.
virtual void threadJoin(const UserObject &y) override
std::vector< enum RAD_BND_TYPE > _side_type
the type of the side, allows lookup index -> type
std::vector< Real > _radiosity
the radiosity of each surface
Real getViewFactor(BoundaryID from_id, BoundaryID to_id) const
std::vector< const Function * > _fixed_side_temperature
side id to index map, side ids can have holes or be out of order
virtual std::vector< std::vector< Real > > setViewFactors()=0
a purely virtual function that defines where view factors come from
void addRequiredCoupledVar(const std::string &name, const std::string &doc_string)
void addRequiredParam(const std::string &name, const std::string &doc_string)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void addClassDescription(const std::string &doc_string)
const std::string & name() const
void paramError(const std::string &param, Args... args) const
void mooseError(Args &&... args) const
bool isParamValid(const std::string &name) const
const std::string & getBoundaryName(const BoundaryID boundary_id) const
BoundaryID getBoundaryID(const BoundaryName &boundary_name) const
static InputParameters validParams()
MooseMesh & _mesh
const MooseArray< Real > & _coord
const QBase *const & _qrule
const MooseArray< Real > & _JxW
const MooseArray< Point > & _q_point
const BoundaryID & _current_boundary_id
void gatherSum(T &value)
T pow(T x, int e)