https://mooseframework.inl.gov
SIMPLESolveNonlinearAssembly.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"
12 #include "SegregatedSolverUtils.h"
13 #include "NonlinearSystemBase.h"
14 
15 #include "libmesh/nonlinear_implicit_system.h"
16 
17 using namespace libMesh;
18 
21 {
23 
24  params.addParam<TagName>("pressure_gradient_tag",
25  "pressure_momentum_kernels",
26  "The name of the tags associated with the kernels in the momentum "
27  "equations which are not related to the pressure gradient.");
28 
29  return params;
30 }
31 
33  : SIMPLESolveBase(ex),
34  _pressure_sys_number(_problem.nlSysNum(getParam<SolverSystemName>("pressure_system"))),
35  _pressure_system(_problem.getNonlinearSystemBase(_pressure_sys_number)),
36  _has_turbulence_systems(!getParam<std::vector<SolverSystemName>>("turbulence_systems").empty()),
37  _energy_sys_number(_has_energy_system
38  ? _problem.nlSysNum(getParam<SolverSystemName>("energy_system"))
40  _energy_system(_has_energy_system ? &_problem.getNonlinearSystemBase(_energy_sys_number)
41  : nullptr),
42  _solid_energy_sys_number(
43  _has_solid_energy_system
44  ? _problem.nlSysNum(getParam<SolverSystemName>("solid_energy_system"))
46  _solid_energy_system(_has_solid_energy_system
47  ? &_problem.getNonlinearSystemBase(_solid_energy_sys_number)
48  : nullptr),
49  _turbulence_system_names(getParam<std::vector<SolverSystemName>>("turbulence_systems")),
50  _turbulence_equation_relaxation(getParam<std::vector<Real>>("turbulence_equation_relaxation")),
51  _turbulence_field_min_limit(getParam<std::vector<Real>>("turbulence_field_min_limit")),
52  _turbulence_l_abs_tol(getParam<Real>("turbulence_l_abs_tol")),
53  _turbulence_absolute_tolerance(getParam<std::vector<Real>>("turbulence_absolute_tolerance")),
54  _pressure_tag_name(getParam<TagName>("pressure_gradient_tag")),
55  _pressure_tag_id(_problem.addVectorTag(_pressure_tag_name))
56 {
57  // We disable this considering that this object passes petsc options a little differently
59 
60  // We fetch the system numbers for the momentum components plus add vectors
61  // for removing the contribution from the pressure gradient terms.
62  for (auto system_i : index_range(_momentum_system_names))
63  {
65  _momentum_systems.push_back(
67  _momentum_systems[system_i]->addVector(_pressure_tag_id, false, ParallelType::PARALLEL);
68 
69  // We disable this considering that this object passes petsc options a little differently
70  _momentum_systems[system_i]->system().prefix_with_name(false);
71  }
72 
74  for (auto system_i : index_range(_passive_scalar_system_names))
75  {
78  _passive_scalar_systems.push_back(
80 
81  // We disable this considering that this object passes petsc options a little differently
82  _passive_scalar_systems[system_i]->system().prefix_with_name(false);
83  }
84 
86  {
87  for (auto system_i : index_range(_turbulence_system_names))
88  {
90  _turbulence_systems.push_back(
92 
93  // We disable this considering that this object passes petsc options a little differently
94  _turbulence_systems[system_i]->system().prefix_with_name(false);
95  }
96 
97  // We check for input errors with regards to the turbulence equations. At the same time, we
98  // set up the corresponding system numbers
100  paramError("turbulence_equation_relaxation",
101  "The number of equation relaxation parameters does not match the number of "
102  "turbulence scalar equations!");
104  paramError("turbulence_absolute_tolerance",
105  "The number of absolute tolerances does not match the number of "
106  "turbulence equations!");
107  if (_turbulence_field_min_limit.empty())
108  // If no minimum bounds are given, initialize to default value 1e-8
110  else if (_turbulence_system_names.size() != _turbulence_field_min_limit.size())
111  paramError("turbulence_field_min_limit",
112  "The number of lower bounds for turbulent quantities does not match the "
113  "number of turbulence equations!");
114  }
115 
116  if (isParamValid("solid_energy_system") && !_has_energy_system)
117  paramError(
118  "solid_energy_system",
119  "We cannot solve a solid energy system without solving for the fluid energy as well!");
120 
122  {
123  const auto & turbulence_petsc_options = getParam<MultiMooseEnum>("turbulence_petsc_options");
124  const auto & turbulence_petsc_pair_options = getParam<MooseEnumItem, std::string>(
125  "turbulence_petsc_options_iname", "turbulence_petsc_options_value");
127  turbulence_petsc_options, "-", *this, _turbulence_petsc_options);
128  Moose::PetscSupport::addPetscPairsToPetscOptions(turbulence_petsc_pair_options,
129  _problem.mesh().dimension(),
130  "-",
131  *this,
133 
134  _turbulence_linear_control.real_valued_data["rel_tol"] = getParam<Real>("turbulence_l_tol");
135  _turbulence_linear_control.real_valued_data["abs_tol"] = getParam<Real>("turbulence_l_abs_tol");
137  getParam<unsigned int>("turbulence_l_max_its");
138  }
139  else
140  checkDependentParameterError("turbulence_system",
141  {"turbulence_petsc_options",
142  "turbulence_petsc_options_iname",
143  "turbulence_petsc_options_value",
144  "turbulence_l_tol",
145  "turbulence_l_abs_tol",
146  "turbulence_l_max_its",
147  "turbulence_equation_relaxation",
148  "turbulence_absolute_tolerance"},
149  false);
150 }
151 
152 void
154 {
155  // Fetch the segregated rhie-chow object and transfer some information about the momentum
156  // system(s)
158  &getUserObject<INSFVRhieChowInterpolatorSegregated>("rhie_chow_user_object"));
160 
161  // Initialize the face velocities in the RC object
163 }
164 
165 std::vector<std::pair<unsigned int, Real>>
167 {
168  // Temporary storage for the (flux-normalized) residuals form
169  // different momentum components
170  std::vector<std::pair<unsigned int, Real>> its_normalized_residuals;
171 
172  // We can create this here with the assumption that every momentum component has the same number
173  // of dofs
174  auto zero_solution = _momentum_systems[0]->system().current_local_solution->zero_clone();
175 
176  // Solve the momentum equations.
177  // TO DO: These equations are VERY similar. If we can store the differences (things coming from
178  // BCs for example) separately, it is enough to construct one matrix.
179  for (const auto system_i : index_range(_momentum_systems))
180  {
182 
183  // We will need the right hand side and the solution of the next component
184  NonlinearImplicitSystem & momentum_system =
185  libMesh::cast_ref<NonlinearImplicitSystem &>(_momentum_systems[system_i]->system());
186 
187  PetscLinearSolver<Real> & momentum_solver =
188  libMesh::cast_ref<PetscLinearSolver<Real> &>(*momentum_system.get_linear_solver());
189 
190  NumericVector<Number> & solution = *(momentum_system.solution);
191  NumericVector<Number> & rhs = *(momentum_system.rhs);
192  SparseMatrix<Number> & mmat = *(momentum_system.matrix);
193 
194  auto diff_diagonal = solution.zero_clone();
195 
196  // We plug zero in this to get the system matrix and the right hand side of the linear problem
197  _problem.computeResidualAndJacobian(*zero_solution, rhs, mmat);
198  // Sadly, this returns -b so we multiply with -1
199  rhs.scale(-1.0);
200 
201  // Still need to relax the right hand side with the same vector
202  NS::FV::relaxMatrix(mmat, _momentum_equation_relaxation, *diff_diagonal);
203  NS::FV::relaxRightHandSide(rhs, solution, *diff_diagonal);
204 
205  // The normalization factor depends on the right hand side so we need to recompute it for this
206  // component
207  Real norm_factor = NS::FV::computeNormalizationFactor(solution, mmat, rhs);
208 
209  // Very important, for deciding the convergence, we need the unpreconditioned
210  // norms in the linear solve
211  LibmeshPetscCall(KSPSetNormType(momentum_solver.ksp(), KSP_NORM_UNPRECONDITIONED));
212  // Solve this component. We don't update the ghosted solution yet, that will come at the end
213  // of the corrector step. Also setting the linear tolerances and maximum iteration counts.
215  momentum_solver.set_solver_configuration(_momentum_linear_control);
216 
217  // We solve the equation
218  auto its_resid_pair = momentum_solver.solve(mmat, mmat, solution, rhs);
219  momentum_system.update();
220 
221  // Save the normalized residual
222  its_normalized_residuals.push_back(
223  std::make_pair(its_resid_pair.first, momentum_solver.get_initial_residual() / norm_factor));
224 
225  if (_print_fields)
226  {
227  _console << " matrix when we solve " << std::endl;
228  mmat.print();
229  _console << " rhs when we solve " << std::endl;
230  rhs.print();
231  _console << " velocity solution component " << system_i << std::endl;
232  solution.print();
233  _console << "Norm factor " << norm_factor << std::endl;
234  _console << Moose::stringify(momentum_solver.get_initial_residual()) << std::endl;
235  }
236 
237  _momentum_systems[system_i]->setSolution(*(momentum_system.current_local_solution));
238  _momentum_systems[system_i]->copyPreviousNonlinearSolutions();
239  }
240 
241  return its_normalized_residuals;
242 }
243 
244 std::pair<unsigned int, Real>
246 {
248 
249  // We will need some members from the implicit nonlinear system
250  NonlinearImplicitSystem & pressure_system =
251  libMesh::cast_ref<NonlinearImplicitSystem &>(_pressure_system.system());
252 
253  // We will need the solution, the right hand side and the matrix
254  NumericVector<Number> & current_local_solution = *(pressure_system.current_local_solution);
255  NumericVector<Number> & solution = *(pressure_system.solution);
256  SparseMatrix<Number> & mmat = *(pressure_system.matrix);
257  NumericVector<Number> & rhs = *(pressure_system.rhs);
258 
259  // Fetch the linear solver from the system
260  PetscLinearSolver<Real> & pressure_solver =
261  libMesh::cast_ref<PetscLinearSolver<Real> &>(*pressure_system.get_linear_solver());
262 
263  // We need a zero vector to be able to emulate the Ax=b system by evaluating the
264  // residual and jacobian. Unfortunately, this will leave us with the -b on the right hand side
265  // so we correct it by multiplying it with (-1)
266  auto zero_solution = current_local_solution.zero_clone();
267  _problem.computeResidualAndJacobian(*zero_solution, rhs, mmat);
268  rhs.scale(-1.0);
269 
270  if (_print_fields)
271  {
272  _console << "Pressure matrix" << std::endl;
273  mmat.print();
274  }
275 
276  // We compute the normalization factors based on the fluxes
277  Real norm_factor = NS::FV::computeNormalizationFactor(solution, mmat, rhs);
278 
279  // We need the non-preconditioned norm to be consistent with the norm factor
280  LibmeshPetscCall(KSPSetNormType(pressure_solver.ksp(), KSP_NORM_UNPRECONDITIONED));
281 
282  // Setting the linear tolerances and maximum iteration counts
285 
286  if (_pin_pressure)
288 
289  auto its_res_pair = pressure_solver.solve(mmat, mmat, solution, rhs);
290  pressure_system.update();
291 
292  if (_print_fields)
293  {
294  _console << " rhs when we solve pressure " << std::endl;
295  rhs.print();
296  _console << " Pressure " << std::endl;
297  solution.print();
298  _console << "Norm factor " << norm_factor << std::endl;
299  }
300 
301  _pressure_system.setSolution(current_local_solution);
302 
303  return std::make_pair(its_res_pair.first, pressure_solver.get_initial_residual() / norm_factor);
304 }
305 
306 std::pair<unsigned int, Real>
308  NonlinearSystemBase & system,
309  const Real relaxation_factor,
310  libMesh::SolverConfiguration & solver_config,
311  const Real absolute_tol)
312 {
314 
315  // We will need some members from the implicit nonlinear system
316  NonlinearImplicitSystem & ni_system =
317  libMesh::cast_ref<NonlinearImplicitSystem &>(system.system());
318 
319  // We will need the solution, the right hand side and the matrix
320  NumericVector<Number> & current_local_solution = *(ni_system.current_local_solution);
321  NumericVector<Number> & solution = *(ni_system.solution);
322  SparseMatrix<Number> & mmat = *(ni_system.matrix);
323  NumericVector<Number> & rhs = *(ni_system.rhs);
324 
325  // We need a vector that stores the (diagonal_relaxed-original_diagonal) vector
326  auto diff_diagonal = solution.zero_clone();
327 
328  // Fetch the linear solver from the system
329  PetscLinearSolver<Real> & linear_solver =
330  libMesh::cast_ref<PetscLinearSolver<Real> &>(*ni_system.get_linear_solver());
331 
332  // We need a zero vector to be able to emulate the Ax=b system by evaluating the
333  // residual and jacobian. Unfortunately, this will leave us with the -b on the right hand side
334  // so we correct it by multiplying it with (-1)
335  auto zero_solution = current_local_solution.zero_clone();
336  _problem.computeResidualAndJacobian(*zero_solution, rhs, mmat);
337  rhs.scale(-1.0);
338 
339  // Go and relax the system matrix and the right hand side
340  NS::FV::relaxMatrix(mmat, relaxation_factor, *diff_diagonal);
341  NS::FV::relaxRightHandSide(rhs, solution, *diff_diagonal);
342 
343  if (_print_fields)
344  {
345  _console << system.name() << " system matrix" << std::endl;
346  mmat.print();
347  _console << system.name() << " RHS vector" << std::endl;
348  rhs.print();
349  }
350 
351  // We compute the normalization factors based on the fluxes
352  Real norm_factor = NS::FV::computeNormalizationFactor(solution, mmat, rhs);
353 
354  // We need the non-preconditioned norm to be consistent with the norm factor
355  LibmeshPetscCall(KSPSetNormType(linear_solver.ksp(), KSP_NORM_UNPRECONDITIONED));
356 
357  // Setting the linear tolerances and maximum iteration counts
358  solver_config.real_valued_data["abs_tol"] = absolute_tol * norm_factor;
359  linear_solver.set_solver_configuration(solver_config);
360 
361  // Solve the system and update current local solution
362  auto its_res_pair = linear_solver.solve(mmat, mmat, solution, rhs);
363  ni_system.update();
364 
365  if (_print_fields)
366  {
367  _console << " rhs when we solve " << system.name() << std::endl;
368  rhs.print();
369  _console << system.name() << " solution " << std::endl;
370  solution.print();
371  _console << " Norm factor " << norm_factor << std::endl;
372  }
373 
374  system.setSolution(current_local_solution);
375 
376  return std::make_pair(its_res_pair.first, linear_solver.get_initial_residual() / norm_factor);
377 }
378 
379 std::pair<unsigned int, Real>
381 {
383 
384  // We will need some members from the implicit nonlinear system
385  NonlinearImplicitSystem & se_system =
386  libMesh::cast_ref<NonlinearImplicitSystem &>(_solid_energy_system->system());
387 
388  // We will need the solution, the right hand side and the matrix
389  NumericVector<Number> & current_local_solution = *(se_system.current_local_solution);
390  NumericVector<Number> & solution = *(se_system.solution);
391  SparseMatrix<Number> & mat = *(se_system.matrix);
392  NumericVector<Number> & rhs = *(se_system.rhs);
393 
394  // Fetch the linear solver from the system
395  PetscLinearSolver<Real> & se_solver =
396  libMesh::cast_ref<PetscLinearSolver<Real> &>(*se_system.get_linear_solver());
397 
398  // We need a zero vector to be able to emulate the Ax=b system by evaluating the
399  // residual and jacobian. Unfortunately, this will leave us with the -b on the righ hand side
400  // so we correct it by multiplying it with (-1)
401  auto zero_solution = current_local_solution.zero_clone();
402  _problem.computeResidualAndJacobian(*zero_solution, rhs, mat);
403  rhs.scale(-1.0);
404 
405  if (_print_fields)
406  {
407  _console << "Solid energy matrix" << std::endl;
408  mat.print();
409  }
410 
411  // We compute the normalization factors based on the fluxes
412  Real norm_factor = NS::FV::computeNormalizationFactor(solution, mat, rhs);
413 
414  // We need the non-preconditioned norm to be consistent with the norm factor
415  LibmeshPetscCall(KSPSetNormType(se_solver.ksp(), KSP_NORM_UNPRECONDITIONED));
416 
417  // Setting the linear tolerances and maximum iteration counts
420 
421  auto its_res_pair = se_solver.solve(mat, mat, solution, rhs);
422  se_system.update();
423 
424  if (_print_fields)
425  {
426  _console << " Solid energy rhs " << std::endl;
427  rhs.print();
428  _console << " Solid temperature " << std::endl;
429  solution.print();
430  _console << "Norm factor " << norm_factor << std::endl;
431  }
432 
433  _solid_energy_system->setSolution(current_local_solution);
434 
435  return std::make_pair(its_res_pair.first, se_solver.get_initial_residual() / norm_factor);
436 }
437 
438 bool
440 {
441  // Dummy solver parameter file which is needed for switching petsc options
442  SolverParams solver_params;
443  solver_params._type = Moose::SolveType::ST_LINEAR;
444  solver_params._line_search = Moose::LineSearchType::LS_NONE;
445 
446  // Initialize the quantities which matter in terms of the iteration
447  unsigned int iteration_counter = 0;
448 
449  // Assign residuals to general residual vector
450  unsigned int no_systems =
453  no_systems += _turbulence_systems.size();
454  std::vector<std::pair<unsigned int, Real>> ns_its_residuals(no_systems, std::make_pair(0, 1.0));
455  std::vector<Real> ns_abs_tols(_momentum_systems.size(), _momentum_absolute_tolerance);
456  ns_abs_tols.push_back(_pressure_absolute_tolerance);
457  if (_has_energy_system)
458  {
459  ns_abs_tols.push_back(_energy_absolute_tolerance);
461  ns_abs_tols.push_back(_solid_energy_absolute_tolerance);
462  }
464  for (auto system_i : index_range(_turbulence_absolute_tolerance))
465  ns_abs_tols.push_back(_turbulence_absolute_tolerance[system_i]);
466 
467  bool converged = false;
468  // Loop until converged or hit the maximum allowed iteration number
469  while (iteration_counter < _num_iterations && !converged)
470  {
471  iteration_counter++;
472  // Resdiual index
473  size_t residual_index = 0;
474 
475  // Execute all objects tagged as nonlinear
476  // This will execute everything in the problem at nonlinear, including the aux kernels.
477  // This way we compute the aux kernels before the momentum equations are solved.
479 
480  // We clear the caches in the momentum and pressure variables
481  for (auto system_i : index_range(_momentum_systems))
482  _momentum_systems[system_i]->residualSetup();
484 
485  // If we solve for energy, we clear the caches there too
486  if (_has_energy_system)
487  {
491  }
492 
493  // If we solve for turbulence, we clear the caches there too
495  for (auto system_i : index_range(_turbulence_systems))
496  _turbulence_systems[system_i]->residualSetup();
497 
498  // We set the preconditioner/controllable parameters through petsc options. Linear
499  // tolerances will be overridden within the solver. In case of a segregated momentum
500  // solver, we assume that every velocity component uses the same preconditioner
502 
503  // Solve the momentum predictor step
504  auto momentum_residual = solveMomentumPredictor();
505  for (const auto system_i : index_range(momentum_residual))
506  ns_its_residuals[system_i] = momentum_residual[system_i];
507 
508  // Compute the coupling fields between the momentum and pressure equations
510 
511  // We set the preconditioner/controllable parameters for the pressure equations through
512  // petsc options. Linear tolerances will be overridden within the solver.
514 
515  // Solve the pressure corrector
516  ns_its_residuals[momentum_residual.size()] = solvePressureCorrector();
517  // We need this to make sure we evaluate cell gradients for the nonorthogonal correction in
518  // the face velocity update
520 
521  // Compute the face velocity which is used in the advection terms
523 
524  auto & pressure_current_solution = *(_pressure_system.system().current_local_solution.get());
525  auto & pressure_old_solution = *(_pressure_system.solutionPreviousNewton());
526  // Relax the pressure update for the next momentum predictor
528  pressure_current_solution, pressure_old_solution, _pressure_variable_relaxation);
529 
530  // Overwrite old solution
531  pressure_old_solution = pressure_current_solution;
532  _pressure_system.setSolution(pressure_current_solution);
533 
534  // We clear out the caches so that the gradients can be computed with the relaxed solution
536 
537  // Reconstruct the cell velocity as well to accelerate convergence
539 
540  // Update residual index
541  residual_index = momentum_residual.size();
542 
543  // If we have an energy equation, solve it here. We assume the material properties in the
544  // Navier-Stokes equations depend on temperature, therefore we can not solve for temperature
545  // outside of the velocity-pressure loop
546  if (_has_energy_system)
547  {
548  // We set the preconditioner/controllable parameters through petsc options. Linear
549  // tolerances will be overridden within the solver.
551  residual_index += 1;
552  ns_its_residuals[residual_index] = solveAdvectedSystem(_energy_sys_number,
557 
559  {
560  // We set the preconditioner/controllable parameters through petsc options. Linear
561  // tolerances will be overridden within the solver.
563  residual_index += 1;
564  ns_its_residuals[residual_index] = solveSolidEnergySystem();
565  }
566  }
567 
568  // If we have an turbulence equations, we solve it here. We solve it inside the
569  // momentum-pressure loop because it affects the turbulent viscosity
571  {
573 
574  for (auto system_i : index_range(_turbulence_systems))
575  {
576  residual_index += 1;
577  ns_its_residuals[residual_index] =
579  *_turbulence_systems[system_i],
583 
584  auto & current_solution =
585  *(_turbulence_systems[system_i]->system().current_local_solution.get());
586  NS::FV::limitSolutionUpdate(current_solution, _turbulence_field_min_limit[system_i]);
587 
588  // Relax the turbulence update for the next momentum predictor
589  auto & old_solution = *(_turbulence_systems[system_i]->solutionPreviousNewton());
590 
591  // Relax the pressure update for the next momentum predictor
593  current_solution, old_solution, _turbulence_equation_relaxation[system_i]);
594 
595  // Overwrite old solution
596  old_solution = current_solution;
597  _turbulence_systems[system_i]->setSolution(current_solution);
598 
599  // We clear out the caches so that the gradients can be computed with the relaxed solution
600  _turbulence_systems[system_i]->residualSetup();
601  }
602  }
603 
604  // Printing residuals
605  residual_index = 0;
606  _console << "Iteration " << iteration_counter << " Initial residual norms:" << std::endl;
607  for (auto system_i : index_range(_momentum_systems))
608  _console << " Momentum equation:"
609  << (_momentum_systems.size() > 1
610  ? std::string(" Component ") + std::to_string(system_i + 1) +
611  std::string(" ")
612  : std::string(" "))
613  << COLOR_GREEN << ns_its_residuals[system_i].second << COLOR_DEFAULT << std::endl;
614  _console << " Pressure equation: " << COLOR_GREEN
615  << ns_its_residuals[momentum_residual.size()].second << COLOR_DEFAULT << std::endl;
616  residual_index = momentum_residual.size();
617 
618  if (_has_energy_system)
619  {
620  residual_index += 1;
621  _console << " Energy equation: " << COLOR_GREEN << ns_its_residuals[residual_index].second
622  << COLOR_DEFAULT << std::endl;
624  {
625  residual_index += 1;
626  _console << " Solid energy equation: " << COLOR_GREEN
627  << ns_its_residuals[residual_index].second << COLOR_DEFAULT << std::endl;
628  }
629  }
630 
632  {
633  _console << "Turbulence Iteration " << std::endl;
634  for (auto system_i : index_range(_turbulence_systems))
635  {
636  residual_index += 1;
637  _console << _turbulence_systems[system_i]->name() << " " << COLOR_GREEN
638  << ns_its_residuals[residual_index].second << COLOR_DEFAULT << std::endl;
639  }
640  }
641 
642  converged = NS::FV::converged(ns_its_residuals, ns_abs_tols);
643  }
644 
646 
647  // Now we solve for the passive scalar equations, they should not influence the solution of the
648  // system above. The reason why we need more than one iteration is due to the matrix relaxation
649  // which can be used to stabilize the equations
651  {
652  _console << " Passive Scalar Iteration " << iteration_counter << std::endl;
653 
654  // We set the options used by Petsc (preconditioners etc). We assume that every passive
655  // scalar equation uses the same options for now.
657 
658  iteration_counter = 0;
659  std::vector<std::pair<unsigned int, Real>> passive_scalar_residuals(
660  _passive_scalar_systems.size(), std::make_pair(0, 1.0));
661 
662  bool passive_scalar_converged =
663  NS::FV::converged(passive_scalar_residuals, _passive_scalar_absolute_tolerance);
664  while (iteration_counter < _num_iterations && !passive_scalar_converged)
665  {
666  // We clear the caches in the passive scalar variables
667  for (auto system_i : index_range(_passive_scalar_systems))
668  _passive_scalar_systems[system_i]->residualSetup();
669 
670  iteration_counter++;
671 
672  // Solve the passive scalar equations
673  for (auto system_i : index_range(_passive_scalar_systems))
674  passive_scalar_residuals[system_i] =
676  *_passive_scalar_systems[system_i],
680 
681  _console << "Iteration " << iteration_counter << " Initial residual norms:" << std::endl;
682  for (auto system_i : index_range(_passive_scalar_systems))
683  _console << _passive_scalar_systems[system_i]->name() << " " << COLOR_GREEN
684  << passive_scalar_residuals[system_i].second << COLOR_DEFAULT << std::endl;
685 
686  passive_scalar_converged =
687  NS::FV::converged(passive_scalar_residuals, _passive_scalar_absolute_tolerance);
688  }
689 
690  converged = _continue_on_max_its ? true : passive_scalar_converged;
691  }
692 
693  return converged;
694 }
695 
696 void
698 {
699  // check to make sure that we don't have any time kernels in this simulation (Steady State)
700  for (const auto system : _momentum_systems)
701  checkTimeKernels(*system);
702 
704 
705  if (_has_energy_system)
706  {
710  }
711 
713  for (const auto system : _passive_scalar_systems)
714  checkTimeKernels(*system);
715 
717  for (const auto system : _turbulence_systems)
718  checkTimeKernels(*system);
719 }
720 
721 void
723 {
724  // check to make sure that we don't have any time kernels in this simulation (Steady State)
725  if (system.containsTimeKernel())
726  mooseError("You have specified time kernels in your steady state simulation in system",
727  system.name());
728 }
const unsigned int _energy_sys_number
The number of the system corresponding to the energy equation.
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...
FEProblemBase & _problem
SIMPLESolverConfiguration _momentum_linear_control
Options for the linear solver of the momentum equation.
const Real _energy_absolute_tolerance
The user-defined absolute tolerance for determining the convergence in energy.
const TagID _pressure_tag_id
The ID of the tag which corresponds to the pressure gradient terms in the momentum equation...
const unsigned int _num_iterations
The maximum number of momentum-pressure iterations.
SIMPLESolverConfiguration _energy_linear_control
Options for the linear solver of the energy equation.
const unsigned int invalid_uint
const bool _print_fields
Debug parameter which allows printing the coupling and solution vectors/matrices. ...
INSFVRhieChowInterpolatorSegregated * _rc_uo
Pointer to the segregated RhieChow interpolation object.
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
const Real _solid_energy_l_abs_tol
Absolute linear tolerance for the energy equations.
const bool _has_energy_system
Boolean for easy check if a fluid energy system shall be solved or not.
Moose::LineSearchType _line_search
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...
const Real _passive_scalar_l_abs_tol
Absolute linear tolerance for the passive scalar equation(s).
std::vector< Real > _turbulence_field_min_limit
The user-defined lower limit for turbulent quantities e.g. k, eps/omega, etc..
const Real _momentum_equation_relaxation
The user-defined relaxation parameter for the momentum equation.
virtual std::unique_ptr< NumericVector< T > > zero_clone() const=0
std::vector< unsigned int > _turbulence_system_numbers
virtual void checkTimeKernels(NonlinearSystemBase &system)
Check if the system contains time kernels.
void checkDependentParameterError(const std::string &main_parameter, const std::vector< std::string > &dependent_parameters, const bool should_be_defined)
static InputParameters validParams()
NumericVector< Number > * rhs
const unsigned int _solid_energy_sys_number
The number of the system corresponding to the solid energy equation.
const Real _momentum_l_abs_tol
Absolute linear tolerance for the momentum equation(s).
void setSolution(const NumericVector< Number > &soln)
virtual LinearSolver< Number > * get_linear_solver() const
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
The following methods are specializations for using the Parallel::packed_range_* routines for a vecto...
virtual void linkRhieChowUserObject() override
Fetch the Rhie Chow user object that is reponsible for determining face velocities and mass flux...
const Real _turbulence_l_abs_tol
Absolute linear tolerance for the turbulence equation(s).
NonlinearSystemBase & _pressure_system
Reference to the nonlinear system corresponding to the pressure equation.
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...
std::map< std::string, Real > real_valued_data
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.
const Real _pressure_absolute_tolerance
The user-defined absolute tolerance for determining the convergence in pressure.
bool isParamValid(const std::string &name) const
const Real _pressure_variable_relaxation
The user-defined relaxation parameter for the pressure variable.
const Real _momentum_absolute_tolerance
The user-defined absolute tolerance for determining the convergence in momentum.
virtual const std::string & name() const
const std::vector< SolverSystemName > & _passive_scalar_system_names
The names of the passive scalar systems.
virtual bool containsTimeKernel() override
SIMPLESolverConfiguration _turbulence_linear_control
Options for the linear solver of the turbulence equation(s)
virtual void scale(const T factor)=0
void computeFaceVelocity()
Update the values of the face velocities in the containers.
SIMPLESolverConfiguration _passive_scalar_linear_control
Options for the linear solver of the passive scalar equation(s)
virtual void execute(const ExecFlagType &exec_type)
Moose::PetscSupport::PetscOptions _energy_petsc_options
Options which hold the petsc settings for the fluid energy equation.
SIMPLESolverConfiguration _pressure_linear_control
Options for the linear solver of the pressure equation.
void setCurrentNonlinearSystem(const unsigned int nl_sys_num)
Moose::PetscSupport::PetscOptions _passive_scalar_petsc_options
Options which hold the petsc settings for the passive scalar equation(s)
virtual unsigned int dimension() const
std::map< std::string, int > int_valued_data
virtual std::unique_ptr< SparseMatrix< T > > zero_clone() const=0
const bool _has_turbulence_systems
Boolean for easy check if turbulence systems shall be solved or not.
Moose::PetscSupport::PetscOptions _momentum_petsc_options
Options which hold the petsc settings for the momentum equation.
const Real _pressure_l_abs_tol
Absolute linear tolerance for the pressure equation.
const std::vector< Real > _passive_scalar_absolute_tolerance
The user-defined absolute tolerance for determining the convergence in passive scalars.
std::unique_ptr< NumericVector< Number > > solution
dof_id_type _pressure_pin_dof
The dof ID where the pressure needs to be pinned.
Moose::SolveType _type
const std::vector< SolverSystemName > & _turbulence_system_names
The names of the turbulence scalar systems.
virtual void print(std::ostream &os=libMesh::out) const
const bool _pin_pressure
If the pressure needs to be pinned.
NonlinearSystemBase & getNonlinearSystemBase(const unsigned int sys_num)
void paramError(const std::string &param, Args... args) const
const Real _energy_l_abs_tol
Absolute linear tolerance for the energy equations.
std::string stringify(const T &t)
std::pair< unsigned int, Real > solveSolidEnergySystem()
Solve the solid energy conservation equation.
void petscSetOptions(const PetscOptions &po, const SolverParams &solver_params, FEProblemBase *const problem=nullptr)
void set_solver_configuration(SolverConfiguration &solver_configuration)
const std::vector< SolverSystemName > & _momentum_system_names
The names of the momentum systems.
const ExecFlagType EXEC_NONLINEAR
NonlinearSystemBase * _solid_energy_system
Pointer to the nonlinear system corresponding to the solid energy equation.
const std::vector< Real > _passive_scalar_equation_relaxation
The user-defined relaxation parameter(s) for the passive scalar equation(s)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual bool solve() override
Performs the momentum pressure coupling.
NonlinearSystemBase * _energy_system
Pointer to the nonlinear system corresponding to the fluid energy equation.
void addPetscPairsToPetscOptions(const std::vector< std::pair< MooseEnumItem, std::string >> &petsc_pair_options, const unsigned int mesh_dimension, const std::string &prefix, const ParallelParamObject &param_object, PetscOptions &petsc_options)
const Real _energy_equation_relaxation
The user-defined relaxation parameter for the energy equation.
SparseMatrix< Number > * matrix
std::vector< NonlinearSystemBase * > _momentum_systems
Pointer(s) to the system(s) corresponding to the momentum equation(s)
const Real _pressure_pin_value
The value we want to enforce for pressure.
void computeResidualAndJacobian(const NumericVector< libMesh::Number > &soln, NumericVector< libMesh::Number > &residual, libMesh::SparseMatrix< libMesh::Number > &jacobian)
virtual MooseMesh & mesh() override
void computeCellVelocity()
Update the cell values of the velocity variables.
void mooseError(Args &&... args) const
std::pair< unsigned int, Real > solveAdvectedSystem(const unsigned int system_num, NonlinearSystemBase &system, const Real relaxation_factor, libMesh::SolverConfiguration &solver_config, const Real abs_tol)
Solve an equation which contains an advection term that depends on the solution of the segregated Nav...
std::unique_ptr< NumericVector< Number > > current_local_solution
virtual const NumericVector< Number > * solutionPreviousNewton() const
Solve class serving as a base class for the two SIMPLE solvers that operate with different assembly a...
const bool _has_passive_scalar_systems
Boolean for easy check if a passive scalar systems shall be solved or not.
void addPetscFlagsToPetscOptions(const MultiMooseEnum &petsc_flags, const std::string &prefix, const ParallelParamObject &param_object, PetscOptions &petsc_options)
const ConsoleStream _console
const Real _solid_energy_absolute_tolerance
The user-defined absolute tolerance for determining the convergence in solid energy.
SIMPLESolverConfiguration _solid_energy_linear_control
Options for the linear solver of the energy equation.
const bool _continue_on_max_its
If solve should continue if maximum number of iterations is hit.
Moose::PetscSupport::PetscOptions _turbulence_petsc_options
Options which hold the petsc settings for the turbulence equation(s)
const unsigned int _pressure_sys_number
The number of the system corresponding to the pressure equation.
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 prefix_with_name(bool value)
const std::vector< Real > _turbulence_absolute_tolerance
The user-defined absolute tolerance for determining the convergence in turbulence equations...
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 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}+ (u - u_{old})$...
void computeHbyA(bool verbose)
Computes the inverse of the digaonal (1/A) of the system matrix plus the H/A components for the press...
const std::vector< Real > _turbulence_equation_relaxation
The user-defined relaxation parameter(s) for the turbulence equation(s)
std::vector< NonlinearSystemBase * > _passive_scalar_systems
Pointer(s) to the system(s) corresponding to the passive scalar equation(s)
auto index_range(const T &sizable)
std::vector< NonlinearSystemBase * > _turbulence_systems
Pointer(s) to the system(s) corresponding to the turbulence equation(s)
void print(std::ostream &os=libMesh::out, const bool sparse=false) const
std::vector< unsigned int > _momentum_system_numbers
The number(s) of the system(s) corresponding to the momentum equation(s)
virtual void checkIntegrity() override
Check if the user defined time kernels.
std::vector< unsigned int > _passive_scalar_system_numbers
virtual unsigned int nlSysNum(const NonlinearSystemName &nl_sys_name) const override
Moose::PetscSupport::PetscOptions _pressure_petsc_options
Options which hold the petsc settings for the pressure equation.
A user object which implements the Rhie Chow interpolation for segregated momentum-pressure systems...
void linkMomentumSystem(std::vector< NonlinearSystemBase *> momentum_systems, const std::vector< unsigned int > &momentum_system_numbers, const TagID pressure_gradient_tag)
Update the momentum system-related information.
const bool _has_solid_energy_system
Boolean for easy check if a solid energy system shall be solved or not.
virtual std::vector< std::pair< unsigned int, Real > > solveMomentumPredictor() override
Solve a momentum predictor step with a fixed pressure field.
virtual std::pair< unsigned int, Real > solvePressureCorrector() override
Solve a pressure corrector step.
void initFaceVelocities()
Initialize the container for face velocities.
virtual void residualSetup() override
virtual libMesh::System & system() override