https://mooseframework.inl.gov
RadiationTransferAction.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 "Factory.h"
12 #include "MooseMesh.h"
13 #include "MeshGeneratorMesh.h"
14 #include "FEProblemBase.h"
15 #include "PatchSidesetGenerator.h"
16 #include "ViewFactorRayBC.h"
17 #include "ViewFactorRayStudy.h"
18 
19 registerMooseAction("HeatTransferApp", RadiationTransferAction, "append_mesh_generator");
20 registerMooseAction("HeatTransferApp", RadiationTransferAction, "setup_mesh_complete");
21 registerMooseAction("HeatTransferApp", RadiationTransferAction, "add_user_object");
22 registerMooseAction("HeatTransferApp", RadiationTransferAction, "add_bc");
23 registerMooseAction("HeatTransferApp", RadiationTransferAction, "add_ray_boundary_condition");
24 
27 {
29  params.addClassDescription(
30  "This action sets up the net radiation calculation between specified sidesets.");
31 
32  params.addRequiredParam<std::vector<BoundaryName>>(
33  "boundary", "The boundaries that participate in the radiative exchange.");
34 
35  params.addParam<std::vector<BoundaryName>>(
36  "adiabatic_boundary",
37  {},
38  "The adiabatic boundaries that participate in the radiative exchange.");
39 
40  params.addParam<std::vector<BoundaryName>>(
41  "fixed_temperature_boundary",
42  {},
43  "The fixed temperature boundaries that participate in the radiative exchange.");
44 
45  params.addParam<std::vector<FunctionName>>(
46  "fixed_boundary_temperatures", {}, "The temperatures of the fixed boundary.");
47 
48  params.addRequiredParam<std::vector<unsigned int>>("n_patches",
49  "Number of radiation patches per sideset.");
50  MultiMooseEnum partitioning(
51  "default=-3 metis=-2 parmetis=-1 linear=0 centroid hilbert_sfc morton_sfc", "default");
52  partitioning.addValidName("grid");
53  params.addParam<MultiMooseEnum>(
54  "partitioners",
55  partitioning,
56  "Specifies a mesh partitioner to use when preparing the radiation patches.");
57 
58  MultiMooseEnum direction("x y z radial");
59  params.addParam<MultiMooseEnum>("centroid_partitioner_directions",
60  direction,
61  "Specifies the sort direction if using the centroid partitioner. "
62  "Available options: x, y, z, radial");
63 
64  params.addRequiredParam<VariableName>("temperature", "The coupled temperature variable.");
65  params.addRequiredParam<std::vector<FunctionName>>("emissivity",
66  "Emissivities for each boundary.");
67 
68  MooseEnum view_factor_calculator("analytical ray_tracing", "ray_tracing");
69  params.addParam<MooseEnum>(
70  "view_factor_calculator", view_factor_calculator, "The view factor calculator being used.");
71 
72  params.addParam<bool>(
73  "print_view_factor_info", false, "Flag to print information about computed view factors.");
74  params.addParam<bool>("normalize_view_factor",
75  true,
76  "Determines if view factors are normalized to sum to one (consistent with "
77  "their definition).");
78 
79  std::vector<BoundaryName> empty = {};
80  params.addParam<std::vector<BoundaryName>>(
81  "symmetry_boundary",
82  empty,
83  "The sidesets that represent symmetry lines/planes for the problem. These sidesets do not "
84  "participate in the radiative exchange"
85  "so they should not be listed in the sidesets parameter.");
86 
87  MooseEnum qtypes("GAUSS GRID", "GRID");
88  params.addParam<MooseEnum>(
89  "ray_tracing_face_type", qtypes, "The face quadrature rule type used for ray tracing.");
90 
91  MooseEnum qorders("CONSTANT FIRST SECOND THIRD FOURTH FIFTH SIXTH SEVENTH EIGHTH NINTH TENTH "
92  "ELEVENTH TWELFTH THIRTEENTH FOURTEENTH FIFTEENTH SIXTEENTH SEVENTEENTH "
93  "EIGHTTEENTH NINTEENTH TWENTIETH",
94  "CONSTANT");
95  params.addParam<MooseEnum>(
96  "ray_tracing_face_order", qorders, "The face quadrature rule order used for ray tracing.");
97 
98  params.addParam<unsigned int>(
99  "polar_quad_order",
100  16,
101  "Order of the polar quadrature [polar angle is between ray and normal]. Must be even. Only "
102  "used if view_factor_calculator = ray_tracing.");
103  params.addParam<unsigned int>(
104  "azimuthal_quad_order",
105  8,
106  "Order of the azimuthal quadrature per quadrant [azimuthal angle is measured in "
107  "a plane perpendicular to the normal]. Only used if view_factor_calculator = "
108  "ray_tracing.");
109 
110  return params;
111 }
112 
114  : Action(params),
115  _boundary_names(getParam<std::vector<BoundaryName>>("boundary")),
116  _view_factor_calculator(getParam<MooseEnum>("view_factor_calculator"))
117 {
118  const auto & symmetry_names = getParam<std::vector<BoundaryName>>("symmetry_boundary");
119 
120  if (_view_factor_calculator != "ray_tracing")
121  {
122  for (const auto & param_name : {"polar_quad_order",
123  "azimuthal_quad_order",
124  "ray_tracing_face_type",
125  "ray_tracing_face_order"})
126  if (params.isParamSetByUser(param_name))
127  paramWarning(param_name,
128  "Only used for view_factor_calculator = ray_tracing. It is ignored for this "
129  "calculation.");
130 
131  if (symmetry_names.size())
132  paramError("symmetry_boundary",
133  "Symmetry boundaries are only supported with view_factor_calculator = "
134  "ray_tracing.");
135  }
136  else
137  {
138  // check that there is no overlap between sidesets and symmetry sidesets
139  for (const auto & name : _boundary_names)
140  if (std::find(symmetry_names.begin(), symmetry_names.end(), name) != symmetry_names.end())
141  paramError("boundary",
142  "Boundary ",
143  name,
144  " is present in parameter boundary and symmetry_boundary.");
145  }
146 }
147 
148 void
150 {
151  if (_current_task == "append_mesh_generator")
153  else if (_current_task == "setup_mesh_complete")
155  else if (_current_task == "add_user_object")
156  {
160  }
161  else if (_current_task == "add_bc")
162  addRadiationBCs();
163  else if (_current_task == "add_ray_boundary_condition")
164  addRayBCs();
165 }
166 
167 void
169 {
170  InputParameters params = _factory.getValidParams("GrayLambertNeumannBC");
171 
172  // set boundary
173  std::vector<std::vector<std::string>> radiation_patch_names = bcRadiationPatchNames();
174  std::vector<BoundaryName> boundary_names;
175  for (auto & e1 : radiation_patch_names)
176  for (auto & e2 : e1)
177  boundary_names.push_back(e2);
178 
179  params.set<std::vector<BoundaryName>>("boundary") = boundary_names;
180 
181  // set temperature variable
182  params.set<NonlinearVariableName>("variable") = getParam<VariableName>("temperature");
183 
184  // set radiationuserobject
185  params.set<UserObjectName>("surface_radiation_object_name") = radiationObjectName();
186 
187  _problem->addBoundaryCondition("GrayLambertNeumannBC", "gray_lamber_neumann_bc_" + _name, params);
188 }
189 
190 void
192 {
193  std::vector<std::vector<std::string>> radiation_patch_names = radiationPatchNames();
194  std::vector<BoundaryName> boundary_names;
195  for (auto & e1 : radiation_patch_names)
196  for (auto & e2 : e1)
197  boundary_names.push_back(e2);
198 
199  // this userobject is only executed on initial
201  exec_enum = {EXEC_INITIAL};
202 
203  if (_view_factor_calculator == "analytical")
204  {
205  // this branch adds the UnobstructedPlanarViewFactor
206  InputParameters params = _factory.getValidParams("UnobstructedPlanarViewFactor");
207  params.set<std::vector<BoundaryName>>("boundary") = boundary_names;
208  params.set<ExecFlagEnum>("execute_on") = exec_enum;
209 
210  _problem->addUserObject("UnobstructedPlanarViewFactor", viewFactorObjectName(), params);
211  }
212  else if (_view_factor_calculator == "ray_tracing")
213  {
214  // this branch adds the ray tracing UO
215  InputParameters params = _factory.getValidParams("RayTracingViewFactor");
216  params.set<std::vector<BoundaryName>>("boundary") = boundary_names;
217  params.set<ExecFlagEnum>("execute_on") = exec_enum;
218  params.set<UserObjectName>("ray_study_name") = rayStudyName();
219  params.set<bool>("print_view_factor_info") = getParam<bool>("print_view_factor_info");
220  params.set<bool>("normalize_view_factor") = getParam<bool>("normalize_view_factor");
221  _problem->addUserObject("RayTracingViewFactor", viewFactorObjectName(), params);
222  }
223 }
224 
225 void
227 {
228  if (_view_factor_calculator == "analytical")
229  return;
230 
231  std::vector<std::vector<std::string>> radiation_patch_names = radiationPatchNames();
232  std::vector<BoundaryName> boundary_names;
233  for (auto & e1 : radiation_patch_names)
234  for (auto & e2 : e1)
235  boundary_names.push_back(e2);
236 
237  InputParameters params = _factory.getValidParams("ViewFactorRayStudy");
238 
239  params.set<std::vector<BoundaryName>>("boundary") = boundary_names;
240 
241  // set this object to be execute on initial only
243  exec_enum = {EXEC_INITIAL};
244  params.set<ExecFlagEnum>("execute_on") = exec_enum;
245 
246  // set face order
247  params.set<MooseEnum>("face_order") = getParam<MooseEnum>("ray_tracing_face_order");
248  params.set<MooseEnum>("face_type") = getParam<MooseEnum>("ray_tracing_face_type");
249 
250  // set angular quadrature
251  params.set<unsigned int>("polar_quad_order") = getParam<unsigned int>("polar_quad_order");
252  params.set<unsigned int>("azimuthal_quad_order") = getParam<unsigned int>("azimuthal_quad_order");
253  _problem->addUserObject("ViewFactorRayStudy", rayStudyName(), params);
254 }
255 
256 void
258 {
259  if (_view_factor_calculator == "analytical")
260  return;
261 
262  std::vector<std::vector<std::string>> radiation_patch_names = radiationPatchNames();
263  std::vector<BoundaryName> boundary_names;
264  for (auto & e1 : radiation_patch_names)
265  for (auto & e2 : e1)
266  boundary_names.push_back(e2);
267 
268  {
269  InputParameters params = _factory.getValidParams("ViewFactorRayBC");
270  params.set<std::vector<BoundaryName>>("boundary") = boundary_names;
271  params.set<RayTracingStudy *>("_ray_tracing_study") =
272  &_problem->getUserObject<ViewFactorRayStudy>(rayStudyName());
273  _problem->addObject<RayBoundaryConditionBase>("ViewFactorRayBC", rayBCName(), params);
274  }
275 
276  // add symmetry BCs if applicable
277  const auto & symmetry_names = getParam<std::vector<BoundaryName>>("symmetry_boundary");
278  if (symmetry_names.size() > 0)
279  {
280  InputParameters params = _factory.getValidParams("ReflectRayBC");
281  params.set<std::vector<BoundaryName>>("boundary") = symmetry_names;
282  params.set<RayTracingStudy *>("_ray_tracing_study") =
283  &_problem->getUserObject<ViewFactorRayStudy>(rayStudyName());
284  _problem->addObject<RayBoundaryConditionBase>("ReflectRayBC", symmetryRayBCName(), params);
285  }
286 }
287 
288 UserObjectName
290 {
291  return "ray_study_uo_" + _name;
292 }
293 
294 std::string
296 {
297  return "ray_bc_" + _name;
298 }
299 
300 std::string
302 {
303  return "symmetry_ray_bc_" + _name;
304 }
305 
306 UserObjectName
308 {
309  return "view_factor_uo_" + _name;
310 }
311 
312 UserObjectName
314 {
315  return "view_factor_surface_radiation_" + _name;
316 }
317 
318 void
320 {
321  std::vector<std::vector<std::string>> radiation_patch_names = radiationPatchNames();
322 
323  // input parameter check
324  std::vector<FunctionName> emissivity = getParam<std::vector<FunctionName>>("emissivity");
325  if (emissivity.size() != _boundary_names.size())
326  mooseError("emissivity parameter needs to be the same size as the boundary parameter.");
327 
328  // the action only sets up ViewFactorObjectSurfaceRadiation, because after splitting
329  // faces auotmatically, it makes no sense to require view factor input by hand.
330  InputParameters params = _factory.getValidParams("ViewFactorObjectSurfaceRadiation");
331  params.set<std::vector<VariableName>>("temperature") = {getParam<VariableName>("temperature")};
332 
333  std::vector<FunctionName> extended_emissivity;
334  for (unsigned int j = 0; j < _boundary_names.size(); ++j)
335  for (unsigned int i = 0; i < nPatch(j); ++i)
336  extended_emissivity.push_back(emissivity[j]);
337  params.set<std::vector<FunctionName>>("emissivity") = extended_emissivity;
338 
339  // add boundary parameter
340  std::vector<BoundaryName> boundary_names;
341  for (auto & e1 : radiation_patch_names)
342  for (auto & e2 : e1)
343  boundary_names.push_back(e2);
344  params.set<std::vector<BoundaryName>>("boundary") = boundary_names;
345 
346  // add adiabatic_boundary parameter if required
347  if (isParamValid("adiabatic_boundary"))
348  {
349  std::vector<BoundaryName> adiabatic_boundary_names =
350  getParam<std::vector<BoundaryName>>("adiabatic_boundary");
351  std::vector<BoundaryName> adiabatic_patch_names;
352  for (unsigned int k = 0; k < adiabatic_boundary_names.size(); ++k)
353  {
354  BoundaryName bnd_name = adiabatic_boundary_names[k];
355 
356  // find the right entry in _boundary_names
357  auto it = std::find(_boundary_names.begin(), _boundary_names.end(), bnd_name);
358 
359  // check if entry was found: it must be found or an error would occur later
360  if (it == _boundary_names.end())
361  mooseError("Adiabatic boundary ", bnd_name, " not present in boundary.");
362 
363  // this is the position in the _boundary_names vector; this is what
364  // we are really after
365  auto index = std::distance(_boundary_names.begin(), it);
366 
367  // collect the correct boundary names
368  for (auto & e : radiation_patch_names[index])
369  adiabatic_patch_names.push_back(e);
370  }
371  params.set<std::vector<BoundaryName>>("adiabatic_boundary") = adiabatic_patch_names;
372  }
373 
374  // add isothermal sidesets if required
375  if (isParamValid("fixed_temperature_boundary"))
376  {
377  if (!isParamValid("fixed_boundary_temperatures"))
378  mooseError("fixed_temperature_boundary is provided so fixed_boundary_temperatures must be "
379  "provided too");
380 
381  std::vector<BoundaryName> fixed_T_boundary_names =
382  getParam<std::vector<BoundaryName>>("fixed_temperature_boundary");
383 
384  std::vector<FunctionName> fixed_T_funcs =
385  getParam<std::vector<FunctionName>>("fixed_boundary_temperatures");
386 
387  // check length of fixed_boundary_temperatures
388  if (fixed_T_funcs.size() != fixed_T_boundary_names.size())
389  mooseError("Size of parameter fixed_boundary_temperatures and fixed_temperature_boundary "
390  "must be equal.");
391 
392  std::vector<BoundaryName> fixed_T_patch_names;
393  std::vector<FunctionName> fixed_T_function_names;
394  for (unsigned int k = 0; k < fixed_T_boundary_names.size(); ++k)
395  {
396  BoundaryName bnd_name = fixed_T_boundary_names[k];
397 
398  // find the right entry in _boundary_names
399  auto it = std::find(_boundary_names.begin(), _boundary_names.end(), bnd_name);
400 
401  // check if entry was found: it must be found or an error would occur later
402  if (it == _boundary_names.end())
403  mooseError("Fixed temperature sideset ", bnd_name, " not present in boundary.");
404 
405  // this is the position in the _boundary_names vector; this is what
406  // we are really after
407  auto index = std::distance(_boundary_names.begin(), it);
408 
409  // collect the correct boundary names
410  for (auto & e : radiation_patch_names[index])
411  {
412  fixed_T_patch_names.push_back(e);
413  fixed_T_function_names.push_back(fixed_T_funcs[k]);
414  }
415  }
416  params.set<std::vector<BoundaryName>>("fixed_temperature_boundary") = fixed_T_patch_names;
417  params.set<std::vector<FunctionName>>("fixed_boundary_temperatures") = fixed_T_function_names;
418  }
419 
420  // the view factor userobject name
421  params.set<UserObjectName>("view_factor_object_name") = viewFactorObjectName();
422 
423  // this userobject needs to be executed on linear and timestep end
425  exec_enum = {EXEC_LINEAR, EXEC_TIMESTEP_END};
426  params.set<ExecFlagEnum>("execute_on") = exec_enum;
427 
428  // add the object
429  _problem->addUserObject("ViewFactorObjectSurfaceRadiation", radiationObjectName(), params);
430 }
431 
432 std::vector<std::vector<std::string>>
434 {
435  std::vector<std::vector<std::string>> radiation_patch_names(_boundary_names.size());
436  std::vector<BoundaryID> boundary_ids = _mesh->getBoundaryIDs(_boundary_names);
437  for (unsigned int j = 0; j < boundary_ids.size(); ++j)
438  {
439  boundary_id_type bid = boundary_ids[j];
440  std::string base_name = _mesh->getBoundaryName(bid);
441  std::vector<std::string> bnames;
442  for (unsigned int i = 0; i < nPatch(j); ++i)
443  {
444  std::stringstream ss;
445  ss << base_name << "_" << i;
446  bnames.push_back(ss.str());
447  }
448  radiation_patch_names[j] = bnames;
449  }
450  return radiation_patch_names;
451 }
452 
453 std::vector<std::vector<std::string>>
455 {
456  auto ad_bnd_names = getParam<std::vector<BoundaryName>>("adiabatic_boundary");
457  auto ft_bnd_names = getParam<std::vector<BoundaryName>>("fixed_temperature_boundary");
458  std::vector<std::vector<std::string>> radiation_patch_names;
459  std::vector<BoundaryID> boundary_ids = _mesh->getBoundaryIDs(_boundary_names);
460  for (unsigned int j = 0; j < boundary_ids.size(); ++j)
461  {
462  boundary_id_type bid = boundary_ids[j];
463  BoundaryName bnd_name = _boundary_names[j];
464 
465  // check if this sideset is adiabatic or isothermal
466  auto it_a = std::find(ad_bnd_names.begin(), ad_bnd_names.end(), bnd_name);
467  auto it_t = std::find(ft_bnd_names.begin(), ft_bnd_names.end(), bnd_name);
468  if (it_a != ad_bnd_names.end() || it_t != ft_bnd_names.end())
469  continue;
470 
471  std::string base_name = _mesh->getBoundaryName(bid);
472  std::vector<std::string> bnames;
473  for (unsigned int i = 0; i < nPatch(j); ++i)
474  {
475  std::stringstream ss;
476  ss << base_name << "_" << i;
477  bnames.push_back(ss.str());
478  }
479  radiation_patch_names.push_back(bnames);
480  }
481  return radiation_patch_names;
482 }
483 
484 void
486 {
487  std::vector<unsigned int> n_patches = getParam<std::vector<unsigned int>>("n_patches");
488  MultiMooseEnum partitioners = getParam<MultiMooseEnum>("partitioners");
489  if (!_pars.isParamSetByUser("partitioners"))
490  {
491  partitioners.clearSetValues();
492  for (unsigned int j = 0; j < _boundary_names.size(); ++j)
493  partitioners.setAdditionalValue("metis");
494  }
495 
496  MultiMooseEnum direction = getParam<MultiMooseEnum>("centroid_partitioner_directions");
497 
498  // check input parameters
499  if (_boundary_names.size() != n_patches.size())
500  mooseError("n_patches parameter must have same length as boundary parameter.");
501 
502  if (_boundary_names.size() != partitioners.size())
503  mooseError("partitioners parameter must have same length as boundary parameter.");
504 
505  for (unsigned int j = 0; j < partitioners.size(); ++j)
506  if (partitioners[j] == "centroid" && direction.size() != _boundary_names.size())
507  mooseError(
508  "centroid partitioner is selected for at least one sideset. "
509  "centroid_partitioner_directions parameter must have same length as boundary parameter.");
510 
511  // check if mesh is a MeshGeneratorMesh
512  std::shared_ptr<MeshGeneratorMesh> mg_mesh = std::dynamic_pointer_cast<MeshGeneratorMesh>(_mesh);
513  if (!mg_mesh)
514  mooseError("This action adds MeshGenerator objects and therefore only works with a "
515  "MeshGeneratorMesh.");
516 
517  for (unsigned int j = 0; j < _boundary_names.size(); ++j)
518  {
519  InputParameters params = _factory.getValidParams("PatchSidesetGenerator");
520  params.set<BoundaryName>("boundary") = _boundary_names[j];
521  params.set<unsigned int>("n_patches") = n_patches[j];
522  params.set<MooseEnum>("partitioner") = partitioners[j];
523 
524  if (partitioners[j] == "centroid")
525  params.set<MooseEnum>("centroid_partitioner_direction") = direction[j];
526 
527  _app.appendMeshGenerator("PatchSidesetGenerator", meshGeneratorName(j), params);
528  }
529 }
530 
531 unsigned int
533 {
535  const PatchSidesetGenerator * psg = dynamic_cast<const PatchSidesetGenerator *>(mg);
536  if (!psg)
537  mooseError("Failed to convert mesh generator ", mg->name(), " to PatchSidesetGenerator.");
538  return psg->nPatches();
539 }
540 
541 MeshGeneratorName
543 {
544  std::stringstream ss;
545  ss << "patch_side_set_generator_" << _boundary_names[j];
546  return ss.str();
547 }
const MeshGenerator & getMeshGenerator(const std::string &name) const
const std::vector< BoundaryName > _boundary_names
the boundary names participating in the radiative heat transfer
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
Subdivides a sidesets into smaller patches each of which is going to be a new patch.
MooseApp & _app
T & set(const std::string &name, bool quiet_mode=false)
InputParameters getValidParams(const std::string &name) const
unsigned int size() const
UserObjectName rayStudyName() const
const ExecFlagType EXEC_TIMESTEP_END
virtual const std::string & name() const
void addRequiredParam(const std::string &name, const std::string &doc_string)
std::vector< std::vector< std::string > > radiationPatchNames() const
static InputParameters validParams()
MeshGeneratorName meshGeneratorName(unsigned int j) const
ExecFlagEnum getDefaultExecFlagEnum()
bool isParamValid(const std::string &name) const
Factory & _factory
RayTracingStudy used to generate Rays for view factor computation using the angular quadrature method...
static InputParameters validParams()
int8_t boundary_id_type
std::vector< std::vector< std::string > > bcRadiationPatchNames() const
UserObjectName viewFactorObjectName() const
const std::string & _current_task
void paramError(const std::string &param, Args... args) const
const ExecFlagType EXEC_LINEAR
const std::string _name
const MeshGenerator & appendMeshGenerator(const std::string &type, const std::string &name, InputParameters params)
bool isParamSetByUser(const std::string &name) const
virtual void act() override
std::shared_ptr< MooseMesh > & _mesh
const MooseEnum _view_factor_calculator
the type of view factor calculation being performed
unsigned int nPatch(unsigned int j) const
provides the updated number of patches for this boundary
UserObjectName radiationObjectName() const
void mooseError(Args &&... args) const
const InputParameters & _pars
void addClassDescription(const std::string &doc_string)
std::shared_ptr< FEProblemBase > & _problem
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
void paramWarning(const std::string &param, Args... args) const
std::string symmetryRayBCName() const
Base class for the RayBC syntax.
unsigned int nPatches() const
static const std::string k
Definition: NS.h:130
RadiationTransferAction(const InputParameters &params)
registerMooseAction("HeatTransferApp", RadiationTransferAction, "append_mesh_generator")
static const std::string emissivity
void clearSetValues()
Base class for Ray tracing studies that will generate Rays and then propagate all of them to terminat...
const ExecFlagType EXEC_INITIAL