https://mooseframework.inl.gov
Loading...
Searching...
No Matches
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"
17#include "FEProblemBase.h"
19
20namespace NS
21{
22namespace FV
23{
24
27{
28 auto params = emptyInputParameters();
31 params.addParam<std::vector<BoundaryName>>(
32 "cht_interfaces",
33 {},
34 "The interfaces where we would like to add conjugate heat transfer handling.");
35
36 params.addRangeCheckedParam<unsigned int>(
37 "max_cht_fpi",
38 1,
39 "max_cht_fpi >= 1",
40 "Number of maximum fixed point iterations (FPI). Currently only applied to"
41 " conjugate heat transfer simulations. The default value of 1 essentially keeps"
42 " the FPI feature turned off. CHT iteration ends after this number of iteration even if the "
43 "tolerance is not met.");
44
45 params.addRangeCheckedParam<Real>(
46 "cht_heat_flux_tolerance",
47 1e-5,
48 "cht_heat_flux_tolerance > 0 & cht_heat_flux_tolerance <= 1.0",
49 "The relative tolerance for terminating conjugate heat transfer iteration before the maximum "
50 "number of CHT iterations. Relative tolerance is ignore if the maximum number of CHT "
51 "iterations is reached.");
52
53 params.addParam<std::vector<Real>>(
54 "cht_fluid_temperature_relaxation",
55 {},
56 "The relaxation factors for the boundary temperature when being updated on the fluid side.");
57 params.addParam<std::vector<Real>>(
58 "cht_solid_temperature_relaxation",
59 {},
60 "The relaxation factors for the boundary temperature when being updated on the solid side.");
61 params.addParam<std::vector<Real>>(
62 "cht_fluid_flux_relaxation",
63 {},
64 "The relaxation factors for the boundary flux when being updated on the fluid side.");
65 params.addParam<std::vector<Real>>(
66 "cht_solid_flux_relaxation",
67 {},
68 "The relaxation factors for the boundary flux when being updated on the solid side.");
69 params.addParam<UserObjectName>(
70 "surface_radiation_object_name",
71 "Name of the Gray-Lambert surface-radiation user object. On matching CHT interfaces, "
72 "its net outward heat flux density is removed from the heat flux transferred to the "
73 "receiving domain.");
74
75 params.addParam<std::vector<MooseFunctorName>>(
76 "thermal_resistance",
77 std::vector<MooseFunctorName>({"0"}),
78 "The custom area-normalized thermal resistance at each interface, in m^2*K/W. "
79 "Provide one value to use for all CHT interfaces or one value per entry in "
80 "cht_interfaces.");
81
82 params.addParamNamesToGroup(
83 "cht_interfaces max_cht_fpi cht_heat_flux_tolerance cht_fluid_temperature_relaxation "
84 "cht_solid_temperature_relaxation cht_fluid_flux_relaxation "
85 "cht_solid_flux_relaxation surface_radiation_object_name thermal_resistance",
86 "Conjugate Heat Transfer");
87
88 return params;
89}
90
92 : MooseObject(params),
95 _problem(*getCheckedPointerParam<FEProblemBase *>(
96 "_fe_problem_base", "This might happen if you don't have a mesh")),
97 _mesh(_problem.mesh()),
98 _cht_boundary_names(getParam<std::vector<BoundaryName>>("cht_interfaces")),
99 _cht_boundary_ids(_mesh.getBoundaryIDs(_cht_boundary_names)),
100 _max_cht_fpi(getParam<unsigned int>("max_cht_fpi")),
101 _cht_heat_flux_tolerance(getParam<Real>("cht_heat_flux_tolerance")),
102 _surface_radiation_uo(nullptr)
103{
104 if (isParamSetByUser("cht_interfaces") && !_cht_boundary_names.size())
105 paramError("cht_interfaces", "You must declare at least one interface!");
106 if (isParamValid("surface_radiation_object_name") && _cht_boundary_names.empty())
107 paramError("surface_radiation_object_name",
108 "Surface radiation coupling requires at least one entry in 'cht_interfaces'.");
109
110 const auto & thermal_resistance_names =
111 getParam<std::vector<MooseFunctorName>>("thermal_resistance");
112 if (thermal_resistance_names.size() != 1 &&
113 thermal_resistance_names.size() != _cht_boundary_names.size())
114 paramError("thermal_resistance",
115 "Provide either one thermal resistance for all CHT interfaces or one value per "
116 "entry in cht_interfaces.");
117
119 for (const auto bd_index : index_range(_cht_boundary_names))
120 {
121 const auto & thermal_resistance_name = thermal_resistance_names.size() == 1
122 ? thermal_resistance_names[0]
123 : thermal_resistance_names[bd_index];
124 _thermal_resistance.push_back(&getFunctorByName<Real>(thermal_resistance_name));
125 }
126}
127
128void
130 SystemBase * fluid_energy_system,
131 std::vector<SystemBase *> pm_radiation_systems)
132{
133 _energy_system = fluid_energy_system;
134 _solid_energy_system = solid_energy_system;
135 _pm_radiation_systems = pm_radiation_systems;
136
138 paramError("cht_interfaces",
139 "You selected to do conjugate heat transfer treatment, but it needs two energy "
140 "systems: a solid and a fluid. One of these systems is missing.");
141}
142
143void
145{
146 // CHTHandler is constructed with the segregated solve object, potentially before user objects
147 // exist. Resolve the optional surface-radiation object here, during initial setup.
148 _surface_radiation_uo = nullptr;
150 if (isParamValid("surface_radiation_object_name"))
151 {
153 &getUserObject<GrayLambertSurfaceRadiationBase>("surface_radiation_object_name");
155
156 const bool has_cht_surface =
157 std::any_of(_cht_boundary_ids.begin(),
158 _cht_boundary_ids.end(),
159 [this](const auto boundary_id)
160 { return _surface_radiation_boundary_ids.count(boundary_id); });
161
162 if (!has_cht_surface)
163 paramError("surface_radiation_object_name",
164 "The supplied surface-radiation user object does not contain any of the "
165 "boundaries listed in 'cht_interfaces'.");
166 }
167
169 mooseError("We should have only one variable in the solid energy system: ",
171 "! Right now we have: ",
173 if (_energy_system->nVariables() != 1)
174 mooseError("We should have only one variable in the fluid energy system: ",
176 "! Right now we have: ",
178 const std::vector<std::string> solid_fluid({"solid", "fluid"});
179
180 // We do some setup at the beginning to make sure the container sizes are good
182 std::vector<unsigned int>({_solid_energy_system->number(), _energy_system->number()});
183 _cht_conduction_kernels = std::vector<LinearFVFluxKernel *>({nullptr, nullptr});
185 _cht_boundary_conditions.resize(_cht_boundary_names.size(), {nullptr, nullptr});
186
187 // Populate the PM radiation system numbers
188 if (!_pm_radiation_systems.empty())
189 {
190 for (const auto sys_i : index_range(_pm_radiation_systems))
192
193 // Reserve space for _cht_pm_radiation_kernels based on the size of
194 // _cht_pm_radiation_system_numbers
196 // Reserve space for pm radiation boundary conditions
199 _cht_boundary_names.size(),
200 std::vector<LinearFVBoundaryCondition *>(_cht_pm_radiation_system_numbers.size(), nullptr));
201 }
202
203 const auto flux_relaxation_param_names =
204 std::vector<std::string>({"cht_solid_flux_relaxation", "cht_fluid_flux_relaxation"});
205 const auto temperature_relaxation_param_names = std::vector<std::string>(
206 {"cht_solid_temperature_relaxation", "cht_fluid_temperature_relaxation"});
208 _cht_flux_relaxation_factor.resize(2, std::vector<Real>(_cht_boundary_names.size(), 1.0));
210 _cht_temperature_relaxation_factor.resize(2, std::vector<Real>(_cht_boundary_names.size(), 1.0));
211
212 for (const auto region_index : index_range(solid_fluid))
213 {
214 // First thing, we fetch the relaxation parameter values
215 const auto & flux_param_value =
216 getParam<std::vector<Real>>(flux_relaxation_param_names[region_index]);
217 if (flux_param_value.empty() || (flux_param_value.size() != _cht_boundary_names.size()))
218 paramError(flux_relaxation_param_names[region_index],
219 "The number of relaxation factors is not the same as the number of interfaces!");
220
221 _cht_flux_relaxation_factor[region_index] = flux_param_value;
222 // We have to do the range check here because the intput parameter check errors if the vector is
223 // empty
224 for (const auto param : _cht_flux_relaxation_factor[region_index])
225 if (param <= 0 || param > 1.0)
226 paramError(flux_relaxation_param_names[region_index],
227 "The relaxation parameter should be between 0 and 1!");
228
229 const auto & temperature_param_value =
230 getParam<std::vector<Real>>(temperature_relaxation_param_names[region_index]);
231 if (temperature_param_value.empty() ||
232 (temperature_param_value.size() != _cht_boundary_names.size()))
233 paramError(temperature_relaxation_param_names[region_index],
234 "The number of relaxation factors is not the same as the number of interfaces!");
235
236 _cht_temperature_relaxation_factor[region_index] = temperature_param_value;
237 // We have to do the range check here because the intput parameter check errors if the vector is
238 // empty
239 for (const auto param : _cht_temperature_relaxation_factor[region_index])
240 if (param <= 0 || param > 1.0)
241 paramError(temperature_relaxation_param_names[region_index],
242 "The relaxation parameter should be between 0 and 1!");
243
244 // We then fetch the conduction kernels
245 std::vector<LinearFVFluxKernel *> flux_kernels;
247 .query()
248 .template condition<AttribSystem>("LinearFVFluxKernel")
249 .template condition<AttribVar>(0)
250 .template condition<AttribSysNum>(_cht_system_numbers[region_index])
251 .queryInto(flux_kernels);
252
253 // We then fetch the radiation conduction kernels in the fluid region
254 if (!_pm_radiation_systems.empty() && region_index == 1)
255 for (const auto sys_i : index_range(_pm_radiation_systems))
256 {
257 // We then fetch the radiation conduction kernels
258 std::vector<LinearFVFluxKernel *> radiation_kernels;
260 .query()
261 .template condition<AttribSystem>("LinearFVFluxKernel")
262 .template condition<AttribVar>(0)
263 .template condition<AttribSysNum>(_cht_pm_radiation_system_numbers[sys_i])
264 .queryInto(radiation_kernels);
265
266 if (radiation_kernels.size() > 1)
268 "We already have a kernel that describes the participating media radiation diffusion "
269 "with the name: ",
270 radiation_kernels[0]->name(),
271 ". Make sure that you have only one conduction kernel.");
272 else if (radiation_kernels.empty())
273 mooseError("We did not find a diffusion kernel for the participating media radiation "
274 "diffusion to compute the "
275 "radiative heat flux. Please add a diffusion kernel.");
276 else
277 _cht_pm_radiation_kernels.push_back(radiation_kernels[0]);
278 }
279
280 for (auto kernel : flux_kernels)
281 {
282 auto check_diff = dynamic_cast<LinearFVDiffusion *>(kernel);
283 auto check_aniso_diff = dynamic_cast<LinearFVAnisotropicDiffusion *>(kernel);
284 if (_cht_conduction_kernels[region_index] && (check_diff || check_aniso_diff))
285 mooseError("We already have a kernel that describes the heat conduction for the ",
286 solid_fluid[region_index],
287 " domain: ",
288 _cht_conduction_kernels[region_index]->name(),
289 " We found another one with the name: ",
290 (check_diff ? check_diff->name() : check_aniso_diff->name()),
291 " Make sure that you have only one conduction kernel on the ",
292 solid_fluid[region_index],
293 " side!");
294
295 if (check_diff || check_aniso_diff)
296 _cht_conduction_kernels[region_index] = kernel;
297 }
298
299 // Then we check the boundary conditions, to make sure at least there is something defined
300 // from both sides
301 for (const auto bd_index : index_range(_cht_boundary_names))
302 {
303 const auto & boundary_name = _cht_boundary_names[bd_index];
304 const auto boundary_id = _cht_boundary_ids[bd_index];
305
306 std::vector<LinearFVBoundaryCondition *> bcs;
308 .theWarehouse()
309 .query()
310 .template condition<AttribSystem>("LinearFVBoundaryCondition")
311 .template condition<AttribVar>(0)
312 .template condition<AttribSysNum>(_cht_system_numbers[region_index])
313 .template condition<AttribBoundaries>(boundary_id)
314 .queryInto(bcs);
315
316 // We then fetch the radiation conduction bcs in the fluid region (i.e MarshakBC in P1)
317 if (!_pm_radiation_systems.empty() && region_index == 1)
318 for (const auto sys_i : index_range(_pm_radiation_systems))
319 {
320 std::vector<LinearFVBoundaryCondition *> rad_bcs;
322 .query()
323 .template condition<AttribSystem>("LinearFVBoundaryCondition")
324 .template condition<AttribVar>(0)
325 .template condition<AttribSysNum>(_cht_pm_radiation_system_numbers[sys_i])
326 .template condition<AttribBoundaries>(boundary_id)
327 .queryInto(rad_bcs);
328
329 if (!rad_bcs.empty())
330 _cht_pm_radiation_boundary_conditions[bd_index][sys_i] = rad_bcs[0];
331 else
332 mooseError("No LinearFVBoundaryCondition found for the given boundary or system.");
333 }
334
335 if (bcs.size() != 1)
336 mooseError("We found multiple or no boundary conditions for solid energy on boundary ",
337 boundary_name,
338 " (ID: ",
339 boundary_id,
340 "). Make sure you define exactly one for conjugate heat transfer applications!");
341 _cht_boundary_conditions[bd_index][region_index] = bcs[0];
342
343 if (!dynamic_cast<LinearFVCHTBCInterface *>(_cht_boundary_conditions[bd_index][region_index]))
344 mooseError("The selected boundary condition cannot be used with CHT problems! Make sure it "
345 "inherits from LinearFVCHTBCInterface!");
346 }
347 }
348}
349
350void
352{
353 // We already error in initialSetup if we have more variables
355 dynamic_cast<const MooseLinearVariableFVReal *>(&_energy_system->getVariable(0, 0));
357 dynamic_cast<const MooseLinearVariableFVReal *>(&_solid_energy_system->getVariable(0, 0));
358
359 _cht_face_info.clear();
360 _cht_face_info.resize(_cht_boundary_ids.size());
361 _boundary_heat_flux.clear();
362 _boundary_temperature.clear();
365
366 for (const auto bd_index : index_range(_cht_boundary_ids))
367 {
368 const auto bd_id = _cht_boundary_ids[bd_index];
369 const auto & bd_name = _cht_boundary_names[bd_index];
370
371 // We populate the face infos for every interface
372 auto & bd_fi_container = _cht_face_info[bd_index];
373 for (auto & fi : _problem.mesh().faceInfo())
374 if (fi->boundaryIDs().count(bd_id))
375 bd_fi_container.push_back(fi);
376
377 // We do this because the coupling functors should be evaluated on both sides
378 // of the interface and there are rigorous checks if the functors don't support a subdomain
379 std::set<SubdomainID> combined_set;
380 std::set_union(_solid_variable->blockIDs().begin(),
381 _solid_variable->blockIDs().end(),
382 _fluid_variable->blockIDs().begin(),
383 _fluid_variable->blockIDs().end(),
384 std::inserter(combined_set, combined_set.begin()));
385
386 // We instantiate the coupling fuctors for heat flux and temperature
388 _problem.mesh(), combined_set, "heat_flux_to_solid_" + bd_name);
390 _problem.mesh(), combined_set, "heat_flux_to_fluid_" + bd_name);
391
392 _boundary_heat_flux.push_back(
393 std::vector<FaceCenteredMapFunctor<Real, std::unordered_map<dof_id_type, Real>>>(
394 {std::move(solid_bd_flux), std::move(fluid_bd_flux)}));
395 auto & flux_container = _boundary_heat_flux.back();
396
397 _integrated_boundary_heat_flux.push_back(std::vector<Real>({0.0, 0.0}));
400
402 _problem.mesh(), combined_set, "interface_temperature_to_solid_" + bd_name);
404 _problem.mesh(), combined_set, "interface_temperature_to_fluid_" + bd_name);
405
406 _boundary_temperature.push_back(
407 std::vector<FaceCenteredMapFunctor<Real, std::unordered_map<dof_id_type, Real>>>(
408 {std::move(solid_bd_temperature), std::move(fluid_bd_temperature)}));
409 auto & temperature_container = _boundary_temperature.back();
410
411 // Time to register the functors on all of the threads
412 for (const auto tid : make_range(_problem.numThreads()))
413 {
414 _problem.addFunctor("heat_flux_to_solid_" + bd_name, flux_container[NS::CHTSide::SOLID], tid);
415 _problem.addFunctor("heat_flux_to_fluid_" + bd_name, flux_container[NS::CHTSide::FLUID], tid);
416 _problem.addFunctor("interface_temperature_to_solid_" + bd_name,
417 temperature_container[NS::CHTSide::SOLID],
418 tid);
419 _problem.addFunctor("interface_temperature_to_fluid_" + bd_name,
420 temperature_container[NS::CHTSide::FLUID],
421 tid);
422 }
423
424 // Initialize the containers, they will be filled with correct values soon.
425 // Before any solve happens.
426 for (const auto region_index : make_range(2))
427 for (auto & fi : bd_fi_container)
428 {
429 flux_container[region_index][fi->id()] = 0.0;
430 temperature_container[region_index][fi->id()] = 0.0;
431 }
432 }
433}
434
435void
437{
438 // We seed the coupling fields directly from the current solution field on each side of the
439 // interface, using the raw cell value adjacent to the face.
440
441 for (const auto bd_index : index_range(_cht_boundary_ids))
442 {
443 const auto & bd_fi_container = _cht_face_info[bd_index];
444 auto & temperature_container = _boundary_temperature[bd_index];
445
446 for (const auto & fi : bd_fi_container)
447 {
448 const bool solid_on_elem = _solid_variable->hasFaceSide(*fi, true);
449 const auto & solid_elem_info = solid_on_elem ? *fi->elemInfo() : *fi->neighborInfo();
450 const Real solid_face_value =
452
453 const bool fluid_on_elem = _fluid_variable->hasFaceSide(*fi, true);
454 const auto & fluid_elem_info = fluid_on_elem ? *fi->elemInfo() : *fi->neighborInfo();
455 const Real fluid_face_value =
457
458 temperature_container[NS::CHTSide::FLUID][fi->id()] = solid_face_value;
459 temperature_container[NS::CHTSide::SOLID][fi->id()] = fluid_face_value;
460 }
461 }
462}
463
464void
466{
467 // Well we can just use the face that this enum casts into int very nicely
468 // we can use it to get the index of the other side
469 const NS::CHTSide other_side = static_cast<NS::CHTSide>(1 - side);
470
471 for (const auto bd_index : index_range(_cht_boundary_ids))
472 {
473 auto & other_bc = _cht_boundary_conditions[bd_index][other_side];
474 auto & other_kernel = _cht_conduction_kernels[other_side];
475
476 // We get the relaxation from the other side, so if we are fluid side we get the solid
477 // relaxation. Use each field's matching relaxation-factor family.
478 const auto temperature_relaxation = _cht_temperature_relaxation_factor[other_side][bd_index];
479 const auto flux_relaxation = _cht_flux_relaxation_factor[other_side][bd_index];
480
481 // Fetching the right container here, if side is fluid we fetch "heat_flux_to_fluid"
482 auto & flux_container = _boundary_heat_flux[bd_index][side];
483 // Fetch the effective interface temperature supplied to this side.
484 auto & temperature_container = _boundary_temperature[bd_index][side];
485 // We will also update the integrated flux for output info
486 auto & integrated_flux = _integrated_boundary_heat_flux[bd_index][side];
487 // We are recomputing this so, time to zero this out
488 integrated_flux = 0.0;
489
490 // GrayLambertSurfaceRadiationBase returns one sideset-averaged net outward flux density.
491 // It is therefore constant over all FaceInfo objects belonging to this CHT patch.
492 Real surface_radiation_flux = 0.0;
494 {
497 surface_radiation_flux =
499 }
500
501 const auto & bd_fi_container = _cht_face_info[bd_index];
502
503 // We enter the face loop to update the coupling fields
504 for (const auto & fi : bd_fi_container)
505 {
506 other_kernel->setupFaceData(fi);
507 // We will want the flux in W/m2 for the coupling so no face integral for now,
508 // this can cause issues if we start using face area in the kernels
509 // for more than just face integral multipliers.
510 // Also, if we decide to not require overlapping meshes on the boundary
511 // this will probably have to change.
512 other_kernel->setCurrentFaceArea(1.0);
513 other_bc->setupFaceData(fi, fi->faceType(std::make_pair(0, _cht_system_numbers[other_side])));
514
515 const auto boundary_temperature = other_bc->computeBoundaryValue();
516
517 const auto & resistance_functor = *_thermal_resistance[bd_index];
518 const auto on_elem = resistance_functor.hasFaceSide(*fi, true);
519 const auto on_neighbor = resistance_functor.hasFaceSide(*fi, false);
520
521 if (!on_elem && !on_neighbor)
522 mooseError("The thermal resistance functor '",
523 resistance_functor.functorName(),
524 "' is not defined on either side of CHT interface '",
525 _cht_boundary_names[bd_index],
526 "'.");
527
528 auto resistance_face_arg = Moose::FaceArg{
529 fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr, nullptr};
530
531 if (on_elem != on_neighbor)
532 resistance_face_arg.face_side = on_elem ? fi->elemPtr() : fi->neighborPtr();
533
534 const auto thermal_resistance =
535 resistance_functor(resistance_face_arg, Moose::currentState());
536
537 if (thermal_resistance < 0.0)
538 paramError("thermal_resistance", "Thermal resistance must be non-negative.");
539
540 // Flux_new = relaxation * Flux_boundary + (1-relaxation) * Flux_old,
541 // minus sign is due to the normal differences
542
543 // Conductive flux
544 auto source_flux = other_kernel->computeBoundaryFlux(*other_bc);
545
546 // If participating media radiation system exists we add the heat flux from the fluid
547 // to the solid region.
548 if (!_pm_radiation_systems.empty() && side == NS::CHTSide::SOLID)
549 for (const auto sys_i : index_range(_pm_radiation_systems))
550 {
551 _cht_pm_radiation_kernels[sys_i]->setupFaceData(fi);
552 _cht_pm_radiation_kernels[sys_i]->setCurrentFaceArea(1.0);
553 _cht_pm_radiation_boundary_conditions[bd_index][sys_i]->setupFaceData(
554 fi, fi->faceType(std::make_pair(0, _cht_pm_radiation_system_numbers[sys_i])));
555 source_flux += _cht_pm_radiation_kernels[sys_i]->computeBoundaryFlux(
556 *_cht_pm_radiation_boundary_conditions[bd_index][sys_i]);
557 }
558
559 // source_flux is positive outward from the source domain, while surface_radiation_flux is
560 // positive outward from the solid. The coupling functor is positive into the receiving
561 // domain, so subtract the surface-to-surface radiation that bypasses the transparent fluid.
562 const Real coupling_flux = source_flux - surface_radiation_flux;
563 const auto relaxed_flux =
564 flux_relaxation * coupling_flux + (1 - flux_relaxation) * flux_container[fi->id()];
565 flux_container[fi->id()] = relaxed_flux;
566
567 // Store the temperature seen by this side after the thermal resistance drop.
568 // The minus sign matches the source-side outward-flux convention used here.
569 temperature_container[fi->id()] =
570 temperature_relaxation * (boundary_temperature - thermal_resistance * relaxed_flux) +
571 (1 - temperature_relaxation) * temperature_container[fi->id()];
572
573 // Integrate the source-domain and surface-radiation fluxes separately. This avoids counting
574 // surface radiation twice when coupling fields are updated in both directions.
575 const Real coordinate_area = fi->faceArea() * fi->faceCoord();
576 integrated_flux += source_flux * coordinate_area;
579 surface_radiation_flux * coordinate_area;
580 }
581 }
582}
583
584void
586{
587 for (const auto i : index_range(_integrated_boundary_heat_flux))
588 {
589 auto & integrated_fluxes = _integrated_boundary_heat_flux[i];
590 _problem.comm().sum(integrated_fluxes[NS::CHTSide::SOLID]);
591 _problem.comm().sum(integrated_fluxes[NS::CHTSide::FLUID]);
594 }
595}
596
597void
599{
600 for (const auto i : index_range(_integrated_boundary_heat_flux))
601 {
602 auto & integrated_fluxes = _integrated_boundary_heat_flux[i];
603 _console << " Iteration " << _fpi_it << " Boundary " << _cht_boundary_names[i]
604 << " flux on solid side " << integrated_fluxes[NS::CHTSide::SOLID]
605 << " flux on fluid side: " << integrated_fluxes[NS::CHTSide::FLUID];
607 _console << " net outward surface-radiation flux: "
609 _console << std::endl;
610 }
611}
612
613void
615{
616 for (const auto i : index_range(_integrated_boundary_heat_flux))
617 {
618 _integrated_boundary_heat_flux[i] = std::vector<Real>({0.0, 0.0});
621 }
622}
623
624bool
626{
627 if (_fpi_it >= _max_cht_fpi)
628 return true;
629
630 for (const auto i : index_range(_integrated_boundary_heat_flux))
631 {
632 const auto & boundary_flux = _integrated_boundary_heat_flux[i];
633 const Real f1 = boundary_flux[0];
634 const Real f2 = boundary_flux[1];
635 const Real radiation_flux =
637
638 // An interface whose fluxes are all zero after the first iteration is balanced. Skip it so
639 // that the remaining interfaces are still checked.
640 if (_fpi_it != 0 && f1 == 0.0 && f2 == 0.0 && radiation_flux == 0.0)
641 continue;
642
643 // Surface radiation leaves the solid but is not deposited in a transparent fluid, giving the
644 // interface balance Q_s,out + Q_f,out - Q_rad,out = 0.
645 const Real diff = std::abs(f1 + f2 - radiation_flux);
646 const Real denom =
647 std::max({std::fabs(f1), std::fabs(f2), std::fabs(radiation_flux), Real(1e-14)});
648 const Real rel_diff = diff / denom;
649
650 if (rel_diff >= _cht_heat_flux_tolerance)
651 return false;
652 }
653
654 return _fpi_it;
655}
656
657} // End FV namespace
658} // End Moose namespace
InputParameters emptyInputParameters()
void ErrorVector unsigned int
virtual const std::set< SubdomainID > & blockIDs() const
const ConsoleStream _console
virtual MooseMesh & mesh() override
A functor whose evaluation relies on querying a map where the keys are face info ids and the values c...
Base class that allows error checking for CHT applications.
TheWarehouse & theWarehouse()
const std::string & name() const
void paramError(const std::string &param, Args... args) const
bool isParamSetByUser(const std::string &name) const
void mooseError(Args &&... args) const
bool isParamValid(const std::string &name) const
MooseApp & getMooseApp() const
Real getElemValue(const ElemInfo &elem_info, const StateArg &state) const
const std::vector< const FaceInfo * > & faceInfo() const
MooseApp & _app
virtual bool hasFaceSide(const FaceInfo &fi, const bool fi_elem_side) const override
const Real _cht_heat_flux_tolerance
Tolerance for heat flux at the CHT interfaces.
Definition CHTHandler.h:114
std::vector< BoundaryName > _cht_boundary_names
The names of the CHT boundaries.
Definition CHTHandler.h:105
std::vector< Real > _integrated_boundary_surface_radiation_heat_flux
Integrated net outward surface-radiation flux, kept separate for the CHT energy balance.
Definition CHTHandler.h:164
void sumIntegratedFluxes()
Sum the integrated fluxes over all processors.
Definition CHTHandler.C:585
SystemBase * _energy_system
The energy system.
Definition CHTHandler.h:90
std::vector< unsigned int > _cht_pm_radiation_system_numbers
The participating media radiation system numbers.
Definition CHTHandler.h:137
std::vector< LinearFVFluxKernel * > _cht_conduction_kernels
The conduction kernels from the solid/fluid domains. Can't be const, considering we are updating the ...
Definition CHTHandler.h:143
void printIntegratedFluxes() const
Print the integrated heat fluxes.
Definition CHTHandler.C:598
std::vector< unsigned int > _cht_system_numbers
The solid (0) and fluid (1) system numbers.
Definition CHTHandler.h:134
std::vector< LinearFVFluxKernel * > _cht_pm_radiation_kernels
The conduction radiation kernels from the fluid domains.
Definition CHTHandler.h:146
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:127
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:157
SystemBase * _solid_energy_system
The solid energy system.
Definition CHTHandler.h:93
std::vector< std::vector< const FaceInfo * > > _cht_face_info
The subset of the FaceInfo objects that belong to the given boundaries.
Definition CHTHandler.h:140
std::vector< SystemBase * > _pm_radiation_systems
The solid energy system.
Definition CHTHandler.h:96
void resetIntegratedFluxes()
Reset the heat fluxes to 0.
Definition CHTHandler.C:614
void initializeCHTCouplingFields()
Initialize the coupling fields for the conjugate heat transfer routines.
Definition CHTHandler.C:436
CHTHandler(const InputParameters &parameters)
Constructor with initialization parameters.
Definition CHTHandler.C:91
std::vector< std::vector< Real > > _integrated_boundary_heat_flux
Integrated source-domain flux for each boundary and solid/fluid transfer direction.
Definition CHTHandler.h:160
std::vector< std::vector< LinearFVBoundaryCondition * > > _cht_boundary_conditions
Vector of boundary conditions that describe the conjugate heat transfer from each side.
Definition CHTHandler.h:149
std::vector< std::vector< LinearFVBoundaryCondition * > > _cht_pm_radiation_boundary_conditions
Vector of boundary conditions that describe the radiation pm bcs from each side.
Definition CHTHandler.h:152
void deduceCHTBoundaryCoupling()
Run error checks and make sure everything works.
Definition CHTHandler.C:144
bool converged() const
Check if CHT iteration converged.
Definition CHTHandler.C:625
std::set< BoundaryID > _surface_radiation_boundary_ids
Boundaries represented by the surface-to-surface radiation model.
Definition CHTHandler.h:120
void setupConjugateHeatTransferContainers()
Set up the boundary condition pairs, functor maps, and every other necessary structure for the conjug...
Definition CHTHandler.C:351
std::vector< std::vector< FaceCenteredMapFunctor< Real, std::unordered_map< dof_id_type, Real > > > > _boundary_temperature
Functors describing the raw wall temperatures on the conjugate heat transfer interfaces.
Definition CHTHandler.h:169
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:131
std::vector< BoundaryID > _cht_boundary_ids
The IDs of the CHT boundaries.
Definition CHTHandler.h:108
const MooseLinearVariableFVReal * _solid_variable
The solid-side temperature variable.
Definition CHTHandler.h:102
static InputParameters validParams()
Definition CHTHandler.C:26
const MooseLinearVariableFVReal * _fluid_variable
The fluid-side temperature variable.
Definition CHTHandler.h:99
FEProblemBase & _problem
Reference to FEProblem.
Definition CHTHandler.h:84
std::vector< const Moose::Functor< Real > * > _thermal_resistance
Thermal resistance functors, one per CHT interface.
Definition CHTHandler.h:123
void updateCHTBoundaryCouplingFields(const NS::CHTSide side)
Update the coupling fields for.
Definition CHTHandler.C:465
unsigned int _fpi_it
CHT fixed point iteration counter.
Definition CHTHandler.h:178
void linkEnergySystems(SystemBase *solid_energy_system, SystemBase *fluid_energy_system, std::vector< SystemBase * > pm_radiation_systems)
Link energy systems.
Definition CHTHandler.C:129
const unsigned int _max_cht_fpi
Maximum number of CHT fixed point iterations.
Definition CHTHandler.h:111
const GrayLambertSurfaceRadiationBase * _surface_radiation_uo
Optional surface-to-surface radiation model supplying net outward wall heat fluxes.
Definition CHTHandler.h:117
static InputParameters validParams()
THREAD_ID numThreads() const
void addFunctor(const std::string &name, const Moose::FunctorBase< T > &functor, const THREAD_ID tid)
virtual unsigned int nVariables() const
MooseVariableFieldBase & getVariable(THREAD_ID tid, const std::string &var_name) const
unsigned int number() const
const std::vector< VariableName > & getVariableNames() const
virtual const std::string & name() const
Query query()
static InputParameters validParams()
const Parallel::Communicator & comm() const
MeshBase & mesh
std::string stringify(const T &t)
StateArg currentState()
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:199
@ SOLID
Definition NS.h:200
@ FLUID
Definition NS.h:201
const libMesh::Elem * face_side