https://mooseframework.inl.gov
CHTHandler.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 
10 // Moose includes
11 #include "CHTHandler.h"
12 #include "LinearFVFluxKernel.h"
13 #include "LinearFVDiffusion.h"
16 #include "LinearFVCHTBCInterface.h"
17 #include "FEProblemBase.h"
18 
19 namespace NS
20 {
21 namespace FV
22 {
23 
26 {
27  auto params = emptyInputParameters();
28  params.addParam<std::vector<BoundaryName>>(
29  "cht_interfaces",
30  {},
31  "The interfaces where we would like to add conjugate heat transfer handling.");
32 
33  params.addRangeCheckedParam<unsigned int>(
34  "max_cht_fpi",
35  1,
36  "max_cht_fpi >= 1",
37  "Number of maximum fixed point iterations (FPI). Currently only applied to"
38  " conjugate heat transfer simulations. The default value of 1 essentially keeps"
39  " the FPI feature turned off. CHT iteration ends after this number of iteration even if the "
40  "tolerance is not met.");
41 
42  params.addRangeCheckedParam<Real>(
43  "cht_heat_flux_tolerance",
44  1e-5,
45  "cht_heat_flux_tolerance > 0 & cht_heat_flux_tolerance <= 1.0",
46  "The relative tolerance for terminating conjugate heat transfer iteration before the maximum "
47  "number of CHT iterations. Relative tolerance is ignore if the maximum number of CHT "
48  "iterations is reached.");
49 
50  params.addParam<std::vector<Real>>(
51  "cht_fluid_temperature_relaxation",
52  {},
53  "The relaxation factors for the boundary temperature when being updated on the fluid side.");
54  params.addParam<std::vector<Real>>(
55  "cht_solid_temperature_relaxation",
56  {},
57  "The relaxation factors for the boundary temperature when being updated on the solid side.");
58  params.addParam<std::vector<Real>>(
59  "cht_fluid_flux_relaxation",
60  {},
61  "The relaxation factors for the boundary flux when being updated on the fluid side.");
62  params.addParam<std::vector<Real>>(
63  "cht_solid_flux_relaxation",
64  {},
65  "The relaxation factors for the boundary flux when being updated on the solid side.");
66 
67  params.addParamNamesToGroup(
68  "cht_interfaces max_cht_fpi cht_heat_flux_tolerance cht_fluid_temperature_relaxation "
69  "cht_solid_temperature_relaxation cht_fluid_flux_relaxation "
70  "cht_solid_flux_relaxation",
71  "Conjugate Heat Transfer");
72 
73  return params;
74 }
75 
77  : MooseObject(params),
78  _problem(*getCheckedPointerParam<FEProblemBase *>(
79  "_fe_problem_base", "This might happen if you don't have a mesh")),
80  _mesh(_problem.mesh()),
81  _cht_boundary_names(getParam<std::vector<BoundaryName>>("cht_interfaces")),
82  _cht_boundary_ids(_mesh.getBoundaryIDs(_cht_boundary_names)),
83  _max_cht_fpi(getParam<unsigned int>("max_cht_fpi")),
84  _cht_heat_flux_tolerance(getParam<Real>("cht_heat_flux_tolerance"))
85 {
86  if (isParamSetByUser("cht_interfaces") && !_cht_boundary_names.size())
87  paramError("cht_interfaces", "You must declare at least one interface!");
88 }
89 
90 void
91 CHTHandler::linkEnergySystems(SystemBase * solid_energy_system, SystemBase * fluid_energy_system)
92 {
93  _energy_system = fluid_energy_system;
94  _solid_energy_system = solid_energy_system;
95 
97  paramError("cht_interfaces",
98  "You selected to do conjugate heat transfer treatment, but it needs two energy "
99  "systems: a solid and a fluid. One of these systems is missing.");
100 }
101 
102 void
104 {
105  if (_solid_energy_system->nVariables() != 1)
106  mooseError("We should have only one variable in the solid energy system: ",
107  _energy_system->name(),
108  "! Right now we have: ",
110  if (_energy_system->nVariables() != 1)
111  mooseError("We should have only one variable in the fluid energy system: ",
112  _energy_system->name(),
113  "! Right now we have: ",
115  const std::vector<std::string> solid_fluid({"solid", "fluid"});
116 
117  // We do some setup at the beginning to make sure the container sizes are good
119  std::vector<unsigned int>({_solid_energy_system->number(), _energy_system->number()});
120  _cht_conduction_kernels = std::vector<LinearFVFluxKernel *>({nullptr, nullptr});
121  _cht_boundary_conditions.clear();
122  _cht_boundary_conditions.resize(_cht_boundary_names.size(), {nullptr, nullptr});
123 
124  const auto flux_relaxation_param_names =
125  std::vector<std::string>({"cht_solid_flux_relaxation", "cht_fluid_flux_relaxation"});
126  const auto temperature_relaxation_param_names = std::vector<std::string>(
127  {"cht_solid_temperature_relaxation", "cht_fluid_temperature_relaxation"});
129  _cht_flux_relaxation_factor.resize(2, std::vector<Real>(_cht_boundary_names.size(), 1.0));
131  _cht_temperature_relaxation_factor.resize(2, std::vector<Real>(_cht_boundary_names.size(), 1.0));
132 
133  for (const auto region_index : index_range(solid_fluid))
134  {
135  // First thing, we fetch the relaxation parameter values
136  const auto & flux_param_value =
137  getParam<std::vector<Real>>(flux_relaxation_param_names[region_index]);
138  if (flux_param_value.empty() || (flux_param_value.size() != _cht_boundary_names.size()))
139  paramError(flux_relaxation_param_names[region_index],
140  "The number of relaxation factors is not the same as the number of interfaces!");
141 
142  _cht_flux_relaxation_factor[region_index] = flux_param_value;
143  // We have to do the range check here because the intput parameter check errors if the vector is
144  // empty
145  for (const auto param : _cht_flux_relaxation_factor[region_index])
146  if (param <= 0 || param > 1.0)
147  paramError(flux_relaxation_param_names[region_index],
148  "The relaxation parameter should be between 0 and 1!");
149 
150  const auto & temperature_param_value =
151  getParam<std::vector<Real>>(temperature_relaxation_param_names[region_index]);
152  if (temperature_param_value.empty() ||
153  (temperature_param_value.size() != _cht_boundary_names.size()))
154  paramError(temperature_relaxation_param_names[region_index],
155  "The number of relaxation factors is not the same as the number of interfaces!");
156 
157  _cht_temperature_relaxation_factor[region_index] = temperature_param_value;
158  // We have to do the range check here because the intput parameter check errors if the vector is
159  // empty
160  for (const auto param : _cht_temperature_relaxation_factor[region_index])
161  if (param <= 0 || param > 1.0)
162  paramError(temperature_relaxation_param_names[region_index],
163  "The relaxation parameter should be between 0 and 1!");
164 
165  // We then fetch the conduction kernels
166  std::vector<LinearFVFluxKernel *> flux_kernels;
168  .query()
169  .template condition<AttribSystem>("LinearFVFluxKernel")
170  .template condition<AttribVar>(0)
171  .template condition<AttribSysNum>(_cht_system_numbers[region_index])
172  .queryInto(flux_kernels);
173 
174  for (auto kernel : flux_kernels)
175  {
176  auto check_diff = dynamic_cast<LinearFVDiffusion *>(kernel);
177  auto check_aniso_diff = dynamic_cast<LinearFVAnisotropicDiffusion *>(kernel);
178  if (_cht_conduction_kernels[region_index] && (check_diff || check_aniso_diff))
179  mooseError("We already have a kernel that describes the heat conduction for the ",
180  solid_fluid[region_index],
181  " domain: ",
182  _cht_conduction_kernels[region_index]->name(),
183  " We found another one with the name: ",
184  (check_diff ? check_diff->name() : check_aniso_diff->name()),
185  " Make sure that you have only one conduction kernel on the ",
186  solid_fluid[region_index],
187  " side!");
188 
189  if (check_diff || check_aniso_diff)
190  _cht_conduction_kernels[region_index] = kernel;
191  }
192 
193  // Then we check the boundary conditions, to make sure at least there is something defined
194  // from both sides
195  for (const auto bd_index : index_range(_cht_boundary_names))
196  {
197  const auto & boundary_name = _cht_boundary_names[bd_index];
198  const auto boundary_id = _cht_boundary_ids[bd_index];
199 
200  std::vector<LinearFVBoundaryCondition *> bcs;
202  .theWarehouse()
203  .query()
204  .template condition<AttribSystem>("LinearFVBoundaryCondition")
205  .template condition<AttribVar>(0)
206  .template condition<AttribSysNum>(_cht_system_numbers[region_index])
207  .template condition<AttribBoundaries>(boundary_id)
208  .queryInto(bcs);
209 
210  if (bcs.size() != 1)
211  mooseError("We found multiple or no boundary conditions for solid energy on boundary ",
212  boundary_name,
213  " (ID: ",
214  boundary_id,
215  "). Make sure you define exactly one for conjugate heat transfer applications!");
216  _cht_boundary_conditions[bd_index][region_index] = bcs[0];
217 
218  if (!dynamic_cast<LinearFVCHTBCInterface *>(_cht_boundary_conditions[bd_index][region_index]))
219  mooseError("The selected boundary condition cannot be used with CHT problems! Make sure it "
220  "inherits from LinearFVCHTBCInterface!");
221  }
222  }
223 }
224 
225 void
227 {
228  // We already error in initialSetup if we have more variables
229  const auto * fluid_variable =
230  dynamic_cast<const MooseLinearVariableFVReal *>(&_energy_system->getVariable(0, 0));
231  const auto * solid_variable =
232  dynamic_cast<const MooseLinearVariableFVReal *>(&_solid_energy_system->getVariable(0, 0));
233 
234  _cht_face_info.clear();
235  _cht_face_info.resize(_cht_boundary_ids.size());
236  _boundary_heat_flux.clear();
237  _boundary_temperature.clear();
239 
240  for (const auto bd_index : index_range(_cht_boundary_ids))
241  {
242  const auto bd_id = _cht_boundary_ids[bd_index];
243  const auto & bd_name = _cht_boundary_names[bd_index];
244 
245  // We populate the face infos for every interface
246  auto & bd_fi_container = _cht_face_info[bd_index];
247  for (auto & fi : _problem.mesh().faceInfo())
248  if (fi->boundaryIDs().count(bd_id))
249  bd_fi_container.push_back(fi);
250 
251  // We do this because the coupling functors should be evaluated on both sides
252  // of the interface and there are rigorous checks if the functors don't support a subdomain
253  std::set<SubdomainID> combined_set;
254  std::set_union(solid_variable->blockIDs().begin(),
255  solid_variable->blockIDs().end(),
256  fluid_variable->blockIDs().begin(),
257  fluid_variable->blockIDs().end(),
258  std::inserter(combined_set, combined_set.begin()));
259 
260  // We instantiate the coupling fuctors for heat flux and temperature
262  _problem.mesh(), combined_set, "heat_flux_to_solid_" + bd_name);
264  _problem.mesh(), combined_set, "heat_flux_to_fluid_" + bd_name);
265 
266  _boundary_heat_flux.push_back(
267  std::vector<FaceCenteredMapFunctor<Real, std::unordered_map<dof_id_type, Real>>>(
268  {std::move(solid_bd_flux), std::move(fluid_bd_flux)}));
269  auto & flux_container = _boundary_heat_flux.back();
270 
271  _integrated_boundary_heat_flux.push_back(std::vector<Real>({0.0, 0.0}));
272 
274  _problem.mesh(), combined_set, "interface_temperature_solid_" + bd_name);
276  _problem.mesh(), combined_set, "interface_temperature_fluid_" + bd_name);
277 
278  _boundary_temperature.push_back(
279  std::vector<FaceCenteredMapFunctor<Real, std::unordered_map<dof_id_type, Real>>>(
280  {std::move(solid_bd_temperature), std::move(fluid_bd_temperature)}));
281  auto & temperature_container = _boundary_temperature.back();
282 
283  // Time to register the functors on all of the threads
284  for (const auto tid : make_range(libMesh::n_threads()))
285  {
286  _problem.addFunctor("heat_flux_to_solid_" + bd_name, flux_container[NS::CHTSide::SOLID], tid);
287  _problem.addFunctor("heat_flux_to_fluid_" + bd_name, flux_container[NS::CHTSide::FLUID], tid);
289  "interface_temperature_solid_" + bd_name, temperature_container[NS::CHTSide::SOLID], tid);
291  "interface_temperature_fluid_" + bd_name, temperature_container[NS::CHTSide::FLUID], tid);
292  }
293 
294  // Initialize the containers, they will be filled with correct values soon.
295  // Before any solve happens.
296  for (const auto region_index : make_range(2))
297  for (auto & fi : bd_fi_container)
298  {
299  flux_container[region_index][fi->id()] = 0.0;
300  temperature_container[region_index][fi->id()] = 0.0;
301  }
302  }
303 }
304 
305 void
307 {
308  for (const auto bd_index : index_range(_cht_boundary_ids))
309  {
310  const auto & bd_fi_container = _cht_face_info[bd_index];
311  auto & temperature_container = _boundary_temperature[bd_index];
312 
313  for (const auto region_index : make_range(2))
314  {
315  // Can't be const considering we will update members from here
316  auto bc = _cht_boundary_conditions[bd_index][region_index];
317  for (const auto & fi : bd_fi_container)
318  {
319  bc->setupFaceData(fi, fi->faceType(std::make_pair(0, _cht_system_numbers[region_index])));
320  temperature_container[1 - region_index][fi->id()] = bc->computeBoundaryValue();
321  }
322  }
323  }
324 }
325 
326 void
328 {
329  // Well we can just use the face that this enum casts into int very nicely
330  // we can use it to get the index of the other side
331  const NS::CHTSide other_side = static_cast<NS::CHTSide>(1 - side);
332 
333  for (const auto bd_index : index_range(_cht_boundary_ids))
334  {
335  auto & other_bc = _cht_boundary_conditions[bd_index][other_side];
336  auto & other_kernel = _cht_conduction_kernels[other_side];
337 
338  // We get the relaxation from the other side, so if we are fluid side we get the solid
339  // relaxation
340  const auto temperature_relaxation = _cht_flux_relaxation_factor[other_side][bd_index];
341  const auto flux_relaxation = _cht_temperature_relaxation_factor[other_side][bd_index];
342 
343  // Fetching the right container here, if side is fluid we fetch "heat_flux_to_fluid"
344  auto & flux_container = _boundary_heat_flux[bd_index][side];
345  // Fetching the other side's contaienr here, if side is fluid we fetch the solid temperature
346  auto & temperature_container = _boundary_temperature[bd_index][other_side];
347  // We will also update the integrated flux for output info
348  auto & integrated_flux = _integrated_boundary_heat_flux[bd_index][side];
349  // We are recomputing this so, time to zero this out
350  integrated_flux = 0.0;
351 
352  const auto & bd_fi_container = _cht_face_info[bd_index];
353 
354  // We enter the face loop to update the coupling fields
355  for (const auto & fi : bd_fi_container)
356  {
357  other_kernel->setupFaceData(fi);
358  // We will want the flux in W/m2 for the coupling so no face integral for now,
359  // this can cause issues if we start using face area in the kernels
360  // for more than just face integral multipliers.
361  // Also, if we decide to not require overlapping meshes on the boundary
362  // this will probably have to change.
363  other_kernel->setCurrentFaceArea(1.0);
364  other_bc->setupFaceData(fi, fi->faceType(std::make_pair(0, _cht_system_numbers[other_side])));
365 
366  // T_new = relaxation * T_boundary + (1-relaxation) * T_old
367  temperature_container[fi->id()] =
368  temperature_relaxation * other_bc->computeBoundaryValue() +
369  (1 - temperature_relaxation) * temperature_container[fi->id()];
370 
371  // Flux_new = relaxation * Flux_boundary + (1-relaxation) * Flux_old,
372  // minus sign is due to the normal differences
373  const auto flux = flux_relaxation * other_kernel->computeBoundaryFlux(*other_bc) +
374  (1 - flux_relaxation) * flux_container[fi->id()];
375 
376  flux_container[fi->id()] = flux;
377 
378  // We do the integral here
379  integrated_flux += flux * fi->faceArea() * fi->faceCoord();
380  }
381  }
382 }
383 
384 void
386 {
387  for (const auto i : index_range(_integrated_boundary_heat_flux))
388  {
389  auto & integrated_fluxes = _integrated_boundary_heat_flux[i];
390  _problem.comm().sum(integrated_fluxes[NS::CHTSide::SOLID]);
391  _problem.comm().sum(integrated_fluxes[NS::CHTSide::FLUID]);
392  }
393 }
394 
395 void
397 {
398  for (const auto i : index_range(_integrated_boundary_heat_flux))
399  {
400  auto & integrated_fluxes = _integrated_boundary_heat_flux[i];
401  _console << " Iteration " << _fpi_it << " Boundary " << _cht_boundary_names[i]
402  << " flux on solid side " << integrated_fluxes[NS::CHTSide::SOLID]
403  << " flux on fluid side: " << integrated_fluxes[NS::CHTSide::FLUID] << std::endl;
404  }
405 }
406 
407 void
409 {
410  for (const auto i : index_range(_integrated_boundary_heat_flux))
411  _integrated_boundary_heat_flux[i] = std::vector<Real>({0.0, 0.0});
412 }
413 
414 bool
416 {
417  if (_fpi_it >= _max_cht_fpi)
418  return true;
419 
420  for (const auto & boundary_flux : _integrated_boundary_heat_flux)
421  {
422  const Real f1 = boundary_flux[0];
423  const Real f2 = boundary_flux[1];
424 
425  // Special case: both are zero at startup not converged yet
426  if (_fpi_it != 0 && (f1 == 0.0 && f2 == 0.0))
427  return true;
428 
429  // These fluxes should be of opposite sign
430  const Real diff = std::abs(f1 + f2);
431  const Real denom = std::max({std::fabs(f1), std::fabs(f2), Real(1e-14)});
432  const Real rel_diff = diff / denom;
433 
434  if (rel_diff >= _cht_heat_flux_tolerance)
435  return false;
436  }
437 
438  return _fpi_it;
439 }
440 
441 } // End FV namespace
442 } // End Moose namespace
std::vector< unsigned int > _cht_system_numbers
The solid (0) and fluid (1) system numbers.
Definition: CHTHandler.h:108
void updateCHTBoundaryCouplingFields(const NS::CHTSide side)
Update the coupling fields for.
Definition: CHTHandler.C:327
unsigned int n_threads()
A functor whose evaluation relies on querying a map where the keys are face info ids and the values c...
void paramError(const std::string &param, Args... args) const
std::vector< BoundaryID > _cht_boundary_ids
The IDs of the CHT boundaries.
Definition: CHTHandler.h:91
FEProblemBase & _problem
Reference to FEProblem.
Definition: CHTHandler.h:76
void resetIntegratedFluxes()
Reset the heat fluxes to 0.
Definition: CHTHandler.C:408
void addFunctor(const std::string &name, const Moose::FunctorBase< T > &functor, const THREAD_ID tid)
MeshBase & mesh
void printIntegratedFluxes() const
Print the integrated heat fluxes.
Definition: CHTHandler.C:396
Definition: NS.h:197
const Parallel::Communicator & comm() const
void initializeCHTCouplingFields()
Initialize the coupling fields for the conjugate heat transfer routines.
Definition: CHTHandler.C:306
SystemBase * _energy_system
The energy system.
Definition: CHTHandler.h:82
void setupConjugateHeatTransferContainers()
Set up the boundary condition pairs, functor maps, and every other necessary structure for the conjug...
Definition: CHTHandler.C:226
MooseApp & getMooseApp() const
InputParameters emptyInputParameters()
std::vector< std::vector< FaceCenteredMapFunctor< Real, std::unordered_map< dof_id_type, Real > > > > _boundary_temperature
Functors describing the heat flux on the conjugate heat transfer interfaces.
Definition: CHTHandler.h:130
virtual unsigned int nVariables() const
virtual const std::string & name() const
const std::vector< const FaceInfo *> & faceInfo() const
std::vector< std::vector< Real > > _integrated_boundary_heat_flux
Integrated flux for the boundaries, first index is the boundary second is solid/fluid.
Definition: CHTHandler.h:125
const std::string & name() const
CHTSide
CHT side options, we want to make sure these can be used as integers so we are avoiding the enum clas...
Definition: NS.h:194
unsigned int _fpi_it
CHT fixed point iteration counter.
Definition: CHTHandler.h:134
void linkEnergySystems(SystemBase *solid_energy_system, SystemBase *fluid_energy_system)
Link energy systems.
Definition: CHTHandler.C:91
bool converged() const
Check if CHT iteration converged.
Definition: CHTHandler.C:415
std::vector< std::vector< const FaceInfo * > > _cht_face_info
The subset of the FaceInfo objects that belong to the given boundaries.
Definition: CHTHandler.h:111
std::vector< std::vector< Real > > _cht_temperature_relaxation_factor
The relaxation factors for temperature fields for the CHT boundaries first index is solid/fluid secon...
Definition: CHTHandler.h:105
const Real _cht_heat_flux_tolerance
Tolerance for heat flux at the CHT interfaces.
Definition: CHTHandler.h:97
std::vector< BoundaryID > getBoundaryIDs(const libMesh::MeshBase &mesh, const std::vector< BoundaryName > &boundary_name, bool generate_unknown, const std::set< BoundaryID > &mesh_boundary_ids)
unsigned int number() const
std::string stringify(const T &t)
void sumIntegratedFluxes()
Sum the integrated fluxes over all processors.
Definition: CHTHandler.C:385
SystemBase * _solid_energy_system
The solid energy system.
Definition: CHTHandler.h:85
std::vector< std::vector< FaceCenteredMapFunctor< Real, std::unordered_map< dof_id_type, Real > > > > _boundary_heat_flux
Functors describing the heat flux on the conjugate heat transfer interfaces.
Definition: CHTHandler.h:122
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
MooseApp & _app
std::vector< BoundaryName > _cht_boundary_names
The names of the CHT boundaries.
Definition: CHTHandler.h:88
Query query()
IntRange< T > make_range(T beg, T end)
virtual MooseMesh & mesh() override
void mooseError(Args &&... args) const
void deduceCHTBoundaryCoupling()
Run error checks and make sure everything works.
Definition: CHTHandler.C:103
const std::vector< VariableName > & getVariableNames() const
TheWarehouse & theWarehouse()
const ConsoleStream _console
static InputParameters validParams()
Definition: CHTHandler.C:25
MooseVariableFieldBase & getVariable(THREAD_ID tid, const std::string &var_name) const
std::vector< std::vector< LinearFVBoundaryCondition * > > _cht_boundary_conditions
Vector of boundary conditions that describe the conjugate heat transfer from each side...
Definition: CHTHandler.h:117
std::vector< std::vector< Real > > _cht_flux_relaxation_factor
The relaxation factors for flux fields for the CHT boundaries first index is solid/fluid second is th...
Definition: CHTHandler.h:101
bool isParamSetByUser(const std::string &name) const
std::vector< LinearFVFluxKernel * > _cht_conduction_kernels
The conduction kernels from the solid/fluid domains. Can&#39;t be const, considering we are updating the ...
Definition: CHTHandler.h:114
const unsigned int _max_cht_fpi
Maximum number of CHT fixed point iterations.
Definition: CHTHandler.h:94
void ErrorVector unsigned int
auto index_range(const T &sizable)
CHTHandler(const InputParameters &parameters)
Constructor with initialization parameters.
Definition: CHTHandler.C:76
Definition: NS.h:196