https://mooseframework.inl.gov
Loading...
Searching...
No Matches
LinearAssemblySegregatedSolve.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 "FEProblem.h"
13#include "LinearSystem.h"
14#include "Executioner.h"
15
16using namespace libMesh;
17
20{
22
23 params.addParam<std::vector<SolverSystemName>>(
24 "active_scalar_systems", {}, "The solver system for each active scalar advection equation.");
25
26 /*
27 * Parameters to control the solution of each scalar advection system
28 */
29 params.addParam<std::vector<Real>>("active_scalar_equation_relaxation",
30 std::vector<Real>(),
31 "The relaxation which should be used for the active scalar "
32 "equations. (=1 for no relaxation, "
33 "diagonal dominance will still be enforced)");
34
35 params.addParam<MultiMooseEnum>("active_scalar_petsc_options",
37 "Singleton PETSc options for the active scalar equation(s)");
39 "active_scalar_petsc_options_iname",
41 "Names of PETSc name/value pairs for the active scalar equation(s)");
42 params.addParam<std::vector<std::string>>(
43 "active_scalar_petsc_options_value",
44 "Values of PETSc name/value pairs (must correspond with \"petsc_options_iname\" for the "
45 "active scalar equation(s)");
46 params.addParam<std::vector<Real>>(
47 "active_scalar_absolute_tolerance",
48 std::vector<Real>(),
49 "The absolute tolerance(s) on the normalized residual(s) of the active scalar equation(s).");
50 params.addRangeCheckedParam<Real>("active_scalar_l_tol",
51 1e-5,
52 "0.0<=active_scalar_l_tol & active_scalar_l_tol<1.0",
53 "The relative tolerance on the normalized residual in the "
54 "linear solver of the active scalar equation(s).");
55 params.addRangeCheckedParam<Real>("active_scalar_l_abs_tol",
56 1e-10,
57 "0.0<active_scalar_l_abs_tol",
58 "The absolute tolerance on the normalized residual in the "
59 "linear solver of the active scalar equation(s).");
60 params.addParam<unsigned int>(
61 "active_scalar_l_max_its",
62 10000,
63 "The maximum allowed iterations in the linear solver of the turbulence equation.");
64
66 "active_scalar_systems active_scalar_equation_relaxation active_scalar_petsc_options "
67 "active_scalar_petsc_options_iname "
68 "active_scalar_petsc_options_value active_scalar_petsc_options_value "
69 "active_scalar_absolute_tolerance "
70 "active_scalar_l_tol active_scalar_l_abs_tol active_scalar_l_max_its",
71 "Active Scalars Equations");
72
73 /*
74 * Flags to optionally skip solving subsets of the thermal-hydraulics system (useful when
75 * recovering a converged solution and only advancing scalar transport for example).
76 */
77 params.addParam<bool>(
78 "should_solve_momentum", true, "Whether we should solve the momentum predictor/corrector.");
79 params.addParam<bool>(
80 "should_solve_pressure", true, "Whether we should solve the pressure corrector.");
81 params.addParam<bool>(
82 "should_solve_energy", true, "Whether we should solve the fluid energy equation.");
83 params.addParam<bool>(
84 "should_solve_solid_energy", true, "Whether we should solve the solid energy equation.");
85 params.addParam<bool>("should_solve_turbulence",
86 true,
87 "Whether we should solve the turbulence surrogate equations.");
88 params.addParam<bool>(
89 "should_solve_passive_scalars", true, "Whether we should solve passive scalar equations.");
90 params.addParam<bool>(
91 "should_solve_active_scalars", true, "Whether we should solve active scalar equations.");
92 params.addParam<bool>("should_solve_pm_radiation",
93 true,
94 "Whether we should solve participating media radiation equations.");
95 params.addParamNamesToGroup("should_solve_momentum should_solve_pressure should_solve_energy "
96 "should_solve_solid_energy should_solve_turbulence "
97 "should_solve_passive_scalars should_solve_active_scalars",
98 "Solve control");
99
100 /*
101 * Parameter to amortize the (often dominant) pressure preconditioner setup cost. The pressure
102 * operator changes slowly between SIMPLE iterations, so its preconditioner can be reused for
103 * several iterations rather than rebuilt every solve.
104 */
105 params.addRangeCheckedParam<unsigned int>(
106 "pressure_pc_recompute_frequency",
107 1,
108 "pressure_pc_recompute_frequency >= 1",
109 "How often (in pressure corrector solves) to recompute the pressure preconditioner. The "
110 "default of 1 rebuilds it on every solve. A value of N rebuilds it once every N solves and "
111 "reuses it in between, which can substantially reduce the pressure solve cost when the "
112 "preconditioner setup dominates (e.g. algebraic multigrid). Larger values trade more reuse "
113 "for a possibly staler preconditioner (more Krylov iterations); for solves where the "
114 "pressure "
115 "operator changes significantly, prefer a smaller value.");
116 params.addParamNamesToGroup("pressure_pc_recompute_frequency", "Pressure Equation");
117
118 /*
119 * Parameters to control the conjugate heat transfer
120 */
122
123 return params;
124}
125
127 : SIMPLESolveBase(ex),
128 _pressure_sys_number(_problem.linearSysNum(getParam<SolverSystemName>("pressure_system"))),
129 _pressure_system(_problem.getLinearSystem(_pressure_sys_number)),
130 _pressure_pc_recompute_frequency(getParam<unsigned int>("pressure_pc_recompute_frequency")),
131 _pressure_pc_solve_counter(0),
132 _energy_sys_number(_has_energy_system
133 ? _problem.linearSysNum(getParam<SolverSystemName>("energy_system"))
135 _energy_system(_has_energy_system ? &_problem.getLinearSystem(_energy_sys_number) : nullptr),
136 _solid_energy_sys_number(
137 _has_solid_energy_system
138 ? _problem.linearSysNum(getParam<SolverSystemName>("solid_energy_system"))
140 _solid_energy_system(
141 _has_solid_energy_system ? &_problem.getLinearSystem(_solid_energy_sys_number) : nullptr),
142 _should_solve_momentum(getParam<bool>("should_solve_momentum")),
143 _should_solve_pressure(getParam<bool>("should_solve_pressure")),
144 _should_solve_energy(getParam<bool>("should_solve_energy")),
145 _should_solve_solid_energy(getParam<bool>("should_solve_solid_energy")),
146 _should_solve_turbulence(getParam<bool>("should_solve_turbulence")),
147 _should_solve_passive_scalars(getParam<bool>("should_solve_passive_scalars")),
148 _should_solve_active_scalars(getParam<bool>("should_solve_active_scalars")),
149 _should_solve_pm_radiation(getParam<bool>("should_solve_pm_radiation")),
150 _active_scalar_system_names(getParam<std::vector<SolverSystemName>>("active_scalar_systems")),
151 _has_active_scalar_systems(!_active_scalar_system_names.empty()),
152 _active_scalar_equation_relaxation(
153 getParam<std::vector<Real>>("active_scalar_equation_relaxation")),
154 _active_scalar_l_abs_tol(getParam<Real>("active_scalar_l_abs_tol")),
155 _active_scalar_absolute_tolerance(
156 getParam<std::vector<Real>>("active_scalar_absolute_tolerance")),
157 _cht(ex.parameters())
158{
160 paramError("should_solve_momentum",
161 "Pressure correction requires solving the momentum equations.");
163 paramError("should_solve_pressure",
164 "Solving momentum without a pressure corrector is not supported.");
166 paramError("should_solve_solid_energy",
167 "Solid energy solve cannot be enabled when the fluid energy solve is disabled.");
168
169 // We fetch the systems and their numbers for the momentum equations only if we solve them
171 for (auto system_i : index_range(_momentum_system_names))
172 {
175 _systems_to_solve.push_back(_momentum_systems.back());
176 }
177
180
183
186 // and for the turbulence surrogate equations
188 for (auto system_i : index_range(_turbulence_system_names))
189 {
192 _turbulence_systems.push_back(
194 }
195
196 // and for the passive scalar equations
198 for (auto system_i : index_range(_passive_scalar_system_names))
199 {
202 _passive_scalar_systems.push_back(
206 }
207
208 // and for the participating media radiation equations
210 for (auto system_i : index_range(_pm_radiation_system_names))
211 {
214 _pm_radiation_systems.push_back(
217 }
218
219 // and for the active scalar equations
221 for (auto system_i : index_range(_active_scalar_system_names))
222 {
225 _active_scalar_systems.push_back(
228
229 const auto & active_scalar_petsc_options =
230 getParam<MultiMooseEnum>("active_scalar_petsc_options");
231 const auto & active_scalar_petsc_pair_options = getParam<MooseEnumItem, std::string>(
232 "active_scalar_petsc_options_iname", "active_scalar_petsc_options_value");
234 active_scalar_petsc_options, "", *this, _active_scalar_petsc_options);
235 Moose::PetscSupport::addPetscPairsToPetscOptions(active_scalar_petsc_pair_options,
237 "",
238 *this,
240
242 getParam<Real>("active_scalar_l_tol");
244 getParam<Real>("active_scalar_l_abs_tol");
246 getParam<unsigned int>("active_scalar_l_max_its");
247 }
248
250 paramError("active_scalar_equation_relaxation",
251 "Should be the same size as the number of systems");
252
253 // We disable the prefix here for the time being, the segregated solvers use a different approach
254 // for setting the petsc parameters
255 for (auto & system : _systems_to_solve)
256 system->system().prefix_with_name(false);
257
258 // Link CHT objects, this will also do some error checking
259 // Make a copy for compatibility. These could change in the future
260 // Convert _pm_radiation_systems to std::vector<SystemBase *>
261 if (_cht.enabled())
262 {
264 paramError("should_solve_energy",
265 "Conjugate heat transfer requires solving the fluid energy equation.");
267 paramError("should_solve_solid_energy",
268 "Conjugate heat transfer requires solving the solid energy equation.");
269
270 std::vector<SystemBase *> pm_radiation_systems_base(_pm_radiation_systems.begin(),
272
273 _cht.linkEnergySystems(_solid_energy_system, _energy_system, pm_radiation_systems_base);
274 }
275}
276
277void
279{
281 return;
282
283 _rc_uo =
284 const_cast<RhieChowMassFlux *>(&getUserObject<RhieChowMassFlux>("rhie_chow_user_object"));
287
288 // Initialize the face velocities in the RC object
289 if (!_app.isRecovering())
292}
293
294std::vector<std::pair<unsigned int, Real>>
296{
297 // Temporary storage for the (flux-normalized) residuals from
298 // different momentum components
299 std::vector<std::pair<unsigned int, Real>> its_normalized_residuals;
300
301 LinearImplicitSystem & momentum_system_0 =
302 libMesh::cast_ref<LinearImplicitSystem &>(_momentum_systems[0]->system());
303
304 PetscLinearSolver<Real> & momentum_solver =
305 libMesh::cast_ref<PetscLinearSolver<Real> &>(*momentum_system_0.get_linear_solver());
306
307 // Solve the momentum equations.
308 // TO DO: These equations are VERY similar. If we can store the differences (things coming from
309 // BCs for example) separately, it is enough to construct one matrix.
310 for (const auto system_i : index_range(_momentum_systems))
311 {
313
314 // We will need the right hand side and the solution of the next component
315 LinearImplicitSystem & momentum_system =
316 libMesh::cast_ref<LinearImplicitSystem &>(_momentum_systems[system_i]->system());
317
318 NumericVector<Number> & solution = *(momentum_system.solution);
319 NumericVector<Number> & rhs = *(momentum_system.rhs);
320 SparseMatrix<Number> & mmat = *(momentum_system.matrix);
321
322 auto diff_diagonal = solution.zero_clone();
323
324 // We assemble the matrix and the right hand side
325 _problem.computeLinearSystemSys(momentum_system, mmat, rhs, /*compute_grads*/ true);
326
327 // Still need to relax the right hand side with the same vector
329 NS::FV::relaxRightHandSide(rhs, solution, *diff_diagonal);
330
331 // The normalization factor depends on the right hand side so we need to recompute it for this
332 // component
333 Real norm_factor = NS::FV::computeNormalizationFactor(solution, mmat, rhs);
334
335 // Very important, for deciding the convergence, we need the unpreconditioned
336 // norms in the linear solve
337 LibmeshPetscCall(KSPSetNormType(momentum_solver.ksp(), KSP_NORM_UNPRECONDITIONED));
338 // Solve this component. We don't update the ghosted solution yet, that will come at the end
339 // of the corrector step. Also setting the linear tolerances and maximum iteration counts.
342
343 // We solve the equation
344 auto its_resid_pair = momentum_solver.solve(mmat, mmat, solution, rhs);
345 momentum_system.update();
346
347 // We will reuse the preconditioner for every momentum system
348 if (system_i == 0)
349 momentum_solver.reuse_preconditioner(true);
350
351 // Save the normalized residual
352 its_normalized_residuals.push_back(
353 std::make_pair(its_resid_pair.first, momentum_solver.get_initial_residual() / norm_factor));
354
355 if (_print_fields)
356 {
357 _console << " matrix when we solve " << std::endl;
358 mmat.print();
359 _console << " rhs when we solve " << std::endl;
360 rhs.print();
361 _console << " velocity solution component " << system_i << std::endl;
362 solution.print();
363 _console << "Norm factor " << norm_factor << std::endl;
364 _console << Moose::stringify(momentum_solver.get_initial_residual()) << std::endl;
365 }
366
367 // Printing residuals
368 _console << " Momentum equation:"
369 << (_momentum_systems.size() > 1
370 ? std::string(" Component ") + std::to_string(system_i + 1) + std::string(" ")
371 : std::string(" "))
372 << COLOR_GREEN << its_normalized_residuals[system_i].second << COLOR_DEFAULT
373 << " Linear its: " << its_normalized_residuals[system_i].first << std::endl;
374 }
375
376 for (const auto system_i : index_range(_momentum_systems))
377 {
378 LinearImplicitSystem & momentum_system =
379 libMesh::cast_ref<LinearImplicitSystem &>(_momentum_systems[system_i]->system());
380 _momentum_systems[system_i]->setSolution(*(momentum_system.current_local_solution));
381 _momentum_systems[system_i]->copyPreviousSolutions(Moose::SolutionIterationType::Nonlinear);
382 }
383
384 // We reset this to ensure the preconditioner is recomputed new time we go to the momentum
385 // predictor
386 momentum_solver.reuse_preconditioner(false);
387
388 return its_normalized_residuals;
389}
390
391void
400
401std::pair<unsigned int, Real>
403{
405
406 // We will need some members from the linear system
407 LinearImplicitSystem & pressure_system =
408 libMesh::cast_ref<LinearImplicitSystem &>(_pressure_system.system());
409
410 // We will need the solution, the right hand side and the matrix
411 NumericVector<Number> & current_local_solution = *(pressure_system.current_local_solution);
412 NumericVector<Number> & solution = *(pressure_system.solution);
413 SparseMatrix<Number> & mmat = *(pressure_system.matrix);
414 NumericVector<Number> & rhs = *(pressure_system.rhs);
415
416 // Fetch the linear solver from the system
417 PetscLinearSolver<Real> & pressure_solver =
418 libMesh::cast_ref<PetscLinearSolver<Real> &>(*pressure_system.get_linear_solver());
419
420 _problem.computeLinearSystemSys(pressure_system, mmat, rhs, false);
421
422 if (_print_fields)
423 {
424 _console << "Pressure matrix" << std::endl;
425 mmat.print();
426 }
427
428 // We compute the normalization factors based on the fluxes
429 Real norm_factor = NS::FV::computeNormalizationFactor(solution, mmat, rhs);
430
431 // We need the non-preconditioned norm to be consistent with the norm factor
432 LibmeshPetscCall(KSPSetNormType(pressure_solver.ksp(), KSP_NORM_UNPRECONDITIONED));
433
434 // Setting the linear tolerances and maximum iteration counts
437
438 if (_pin_pressure)
440 pressure_system.update();
441
442 // Optionally reuse the pressure preconditioner across SIMPLE iterations to amortize its setup
443 // cost. We rebuild it on the first solve and then once every _pressure_pc_recompute_frequency
444 // solves, reusing it in between. With the default frequency of 1 this rebuilds on every solve.
445 pressure_solver.reuse_preconditioner(
448
449 auto its_res_pair = pressure_solver.solve(mmat, mmat, solution, rhs);
450 pressure_system.update();
451
452 if (_print_fields)
453 {
454 _console << " rhs when we solve pressure " << std::endl;
455 rhs.print();
456 _console << " Pressure " << std::endl;
457 solution.print();
458 _console << "Norm factor " << norm_factor << std::endl;
459 }
460
461 _pressure_system.setSolution(current_local_solution);
462
463 const auto residuals =
464 std::make_pair(its_res_pair.first, pressure_solver.get_initial_residual() / norm_factor);
465
466 _console << " Pressure equation: " << COLOR_GREEN << residuals.second << COLOR_DEFAULT
467 << " Linear its: " << residuals.first << std::endl;
468
469 return residuals;
470}
471
472std::pair<unsigned int, Real>
474{
476
477 // We will need some members from the linear system
478 LinearImplicitSystem & system =
479 libMesh::cast_ref<LinearImplicitSystem &>(_solid_energy_system->system());
480
481 // We will need the solution, the right hand side and the matrix
482 NumericVector<Number> & current_local_solution = *(system.current_local_solution);
483 NumericVector<Number> & solution = *(system.solution);
484 SparseMatrix<Number> & mmat = *(system.matrix);
485 NumericVector<Number> & rhs = *(system.rhs);
486
487 // Fetch the linear solver from the system
488 PetscLinearSolver<Real> & solver =
489 libMesh::cast_ref<PetscLinearSolver<Real> &>(*system.get_linear_solver());
490
491 _problem.computeLinearSystemSys(system, mmat, rhs, false);
492
493 if (_print_fields)
494 {
495 _console << "Solid energy matrix" << std::endl;
496 mmat.print();
497 }
498
499 // We compute the normalization factors based on the fluxes
500 Real norm_factor = NS::FV::computeNormalizationFactor(solution, mmat, rhs);
501
502 // We need the non-preconditioned norm to be consistent with the norm factor
503 LibmeshPetscCall(KSPSetNormType(solver.ksp(), KSP_NORM_UNPRECONDITIONED));
504
505 // Setting the linear tolerances and maximum iteration counts
508
509 auto its_res_pair = solver.solve(mmat, mmat, solution, rhs);
510 system.update();
511
512 if (_print_fields)
513 {
514 _console << " rhs when we solve solid energy " << std::endl;
515 rhs.print();
516 _console << " Solid energy " << std::endl;
517 solution.print();
518 _console << "Norm factor " << norm_factor << std::endl;
519 }
520
521 _solid_energy_system->setSolution(current_local_solution);
522
523 const auto residuals =
524 std::make_pair(its_res_pair.first, solver.get_initial_residual() / norm_factor);
525
526 _console << " Solid energy equation: " << COLOR_GREEN << residuals.second << COLOR_DEFAULT
527 << " Linear its: " << residuals.first << std::endl;
528
529 return residuals;
530}
531
532std::pair<unsigned int, Real>
533LinearAssemblySegregatedSolve::correctVelocity(const bool subtract_updated_pressure,
534 const bool recompute_face_mass_flux,
535 const SolverParams & solver_params)
536{
537 // Compute the coupling fields between the momentum and pressure equations.
538 // The first argument makes sure the pressure gradient is staged at the first
539 // iteration
540 _rc_uo->computeHbyA(subtract_updated_pressure, _print_fields);
541
542 // We set the preconditioner/controllable parameters for the pressure equations through
543 // petsc options. Linear tolerances will be overridden within the solver.
545
546 // Solve the pressure corrector
547 const auto residuals = solvePressureCorrector();
548
549 // Compute the face velocity which is used in the advection terms. In certain
550 // segregated solver algorithms (like PISO) this is only done on the last iteration.
551 if (recompute_face_mass_flux)
553
554 auto & pressure_current_solution = *(_pressure_system.system().current_local_solution.get());
555 auto & pressure_old_solution = *(_pressure_system.solutionPreviousNewton());
556
557 // Relax the pressure update for the next momentum predictor
559 pressure_current_solution, pressure_old_solution, _pressure_variable_relaxation);
560
561 // Overwrite old solution
562 pressure_old_solution = pressure_current_solution;
563 _pressure_system.setSolution(pressure_current_solution);
564
565 // We recompute the updated pressure gradient
567
568 // Reconstruct the cell velocity as well to accelerate convergence
570
571 return residuals;
572}
573
574std::pair<unsigned int, Real>
576 LinearSystem & system,
577 const Real relaxation_factor,
578 SolverConfiguration & solver_config,
579 const Real absolute_tol,
580 const Real field_relaxation,
581 const Real min_value_limiter)
582{
584
585 // We will need some members from the implicit linear system
586 LinearImplicitSystem & li_system = libMesh::cast_ref<LinearImplicitSystem &>(system.system());
587
588 // We will need the solution, the right hand side and the matrix
589 NumericVector<Number> & current_local_solution = *(li_system.current_local_solution);
590 NumericVector<Number> & solution = *(li_system.solution);
591 SparseMatrix<Number> & mmat = *(li_system.matrix);
592 NumericVector<Number> & rhs = *(li_system.rhs);
593
594 // We need a vector that stores the (diagonal_relaxed-original_diagonal) vector
595 auto diff_diagonal = solution.zero_clone();
596
597 // Fetch the linear solver from the system
598 PetscLinearSolver<Real> & linear_solver =
599 libMesh::cast_ref<PetscLinearSolver<Real> &>(*li_system.get_linear_solver());
600
601 _problem.computeLinearSystemSys(li_system, mmat, rhs, true);
602
603 // Go and relax the system matrix and the right hand side
604 NS::FV::relaxMatrix(mmat, relaxation_factor, *diff_diagonal);
605 NS::FV::relaxRightHandSide(rhs, solution, *diff_diagonal);
606
607 if (_print_fields)
608 {
609 _console << system.name() << " system matrix" << std::endl;
610 mmat.print();
611 }
612
613 // We compute the normalization factors based on the fluxes
614 Real norm_factor = NS::FV::computeNormalizationFactor(solution, mmat, rhs);
615
616 // We need the non-preconditioned norm to be consistent with the norm factor
617 LibmeshPetscCall(KSPSetNormType(linear_solver.ksp(), KSP_NORM_UNPRECONDITIONED));
618
619 // Setting the linear tolerances and maximum iteration counts
620 solver_config.real_valued_data["abs_tol"] = absolute_tol * norm_factor;
621 linear_solver.set_solver_configuration(solver_config);
622
623 // Solve the system and update current local solution
624 auto its_res_pair = linear_solver.solve(mmat, mmat, solution, rhs);
625 li_system.update();
626
627 if (_print_fields)
628 {
629 _console << " rhs when we solve " << system.name() << std::endl;
630 rhs.print();
631 _console << system.name() << " solution " << std::endl;
632 solution.print();
633 _console << " Norm factor " << norm_factor << std::endl;
634 }
635
636 // Limiting scalar solution
637 if (min_value_limiter != std::numeric_limits<Real>::min())
638 NS::FV::limitSolutionUpdate(current_local_solution, min_value_limiter);
639
640 // Relax the field update for the next momentum predictor
641 if (field_relaxation != 1.0)
642 {
643 auto & old_local_solution = *(system.solutionPreviousNewton());
644 NS::FV::relaxSolutionUpdate(current_local_solution, old_local_solution, field_relaxation);
645
646 // Update old solution, only needed if relaxing the field
647 old_local_solution = current_local_solution;
648 }
649
650 system.setSolution(current_local_solution);
651
652 const auto residuals =
653 std::make_pair(its_res_pair.first, linear_solver.get_initial_residual() / norm_factor);
654
655 _console << " Advected system: " << system.name() << " " << COLOR_GREEN << residuals.second
656 << COLOR_DEFAULT << " Linear its: " << residuals.first << std::endl;
657
658 return residuals;
659}
660
661bool
663{
664 // Do not solve if problem is set not to
665 if (!_problem.shouldSolve())
666 return true;
667
669
670 // Dummy solver parameter file which is needed for switching petsc options
671 SolverParams solver_params;
672 solver_params._type = Moose::SolveType::ST_LINEAR;
673 solver_params._line_search = Moose::LineSearchType::LS_NONE;
674
675 // Initialize the SIMPLE iteration counter
676 unsigned int simple_iteration_counter = 0;
677
678 // Rebuild the pressure preconditioner on the first solve of this (e.g. time) step before reusing
679 // it according to _pressure_pc_recompute_frequency.
681
682 // We set up the residual storage and the corresponding tolerances.
683 ResidualStorage residual_storage = setupResidualStorage();
684 auto & ns_residuals = residual_storage.ns_residuals;
685 auto & ns_abs_tols = residual_storage.ns_abs_tols;
686 const auto & momentum_indices = residual_storage.momentum_indices;
687 const auto pressure_index = residual_storage.pressure_index;
688 const auto energy_index = residual_storage.energy_index;
689 const auto solid_energy_index = residual_storage.solid_energy_index;
690 const auto & active_scalar_indices = residual_storage.active_scalar_indices;
691 const auto & turbulence_indices = residual_storage.turbulence_indices;
692 const auto & pm_radiation_indices = residual_storage.pm_radiation_indices;
693
694 bool converged = residual_storage.converged;
695
696 // Loop until converged or hit the maximum allowed iteration number
699
700 while (simple_iteration_counter < _num_iterations && !converged)
701 {
702 simple_iteration_counter++;
703
704 // We set the preconditioner/controllable parameters through petsc options. Linear
705 // tolerances will be overridden within the solver. In case of a segregated momentum
706 // solver, we assume that every velocity component uses the same preconditioner
709
710 // Initialize pressure gradients, after this we just reuse the last ones from each
711 // iteration
712 if (_should_solve_pressure && simple_iteration_counter == 1)
714
715 _console << "Iteration " << simple_iteration_counter << " Initial residual norms:" << std::endl;
716
717 // Solve the momentum predictor step
719 {
720 auto momentum_residual = solveMomentumPredictor();
721 for (const auto system_i : index_range(momentum_residual))
722 ns_residuals[momentum_indices[system_i]] = momentum_residual[system_i];
723 }
724
725 // Now we correct the velocity, this function depends on the method, it differs for
726 // SIMPLE/PIMPLE, this returns the pressure errors
728 ns_residuals[pressure_index] = correctVelocity(true, true, solver_params);
729
730 // If we have an energy equation, solve it here.We assume the material properties in the
731 // Navier-Stokes equations depend on temperature, therefore we can not solve for temperature
732 // outside of the velocity-pressure loop
734 {
735 // If there is no CHT specified this will just do go once through this block
737 while (!_cht.converged())
738 {
739 if (_cht.enabled())
741
742 // We set the preconditioner/controllable parameters through petsc options. Linear
743 // tolerances will be overridden within the solver.
745 ns_residuals[energy_index] = solveAdvectedSystem(_energy_sys_number,
750
752 {
753 // We set the preconditioner/controllable parameters through petsc options. Linear
754 // tolerances will be overridden within the solver.
756 for (const auto i : index_range(_pm_radiation_system_names))
757 {
758 ns_residuals[pm_radiation_indices[i]] =
764 }
765 }
766
768 {
769 // For now we only update gradients if cht is needed, might change in the future
770 if (_cht.enabled())
771 {
774 }
775
776 // We set the preconditioner/controllable parameters through petsc options. Linear
777 // tolerances will be overridden within the solver.
779 ns_residuals[solid_energy_index] = solveSolidEnergy();
780
781 // For now we only update gradients if cht is needed, might change in the future
782 if (_cht.enabled())
784 }
785
786 if (_cht.enabled())
787 {
790 }
791
793 }
794 if (_cht.enabled())
796 }
797
798 // If we have active scalar equations, solve them here in case they depend on temperature
799 // or they affect the fluid properties such that they must be solved concurrently with
800 // pressure and velocity
802 {
804
805 // We set the preconditioner/controllable parameters through petsc options. Linear
806 // tolerances will be overridden within the solver.
808 for (const auto i : index_range(_active_scalar_system_names))
809 ns_residuals[active_scalar_indices[i]] =
815 }
816
817 // If we have turbulence equations, solve them here.
818 // The turbulent viscosity depends on the value of the turbulence surrogate variables
820 {
821 // We set the preconditioner/controllable parameters through petsc options. Linear
822 // tolerances will be overridden within the solver.
824 for (const auto i : index_range(_turbulence_system_names))
825 {
826 ns_residuals[turbulence_indices[i]] =
834 }
835 }
836
838
839 converged = NS::FV::converged(ns_residuals, ns_abs_tols);
840 }
841
842 // If we have passive scalar equations, solve them here. We assume the material properties in
843 // the Navier-Stokes equations do not depend on passive scalars, as they are passive, therefore
844 // we solve outside of the velocity-pressure loop
846 (converged || _continue_on_max_its))
847 {
848 // The reason why we need more than one iteration is due to the matrix relaxation
849 // which can be used to stabilize the equations
850 bool passive_scalar_converged = false;
851 unsigned int ps_iteration_counter = 0;
852
853 _console << "Passive scalar iteration " << ps_iteration_counter
854 << " Initial residual norms:" << std::endl;
855
856 while (ps_iteration_counter < _num_iterations && !passive_scalar_converged)
857 {
858 ps_iteration_counter++;
859 std::vector<std::pair<unsigned int, Real>> scalar_residuals(
860 _passive_scalar_system_names.size(), std::make_pair(0, 1.0));
861 std::vector<Real> scalar_abs_tols;
862 for (const auto scalar_tol : _passive_scalar_absolute_tolerance)
863 scalar_abs_tols.push_back(scalar_tol);
864
865 // We set the preconditioner/controllable parameters through petsc options. Linear
866 // tolerances will be overridden within the solver.
868 for (const auto i : index_range(_passive_scalar_system_names))
874
875 passive_scalar_converged = NS::FV::converged(scalar_residuals, scalar_abs_tols);
876 }
877
878 // Both flow and scalars must converge
879 converged = passive_scalar_converged && converged;
880 }
881
882 converged = _continue_on_max_its ? true : converged;
883
884 return converged;
885}
886
889{
890 ResidualStorage storage;
891
892 // Residual store: position in this vector defines the ordering used by NS::FV::converged()
893 // Each entry holds (linear its, normalized residual) for one system
895 for ([[maybe_unused]] const auto system_i : index_range(_momentum_systems))
896 {
897 storage.momentum_indices.push_back(storage.ns_residuals.size());
898 storage.ns_residuals.push_back(std::make_pair(0, 1.0));
899 storage.ns_abs_tols.push_back(_momentum_absolute_tolerance);
900 }
901
903 {
904 storage.pressure_index = storage.ns_residuals.size();
905 storage.ns_residuals.push_back(std::make_pair(0, 1.0));
906 storage.ns_abs_tols.push_back(_pressure_absolute_tolerance);
907 }
908
910 {
911 storage.energy_index = storage.ns_residuals.size();
912 storage.ns_residuals.push_back(std::make_pair(0, 1.0));
913 storage.ns_abs_tols.push_back(_energy_absolute_tolerance);
914 }
915
917 {
918 storage.solid_energy_index = storage.ns_residuals.size();
919 storage.ns_residuals.push_back(std::make_pair(0, 1.0));
921 }
922
924 for (const auto i : index_range(_active_scalar_system_names))
925 {
926 storage.active_scalar_indices.push_back(storage.ns_residuals.size());
927 storage.ns_residuals.push_back(std::make_pair(0, 1.0));
929 }
930
932 for (const auto i : index_range(_turbulence_system_names))
933 {
934 storage.turbulence_indices.push_back(storage.ns_residuals.size());
935 storage.ns_residuals.push_back(std::make_pair(0, 1.0));
936 storage.ns_abs_tols.push_back(_turbulence_absolute_tolerance[i]);
937 }
938
940 for (const auto i : index_range(_pm_radiation_system_names))
941 {
942 storage.pm_radiation_indices.push_back(storage.ns_residuals.size());
943 storage.ns_residuals.push_back(std::make_pair(0, 1.0));
944 storage.ns_abs_tols.push_back(_pm_radiation_absolute_tolerance[i]);
945 }
946
947 storage.converged = storage.ns_residuals.empty();
948 return storage;
949}
const ExecFlagType EXEC_NONLINEAR
void ErrorVector unsigned int
const ConsoleStream _console
virtual void computeLinearSystemSys(libMesh::LinearImplicitSystem &sys, libMesh::SparseMatrix< libMesh::Number > &system_matrix, NumericVector< libMesh::Number > &rhs, const bool compute_gradients=true)
bool shouldSolve() const
LinearSystem & getLinearSystem(unsigned int sys_num)
void setCurrentLinearSystem(unsigned int sys_num)
unsigned int linearSysNum(const LinearSystemName &linear_sys_name) const override
virtual MooseMesh & mesh() override
virtual void execute(const ExecFlagType &exec_type)
void addParamNamesToGroup(const std::string &space_delim_names, const std::string group_name)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
const unsigned int _energy_sys_number
The number of the system corresponding to the energy equation.
std::pair< unsigned int, Real > solveSolidEnergy()
Solve an equation which contains the solid energy conservation.
virtual std::pair< unsigned int, Real > correctVelocity(const bool subtract_updated_pressure, const bool recompute_face_mass_flux, const SolverParams &solver_params)
Computes new velocity field based on computed pressure gradients.
SIMPLESolverConfiguration _active_scalar_linear_control
Options for the linear solver of the active scalar equation(s)
ResidualStorage setupResidualStorage() const
Build residual/tolerance vectors and associated indices for all enabled systems.
const unsigned int _solid_energy_sys_number
The number of the system corresponding to the solid energy equation.
std::pair< unsigned int, Real > solveAdvectedSystem(const unsigned int system_num, LinearSystem &system, const Real relaxation_factor, libMesh::SolverConfiguration &solver_config, const Real abs_tol, const Real field_relaxation=1.0, const Real min_value_limiter=std::numeric_limits< Real >::min())
Solve an equation which contains an advection term that depends on the solution of the segregated Nav...
std::vector< LinearSystem * > _systems_to_solve
Shortcut to every linear system that we solve for here.
const Real _active_scalar_l_abs_tol
Absolute linear tolerance for the active scalar equation(s).
LinearSystem * _energy_system
Pointer to the linear system corresponding to the fluid energy equation.
NS::FV::CHTHandler _cht
********************** Conjugate heat transfer variables ************** //
LinearSystem * _solid_energy_system
Pointer to the linear system corresponding to the solid energy equation.
std::vector< unsigned int > _momentum_system_numbers
The number(s) of the system(s) corresponding to the momentum equation(s)
std::vector< LinearSystem * > _turbulence_systems
Pointer(s) to the system(s) corresponding to the turbulence equation(s)
virtual bool solve() override
Performs the momentum pressure coupling.
std::vector< LinearSystem * > _momentum_systems
Pointer(s) to the system(s) corresponding to the momentum equation(s)
std::vector< LinearSystem * > _pm_radiation_systems
Pointer(s) to the system(s) corresponding to the participting media radiation equation(s)
Moose::PetscSupport::PetscOptions _active_scalar_petsc_options
Options which hold the petsc settings for the active scalar equation(s)
RhieChowMassFlux * _rc_uo
Pointer to the segregated RhieChow interpolation object.
const unsigned int _pressure_pc_recompute_frequency
How often (in pressure corrector solves) to recompute the pressure preconditioner.
virtual std::vector< std::pair< unsigned int, Real > > solveMomentumPredictor() override
Solve a momentum predictor step with a fixed pressure field.
const std::vector< Real > _active_scalar_equation_relaxation
The user-defined relaxation parameter(s) for the active scalar equation(s)
std::vector< LinearSystem * > _active_scalar_systems
Pointer(s) to the system(s) corresponding to the active scalar equation(s)
unsigned int _pressure_pc_solve_counter
Number of pressure corrector solves performed since the start of the current SIMPLE solve,...
virtual void linkRhieChowUserObject() override
Fetch the Rhie Chow user object that is reponsible for determining face velocities and mass flux.
LinearSystem & _pressure_system
Reference to the linear system corresponding to the pressure equation.
const std::vector< Real > _active_scalar_absolute_tolerance
The user-defined absolute tolerance for determining the convergence in active scalars.
const bool _has_active_scalar_systems
Boolean for easy check if a active scalar systems shall be solved or not.
const std::vector< SolverSystemName > & _active_scalar_system_names
The names of the active scalar systems.
const unsigned int _pressure_sys_number
The number of the system corresponding to the pressure equation.
std::vector< unsigned int > _active_scalar_system_numbers
virtual std::pair< unsigned int, Real > solvePressureCorrector() override
Solve a pressure corrector step.
const bool _should_solve_momentum
Flags controlling which systems are actively solved (can be used with restart to freeze flow)
std::vector< LinearSystem * > _passive_scalar_systems
Pointer(s) to the system(s) corresponding to the passive scalar equation(s)
virtual System & system() override
void computeGradients()
bool isRecovering() const
void paramError(const std::string &param, Args... args) const
virtual unsigned int dimension() const
MooseApp & _app
void sumIntegratedFluxes()
Sum the integrated fluxes over all processors.
Definition CHTHandler.C:465
void printIntegratedFluxes() const
Print the integrated heat fluxes.
Definition CHTHandler.C:476
void resetCHTConvergence()
Reset the convergence data.
Definition CHTHandler.h:158
void resetIntegratedFluxes()
Reset the heat fluxes to 0.
Definition CHTHandler.C:488
void initializeCHTCouplingFields()
Initialize the coupling fields for the conjugate heat transfer routines.
Definition CHTHandler.C:371
void deduceCHTBoundaryCoupling()
Run error checks and make sure everything works.
Definition CHTHandler.C:106
bool converged() const
Check if CHT iteration converged.
Definition CHTHandler.C:495
void setupConjugateHeatTransferContainers()
Set up the boundary condition pairs, functor maps, and every other necessary structure for the conjug...
Definition CHTHandler.C:291
virtual bool enabled() const override final
Check if CHT treatment is needed.
Definition CHTHandler.h:152
static InputParameters validParams()
Definition CHTHandler.C:25
void updateCHTBoundaryCouplingFields(const NS::CHTSide side)
Update the coupling fields for.
Definition CHTHandler.C:392
void linkEnergySystems(SystemBase *solid_energy_system, SystemBase *fluid_energy_system, std::vector< SystemBase * > pm_radiation_systems)
Link energy systems.
Definition CHTHandler.C:91
void incrementCHTIterators()
Increment CHT iterators in the loop.
Definition CHTHandler.h:164
User object responsible for determining the face fluxes using the Rhie-Chow interpolation in a segreg...
void initFaceMassFlux()
Initialize the container for face velocities.
void computeHbyA(const bool with_updated_pressure, const bool verbose)
Computes the inverse of the diagonal (1/A) of the system matrix plus the H/A components for the press...
void computeCellVelocity()
Update the cell values of the velocity variables.
void computeFaceMassFlux()
Update the values of the face velocities in the containers.
void initCouplingField()
Initialize the coupling fields (HbyA and Ainv)
void linkMomentumPressureSystems(const std::vector< LinearSystem * > &momentum_systems, const LinearSystem &pressure_system, const std::vector< unsigned int > &momentum_system_numbers)
Update the momentum system-related information.
Solve class serving as a base class for the two SIMPLE solvers that operate with different assembly a...
const std::vector< Real > _turbulence_equation_relaxation
The user-defined relaxation parameter(s) for the turbulence equation(s)
const Real _momentum_equation_relaxation
The user-defined relaxation parameter for the momentum equation.
const bool _has_energy_system
Boolean for easy check if a fluid energy system shall be solved or not.
std::vector< unsigned int > _pm_radiation_system_numbers
dof_id_type _pressure_pin_dof
The dof ID where the pressure needs to be pinned.
const bool _has_turbulence_systems
Boolean for easy check if a turbulence scalar systems shall be solved or not.
SIMPLESolverConfiguration _pm_radiation_linear_control
Options for the linear solver of the participating media radiation equation(s)
std::vector< unsigned int > _turbulence_system_numbers
const std::vector< SolverSystemName > & _passive_scalar_system_names
The names of the passive scalar systems.
const std::vector< Real > _pm_radiation_absolute_tolerance
The user-defined absolute tolerance for determining the convergence in participating media radiation.
std::vector< unsigned int > _passive_scalar_system_numbers
Moose::PetscSupport::PetscOptions _turbulence_petsc_options
Options which hold the petsc settings for the turbulence equation(s)
const bool _has_pm_radiation_systems
Boolean for easy check if participating media radiation systems shall be solved or not.
const Real _pressure_absolute_tolerance
The user-defined absolute tolerance for determining the convergence in pressure.
const std::vector< SolverSystemName > & _turbulence_system_names
The names of the turbulence systems.
const Real _turbulence_l_abs_tol
Absolute linear tolerance for the turbulence equation(s).
const std::vector< Real > _passive_scalar_equation_relaxation
The user-defined relaxation parameter(s) for the passive scalar equation(s)
const Real _pressure_l_abs_tol
Absolute linear tolerance for the pressure equation.
const Real _passive_scalar_l_abs_tol
Absolute linear tolerance for the passive scalar equation(s).
const bool _has_solid_energy_system
Boolean for easy check if a solid energy system shall be solved or not.
Moose::PetscSupport::PetscOptions _passive_scalar_petsc_options
Options which hold the petsc settings for the passive scalar equation(s)
SIMPLESolverConfiguration _pressure_linear_control
Options for the linear solver of the pressure equation.
static InputParameters validParams()
std::vector< Real > _turbulence_field_relaxation
The user-defined relaxation parameter(s) for the turbulence field(s)
const std::vector< Real > _turbulence_absolute_tolerance
The user-defined absolute tolerance for determining the convergence turbulence variables.
SIMPLESolverConfiguration _solid_energy_linear_control
Options for the linear solver of the energy equation.
const bool _has_passive_scalar_systems
Boolean for easy check if a passive scalar systems shall be solved or not.
std::vector< Real > _turbulence_field_min_limit
The user-defined lower limit for turbulent quantities e.g. k, eps/omega, etc..
Moose::PetscSupport::PetscOptions _pm_radiation_petsc_options
Options which hold the petsc settings for the participating media radiation equation(s)
const std::vector< SolverSystemName > & _pm_radiation_system_names
The names of the participating media radiation systems.
const Real _momentum_absolute_tolerance
The user-defined absolute tolerance for determining the convergence in momentum.
const Real _pm_radiation_l_abs_tol
Absolute linear tolerance for the participating media radiation equation(s).
const Real _pressure_variable_relaxation
The user-defined relaxation parameter for the pressure variable.
const Real _momentum_l_abs_tol
Absolute linear tolerance for the momentum equation(s).
Moose::PetscSupport::PetscOptions _momentum_petsc_options
Options which hold the petsc settings for the momentum equation.
SIMPLESolverConfiguration _energy_linear_control
Options for the linear solver of the energy equation.
const Real _energy_l_abs_tol
Absolute linear tolerance for the energy equations.
const Real _pressure_pin_value
The value we want to enforce for pressure.
Moose::PetscSupport::PetscOptions _solid_energy_petsc_options
Options which hold the petsc settings for the fluid energy equation.
Moose::PetscSupport::PetscOptions _pressure_petsc_options
Options which hold the petsc settings for the pressure equation.
const bool _continue_on_max_its
If solve should continue if maximum number of iterations is hit.
const Real _energy_absolute_tolerance
The user-defined absolute tolerance for determining the convergence in energy.
const unsigned int _num_iterations
The maximum number of momentum-pressure iterations.
const std::vector< Real > _passive_scalar_absolute_tolerance
The user-defined absolute tolerance for determining the convergence in passive scalars.
SIMPLESolverConfiguration _turbulence_linear_control
Options for the linear solver of the turbulence equation(s)
const std::vector< SolverSystemName > & _momentum_system_names
The names of the momentum systems.
const Real _energy_equation_relaxation
The user-defined relaxation parameter for the energy equation.
SIMPLESolverConfiguration _momentum_linear_control
Options for the linear solver of the momentum equation.
SIMPLESolverConfiguration _passive_scalar_linear_control
Options for the linear solver of the passive scalar equation(s)
const Real _solid_energy_l_abs_tol
Absolute linear tolerance for the energy equations.
const bool _pin_pressure
If the pressure needs to be pinned.
Moose::PetscSupport::PetscOptions _energy_petsc_options
Options which hold the petsc settings for the fluid energy equation.
const std::vector< Real > _pm_radiation_equation_relaxation
The user-defined relaxation parameter(s) for the participating media radiation equation(s)
const bool _print_fields
Debug parameter which allows printing the coupling and solution vectors/matrices.
const Real _solid_energy_absolute_tolerance
The user-defined absolute tolerance for determining the convergence in solid energy.
FEProblemBase & _problem
Moose::LineSearchType _line_search
Moose::SolveType _type
void setSolution(const NumericVector< Number > &soln)
virtual const NumericVector< Number > * solutionPreviousNewton() const
virtual const std::string & name() const
NumericVector< Number > * rhs
SparseMatrix< Number > * matrix
virtual LinearSolver< Number > * get_linear_solver() const override
void set_solver_configuration(SolverConfiguration &solver_configuration)
virtual void reuse_preconditioner(bool)
virtual void print(std::ostream &os=libMesh::out) const
virtual std::unique_ptr< NumericVector< T > > zero_clone() const=0
virtual std::pair< unsigned int, Real > solve(SparseMatrix< T > &matrix_in, NumericVector< T > &solution_in, NumericVector< T > &rhs_in, const std::optional< double > tol=std::nullopt, const std::optional< unsigned int > m_its=std::nullopt) override
std::map< std::string, int > int_valued_data
std::map< std::string, Real > real_valued_data
void print(std::ostream &os=libMesh::out, const bool sparse=false) const
std::unique_ptr< NumericVector< Number > > current_local_solution
std::unique_ptr< NumericVector< Number > > solution
void petscSetOptions(const PetscOptions &po, const SolverParams &solver_params, FEProblemBase *const problem=nullptr)
MultiMooseEnum getCommonPetscFlags()
MultiMooseEnum getCommonPetscKeys()
void addPetscFlagsToPetscOptions(const MultiMooseEnum &petsc_flags, std::string prefix, const ParallelParamObject &param_object, PetscOptions &petsc_options)
void addPetscPairsToPetscOptions(const std::vector< std::pair< MooseEnumItem, std::string > > &petsc_pair_options, const unsigned int mesh_dimension, std::string prefix, const ParallelParamObject &param_object, PetscOptions &petsc_options)
std::string stringify(const T &t)
Real computeNormalizationFactor(const NumericVector< Number > &solution, const SparseMatrix< Number > &mat, const NumericVector< Number > &rhs)
Compute a normalization factor which is applied to the linear residual to determine convergence.
bool converged(const std::vector< std::pair< unsigned int, Real > > &residuals, const std::vector< Real > &abs_tolerances)
Based on the residuals, determine if the iterative process converged or not.
void relaxMatrix(SparseMatrix< Number > &matrix_in, const Real relaxation_parameter, NumericVector< Number > &diff_diagonal)
Relax the matrix to ensure diagonal dominance, we hold onto the difference in diagonals for later use...
void constrainSystem(SparseMatrix< Number > &mx, NumericVector< Number > &rhs, const Real desired_value, const dof_id_type dof_id)
Implicitly constrain the system by adding a factor*(u-u_desired) to it at a desired dof value.
void relaxSolutionUpdate(NumericVector< Number > &vec_new, const NumericVector< Number > &vec_old, const Real relaxation_factor)
Relax the update on a solution field using the following approach: $u = u_{old}+\lambda (u - u_{old})...
void limitSolutionUpdate(NumericVector< Number > &solution, const Real min_limit=std::numeric_limits< Real >::epsilon(), const Real max_limit=1e10)
Limit a solution to its minimum and maximum bounds: $u = min(max(u, min_limit), max_limit)$.
void relaxRightHandSide(NumericVector< Number > &rhs_in, const NumericVector< Number > &solution_in, const NumericVector< Number > &diff_diagonal)
Relax the right hand side of an equation, this needs to be called once and the system matrix has been...
@ SOLID
Definition NS.h:200
@ FLUID
Definition NS.h:201
The following methods are specializations for using the Parallel::packed_range_* routines for a vecto...
auto index_range(const T &sizable)
const unsigned int invalid_uint
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Aggregated storage for residuals, tolerances, and indices used in convergence checks.
std::vector< std::size_t > active_scalar_indices
Indices of active scalar equations in ns_residuals.
std::size_t pressure_index
Index of the pressure equation in ns_residuals.
std::vector< std::size_t > turbulence_indices
Indices of turbulence surrogate equations in ns_residuals.
std::size_t energy_index
Index of the energy equation in ns_residuals.
std::vector< std::pair< unsigned int, Real > > ns_residuals
(linear iterations, normalized residual) entries in the order used by NS::FV::converged()
bool converged
This will be an initial indicator if we have something to solve.
std::vector< std::size_t > pm_radiation_indices
Indices of participating media radiation equations in ns_residuals.
std::vector< std::size_t > momentum_indices
Indices of momentum equations in ns_residuals.
std::vector< Real > ns_abs_tols
Absolute tolerances matching ns_residuals.
std::size_t solid_energy_index
Index of the solid energy equation in ns_residuals.