https://mooseframework.inl.gov
PetscSupport.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 #include "PetscSupport.h"
11 
12 // MOOSE includes
13 #include "MooseApp.h"
14 #include "FEProblem.h"
15 #include "DisplacedProblem.h"
16 #include "NonlinearSystem.h"
17 #include "LinearSystem.h"
18 #include "AuxiliarySystem.h"
19 #include "DisplacedProblem.h"
20 #include "PenetrationLocator.h"
21 #include "NearestNodeLocator.h"
22 #include "MooseTypes.h"
23 #include "MooseUtils.h"
24 #include "CommandLine.h"
25 #include "Console.h"
26 #include "MultiMooseEnum.h"
27 #include "Conversion.h"
28 #include "Executioner.h"
29 #include "MooseMesh.h"
31 #include "Convergence.h"
32 #include "ParallelParamObject.h"
33 
34 #include "libmesh/equation_systems.h"
35 #include "libmesh/linear_implicit_system.h"
36 #include "libmesh/nonlinear_implicit_system.h"
37 #include "libmesh/petsc_linear_solver.h"
38 #include "libmesh/petsc_matrix.h"
39 #include "libmesh/petsc_nonlinear_solver.h"
40 #include "libmesh/petsc_preconditioner.h"
41 #include "libmesh/petsc_vector.h"
42 #include "libmesh/sparse_matrix.h"
43 #include "libmesh/petsc_solver_exception.h"
44 #include "libmesh/simple_range.h"
45 
46 // PETSc includes
47 #include <petsc.h>
48 #include <petscsnes.h>
49 #include <petscksp.h>
50 #include <petscmat.h>
51 #include <petscis.h>
52 #include <petscdm.h>
53 #include <petscoptions.h>
54 
55 // PetscDMMoose include
56 #include "PetscDMMoose.h"
57 
58 // Standard includes
59 #include <ostream>
60 #include <cctype>
61 #include <fstream>
62 #include <optional>
63 #include <string>
64 
65 using namespace libMesh;
66 
67 void
69 {
70  PetscVector<Number> & petsc_vec = static_cast<PetscVector<Number> &>(vector);
71  LibmeshPetscCallA(vector.comm().get(), VecView(petsc_vec.vec(), 0));
72 }
73 
74 void
76 {
77  PetscMatrixBase<Number> & petsc_mat = static_cast<PetscMatrix<Number> &>(mat);
78  LibmeshPetscCallA(mat.comm().get(), MatView(petsc_mat.mat(), 0));
79 }
80 
81 void
83 {
84  PetscVector<Number> & petsc_vec =
85  static_cast<PetscVector<Number> &>(const_cast<NumericVector<Number> &>(vector));
86  LibmeshPetscCallA(vector.comm().get(), VecView(petsc_vec.vec(), 0));
87 }
88 
89 void
91 {
92  PetscMatrixBase<Number> & petsc_mat =
93  static_cast<PetscMatrix<Number> &>(const_cast<SparseMatrix<Number> &>(mat));
94  LibmeshPetscCallA(mat.comm().get(), MatView(petsc_mat.mat(), 0));
95 }
96 
97 namespace Moose
98 {
99 namespace PetscSupport
100 {
101 
102 namespace
103 {
104 
105 void
106 applySystemVectorTypeOptions(FEProblemBase & problem, libMesh::System & lm_sys)
107 {
108  for (auto & [_, vec] : as_range(lm_sys.vectors_begin(), lm_sys.vectors_end()))
109  {
110  auto * const petsc_vec = cast_ptr<PetscVector<Number> *>(vec.get());
111  LibmeshPetscCallA(problem.comm().get(), VecSetFromOptions(petsc_vec->vec()));
112  }
113 
114  // The solution vectors aren't included in the system vectors storage.
115  auto * petsc_vec = cast_ptr<PetscVector<Number> *>(lm_sys.solution.get());
116  LibmeshPetscCallA(problem.comm().get(), VecSetFromOptions(petsc_vec->vec()));
117  petsc_vec = cast_ptr<PetscVector<Number> *>(lm_sys.current_local_solution.get());
118  LibmeshPetscCallA(problem.comm().get(), VecSetFromOptions(petsc_vec->vec()));
119 }
120 
121 void
122 applyVectorTypeOptions(FEProblemBase & problem)
123 {
124  for (const auto sys_index : make_range(problem.numSolverSystems()))
125  applySystemVectorTypeOptions(problem, problem.getSolverSystem(sys_index).system());
126 
127  applySystemVectorTypeOptions(problem, problem.getAuxiliarySystem().system());
128 }
129 
130 bool
131 petscOptionsHasName(::PetscOptions options,
132  const std::string & name,
133  const std::string & prefix = "")
134 {
135  PetscBool found = PETSC_FALSE;
136  const char * const prefix_ptr = prefix.empty() ? nullptr : prefix.c_str();
137  LibmeshPetscCallA(PETSC_COMM_WORLD,
138  PetscOptionsHasName(options, prefix_ptr, name.c_str(), &found));
139  return found;
140 }
141 
142 bool
143 hasMatrixFreeSolveType(const FEProblemBase & problem)
144 {
145  for (const auto sys_index : make_range(problem.numSolverSystems()))
146  if (const auto solve_type = problem.solverParams(sys_index)._type;
147  solve_type == Moose::ST_JFNK || solve_type == Moose::ST_PJFNK)
148  return true;
149 
150  return false;
151 }
152 
153 bool
154 mightBeMatTypeOption(const std::string & name)
155 {
156  static constexpr std::string_view mat_type_suffix = "mat_type";
157  return name.size() >= mat_type_suffix.size() &&
158  std::equal(mat_type_suffix.rbegin(),
159  mat_type_suffix.rend(),
160  name.rbegin(),
161  [](const char left, const char right)
162  // tolower requires representability by unsigned char
163  {
164  return static_cast<int>(left) ==
165  std::tolower(libMesh::cast_int<unsigned char>(right));
166  });
167 }
168 
169 void
170 errorOnUnprefixedMatTypeOption(::PetscOptions options, FEProblemBase & problem)
171 {
172  if (!petscOptionsHasName(options, "-mat_type"))
173  return;
174 
175  std::string error_string =
176  "Setting option '-mat_type' is not supported without a solver-system prefix. Use an option "
177  "such as '-" +
178  problem.getSolverSystem(0).name() + "_mat_type' for assembled libMesh matrices.";
179  if (hasMatrixFreeSolveType(problem))
180  error_string +=
181  " Attempting to change the matrix "
182  "type for the MFFD matrix type used to represent the Jacobian for (P)JFNK solve "
183  "types is not supported.";
184  mooseError(error_string);
185 }
186 
187 // Allow iterating over all systems or allowing caller to specify a specific system for which to
188 // apply matrix type options
189 void
190 applyMatrixTypeOptions(FEProblemBase & problem,
191  const std::optional<std::size_t> system_index = std::nullopt)
192 {
193  const auto begin = system_index.value_or(0);
194  const auto end = system_index ? begin + 1 : problem.numSolverSystems();
195 
196  for (const auto sys_index : make_range(begin, end))
197  {
198  auto & solver_system = problem.getSolverSystem(sys_index);
199  auto & lm_sys = solver_system.system();
200 
201  // Even in matrix-free modes the libMesh matrix wrappers can exist before the PETSc Mat does.
202  if (problem.solverParams(sys_index)._type == Moose::ST_JFNK)
203  continue;
204 
205  for (auto & [_, mat] : as_range(lm_sys.matrices_begin(), lm_sys.matrices_end()))
206  if (auto * const petsc_mat = dynamic_cast<PetscMatrixBase<Number> *>(mat.get()); petsc_mat)
207  {
208  LibmeshPetscCallA(
209  problem.comm().get(),
210  MatSetOptionsPrefix(petsc_mat->mat(), (solver_system.name() + "_").c_str()));
211  LibmeshPetscCallA(problem.comm().get(), MatSetFromOptions(petsc_mat->mat()));
212  }
213  }
214 }
215 
216 } // namespace
217 
218 std::string
220 {
221  switch (t)
222  {
223  case LS_BASIC:
224  return "basic";
225  case LS_DEFAULT:
226  return "default";
227  case LS_NONE:
228  return "none";
229  case LS_SHELL:
230  return "shell";
231  case LS_L2:
232  return "l2";
233  case LS_BT:
234  return "bt";
235  case LS_CP:
236  return "cp";
237  case LS_CONTACT:
238  return "contact";
239  case LS_PROJECT:
240  return "project";
241  case LS_INVALID:
242  mooseError("Invalid LineSearchType");
243  }
244  return "";
245 }
246 
247 std::string
248 stringify(const MffdType & t)
249 {
250  switch (t)
251  {
252  case MFFD_WP:
253  return "wp";
254  case MFFD_DS:
255  return "ds";
256  case MFFD_INVALID:
257  mooseError("Invalid MffdType");
258  }
259  return "";
260 }
261 
262 void
263 setSolverOptions(const SolverParams & solver_params, const MultiMooseEnum & dont_add_these_options)
264 {
265  const auto prefix_with_dash = '-' + solver_params._prefix;
266  // set PETSc options implied by a solve type
267  switch (solver_params._type)
268  {
269  case Moose::ST_PJFNK:
270  setSinglePetscOptionIfAppropriate(dont_add_these_options,
271  prefix_with_dash + "snes_mf_operator");
272  setSinglePetscOptionIfAppropriate(dont_add_these_options,
273  prefix_with_dash + "mat_mffd_type",
274  stringify(solver_params._mffd_type));
275  break;
276 
277  case Moose::ST_JFNK:
278  setSinglePetscOptionIfAppropriate(dont_add_these_options, prefix_with_dash + "snes_mf");
279  setSinglePetscOptionIfAppropriate(dont_add_these_options,
280  prefix_with_dash + "mat_mffd_type",
281  stringify(solver_params._mffd_type));
282  break;
283 
284  case Moose::ST_NEWTON:
285  break;
286 
287  case Moose::ST_FD:
288  setSinglePetscOptionIfAppropriate(dont_add_these_options, prefix_with_dash + "snes_fd");
289  break;
290 
291  case Moose::ST_LINEAR:
293  dont_add_these_options, prefix_with_dash + "snes_type", "ksponly");
294  setSinglePetscOptionIfAppropriate(dont_add_these_options,
295  prefix_with_dash + "snes_monitor_cancel");
296  break;
297  }
298 
299  Moose::LineSearchType ls_type = solver_params._line_search;
300  if (ls_type == Moose::LS_NONE)
301  ls_type = Moose::LS_BASIC;
302 
303  if (ls_type != Moose::LS_DEFAULT && ls_type != Moose::LS_CONTACT && ls_type != Moose::LS_PROJECT)
305  dont_add_these_options, prefix_with_dash + "snes_linesearch_type", stringify(ls_type));
306 }
307 
308 void
310 {
311  // commandline options always win
312  // the options from a user commandline will overwrite the existing ones if any conflicts
313  int argc;
314  char ** args;
315 
316  LibmeshPetscCallA(PETSC_COMM_WORLD, PetscGetArgs(&argc, &args));
317  std::vector<const char *> cl_args(args + 1, args + argc);
318  const auto cl_argc = libMesh::cast_int<int>(cl_args.size());
319 
320  ::PetscOptions command_line_options;
321  LibmeshPetscCallA(PETSC_COMM_WORLD, PetscOptionsCreate(&command_line_options));
322  LibmeshPetscCallA(PETSC_COMM_WORLD,
323  PetscOptionsInsertArgs(command_line_options, cl_argc, cl_args.data()));
324  LibmeshPetscCallA(PETSC_COMM_WORLD,
325  PetscOptionsInsertArgs(LIBMESH_PETSC_NULLPTR, cl_argc, cl_args.data()));
326 
327  if (!problem)
328  {
329  LibmeshPetscCallA(PETSC_COMM_WORLD, PetscOptionsDestroy(&command_line_options));
330  return;
331  }
332 
333  errorOnUnprefixedMatTypeOption(command_line_options, *problem);
334 
335  // Some vector/matrix-type options may have been consumed before the PETSc database rebuild.
336  // Replay only the command-line-controlled applications so input-file options handled through
337  // setSinglePetscOption() do not pay the cost twice.
338  const bool have_vec_type = petscOptionsHasName(command_line_options, "-vec_type");
339  bool have_mat_type = false;
340 
341  for (const auto sys_index : make_range(problem->numSolverSystems()))
342  {
343  have_mat_type = petscOptionsHasName(
344  command_line_options, "-mat_type", problem->getSolverSystem(sys_index).name() + "_");
345  if (have_mat_type)
346  break;
347  }
348 
349  if (have_vec_type)
350  applyVectorTypeOptions(*problem);
351  if (have_mat_type)
352  applyMatrixTypeOptions(*problem);
353 
354  LibmeshPetscCallA(PETSC_COMM_WORLD, PetscOptionsDestroy(&command_line_options));
355 }
356 
357 void
359 {
360  // Add any additional options specified in the input file
361  for (const auto & flag : po.flags)
362  // Need to use name method here to pass a str instead of an EnumItem because
363  // we don't care if the id attributes match
364  if (!po.dont_add_these_options.contains(flag.name()) ||
365  po.user_set_options.contains(flag.name()))
366  setSinglePetscOption(flag.rawName().c_str());
367 
368  // Add option pairs
369  for (auto & option : po.pairs)
370  if (!po.dont_add_these_options.contains(option.first) ||
371  po.user_set_options.contains(option.first))
372  setSinglePetscOption(option.first, option.second, problem);
373 
375 }
376 
377 void
379  const SolverParams & solver_params,
380  FEProblemBase * const problem)
381 {
382  PetscCallAbort(PETSC_COMM_WORLD, PetscOptionsClear(LIBMESH_PETSC_NULLPTR));
383  setSolverOptions(solver_params, po.dont_add_these_options);
384  petscSetOptionsHelper(po, problem);
385 }
386 
387 void
389  const std::vector<SolverParams> & solver_params_vec,
390  FEProblemBase * const problem)
391 {
392  PetscCallAbort(PETSC_COMM_WORLD, PetscOptionsClear(LIBMESH_PETSC_NULLPTR));
393  for (const auto & solver_params : solver_params_vec)
394  setSolverOptions(solver_params, po.dont_add_these_options);
395  petscSetOptionsHelper(po, problem);
396 }
397 
398 PetscErrorCode
400 {
402  char code[10] = {45, 45, 109, 111, 111, 115, 101};
403  const std::vector<std::string> argv = cmd_line->getArguments();
404  for (const auto & arg : argv)
405  {
406  if (arg.compare(code) == 0)
407  {
409  break;
410  }
411  }
412  PetscFunctionReturn(PETSC_SUCCESS);
413 }
414 
415 PetscErrorCode
417  PetscInt it,
418  PetscReal /*xnorm*/,
419  PetscReal /*snorm*/,
420  PetscReal /*fnorm*/,
421  SNESConvergedReason * reason,
422  void * ctx)
423 {
425  FEProblemBase & problem = *static_cast<FEProblemBase *>(ctx);
426 
427  // execute objects that may be used in convergence check
429 
430  // perform the convergence check
433  {
436  }
437  else
438  {
439  auto & convergence = problem.getConvergence(
441  status = convergence.checkConvergence(it);
442  }
443 
444  // convert convergence status to PETSc converged reason
445  switch (status)
446  {
448  *reason = SNES_CONVERGED_ITERATING;
449  break;
450 
452  *reason = SNES_CONVERGED_FNORM_ABS;
453  break;
454 
456  *reason = SNES_DIVERGED_DTOL;
457  break;
458  }
459 
460  PetscFunctionReturn(PETSC_SUCCESS);
461 }
462 
463 PetscErrorCode
465  KSP /*ksp*/, PetscInt it, PetscReal /*norm*/, KSPConvergedReason * reason, void * ctx)
466 {
468  FEProblemBase & problem = *static_cast<FEProblemBase *>(ctx);
469 
470  // execute objects that may be used in convergence check
471  // Right now, setting objects to execute on this flag would be ignored except in the
472  // linear-system-only use case.
474 
475  // perform the convergence check
477  if (problem.getFailNextSystemConvergenceCheck())
478  {
481  }
482  else
483  {
484  auto & convergence = problem.getConvergence(
485  problem.getLinearConvergenceNames()[problem.currentLinearSystem().number()]);
486  status = convergence.checkConvergence(it);
487  }
488 
489  // convert convergence status to PETSc converged reason
490  switch (status)
491  {
493  *reason = KSP_CONVERGED_ITERATING;
494  break;
495 
496  // TODO: find a KSP code that works better for this case
498 #if PETSC_VERSION_LESS_THAN(3, 24, 0)
499  *reason = KSP_CONVERGED_RTOL_NORMAL;
500 #else
501  *reason = KSP_CONVERGED_RTOL_NORMAL_EQUATIONS;
502 #endif
503  break;
504 
506  *reason = KSP_DIVERGED_DTOL;
507  break;
508  }
509 
510  PetscFunctionReturn(PETSC_SUCCESS);
511 }
512 
513 PCSide
515 {
516  switch (pcs)
517  {
518  case Moose::PCS_LEFT:
519  return PC_LEFT;
520  case Moose::PCS_RIGHT:
521  return PC_RIGHT;
523  return PC_SYMMETRIC;
524  default:
525  mooseError("Unknown PC side requested.");
526  break;
527  }
528 }
529 
530 KSPNormType
532 {
533  switch (kspnorm)
534  {
535  case Moose::KSPN_NONE:
536  return KSP_NORM_NONE;
538  return KSP_NORM_PRECONDITIONED;
540  return KSP_NORM_UNPRECONDITIONED;
541  case Moose::KSPN_NATURAL:
542  return KSP_NORM_NATURAL;
543  case Moose::KSPN_DEFAULT:
544  return KSP_NORM_DEFAULT;
545  default:
546  mooseError("Unknown KSP norm type requested.");
547  break;
548  }
549 }
550 
551 void
553 {
554  for (const auto i : make_range(problem.numSolverSystems()))
555  {
556  SolverSystem & sys = problem.getSolverSystem(i);
557  LibmeshPetscCallA(problem.comm().get(),
558  KSPSetNormType(ksp, getPetscKSPNormType(sys.getMooseKSPNormType())));
559  }
560 }
561 
562 void
564 {
565  for (const auto i : make_range(problem.numSolverSystems()))
566  {
567  SolverSystem & sys = problem.getSolverSystem(i);
568 
569  // PETSc 3.2.x+
570  if (sys.getPCSide() != Moose::PCS_DEFAULT)
571  LibmeshPetscCallA(problem.comm().get(), KSPSetPCSide(ksp, getPetscPCSide(sys.getPCSide())));
572  }
573 }
574 
575 void
577 {
578  auto & es = problem.es();
579 
580  PetscReal rtol = es.parameters.get<Real>("linear solver tolerance");
581  PetscReal atol = es.parameters.get<Real>("linear solver absolute tolerance");
582 
583  // MOOSE defaults this to -1 for some dumb reason
584  if (atol < 0)
585  atol = 1e-50;
586 
587  PetscReal maxits = es.parameters.get<unsigned int>("linear solver maximum iterations");
588 
589  // 1e100 is because we don't use divtol currently
590  LibmeshPetscCallA(problem.comm().get(), KSPSetTolerances(ksp, rtol, atol, 1e100, maxits));
591 
592  petscSetDefaultPCSide(problem, ksp);
593 
594  petscSetDefaultKSPNormType(problem, ksp);
595 }
596 
597 void
599 {
600  // Apply matrix-type options once the per-system matrix prefixes are known. This is different
601  // from vectors: libMesh/PETSc vector construction already sees a global '-vec_type' option,
602  // but prefixed matrix options such as '-nl0_mat_type' cannot match anything until we set the
603  // matrix prefix here. Without this, a matrix may be constructed with the default type and keep
604  // that type for the rest of the solve, unless we not only set the options prefix but also apply
605  // the options to the matrix in this function call.
606  applyMatrixTypeOptions(problem);
607 
608  for (const auto nl_index : make_range(problem.numNonlinearSystems()))
609  {
610  NonlinearSystemBase & nl = problem.getNonlinearSystemBase(nl_index);
611 
612  // dig out PETSc solver
613  auto * const petsc_solver = cast_ptr<PetscNonlinearSolver<Number> *>(nl.nonlinearSolver());
614 
615  // Ensure we properly prefix SNES which in turn prefixes its KSP
616  const char * snes_prefix = nullptr;
617  std::string snes_prefix_str;
618  if (nl.system().prefix_with_name())
619  {
620  snes_prefix_str = nl.system().prefix();
621  snes_prefix = snes_prefix_str.c_str();
622  }
623  SNES snes = petsc_solver->snes(snes_prefix);
624  KSP ksp;
625  LibmeshPetscCallA(nl.comm().get(), SNESGetKSP(snes, &ksp));
626  LibmeshPetscCallA(nl.comm().get(), SNESSetMaxLinearSolveFailures(snes, 1000000));
627  LibmeshPetscCallA(nl.comm().get(), SNESSetCheckJacobianDomainError(snes, PETSC_TRUE));
628  LibmeshPetscCallA(
629  nl.comm().get(),
630  SNESSetConvergenceTest(snes, petscNonlinearConverged, &problem, LIBMESH_PETSC_NULLPTR));
631 
632  petscSetKSPDefaults(problem, ksp);
633  }
634 
635  for (auto sys_index : make_range(problem.numLinearSystems()))
636  {
637  // dig out PETSc solver
638  LinearSystem & lin_sys = problem.getLinearSystem(sys_index);
639  auto & lm_lin_sys = lin_sys.linearImplicitSystem();
640  auto * const petsc_solver =
641  dynamic_cast<PetscLinearSolver<Number> *>(lm_lin_sys.get_linear_solver());
642  // Ensure we properly prefix KSP
643  if (lm_lin_sys.prefix_with_name())
644  petsc_solver->init(lm_lin_sys.prefix().c_str());
645  else
646  petsc_solver->init();
647  // The KSP call here would initialize without a prefix if we hadn't "manually" performed
648  // initialization above
649  KSP ksp = petsc_solver->ksp();
650 
651  if (problem.hasLinearConvergenceObjects())
652  LibmeshPetscCallA(
653  lin_sys.comm().get(),
654  KSPSetConvergenceTest(ksp, petscLinearConverged, &problem, LIBMESH_PETSC_NULLPTR));
655 
656  // We dont set the KSP defaults here because they seem to clash with the linear solve parameters
657  // set in FEProblemBase::solveLinearSystem
658  }
659 }
660 
661 void
663 {
664  setSolveTypeFromParams(fe_problem, params);
665  setLineSearchFromParams(fe_problem, params);
666  setMFFDTypeFromParams(fe_problem, params);
667 }
668 
669 #define checkPrefix(prefix) \
670  mooseAssert(prefix[0] == '-', \
671  "Leading prefix character must be a '-'. Current prefix is '" << prefix << "'"); \
672  mooseAssert((prefix.size() == 1) || (prefix.back() == '_'), \
673  "Terminating prefix character must be a '_'. Current prefix is '" << prefix << "'"); \
674  mooseAssert(MooseUtils::isAllLowercase(prefix), "PETSc prefixes should be all lower-case")
675 
676 void
678  const std::string & prefix,
679  const ParallelParamObject & param_object)
680 {
681  const auto & params = param_object.parameters();
682  processSingletonMooseWrappedOptions(fe_problem, params);
683 
684  // The parameters contained in the Action
685  const auto & petsc_options = params.get<MultiMooseEnum>("petsc_options");
686  const auto & petsc_pair_options =
687  params.get<MooseEnumItem, std::string>("petsc_options_iname", "petsc_options_value");
688 
689  // A reference to the PetscOptions object that contains the settings that will be used in the
690  // solve
691  auto & po = fe_problem.getPetscOptions();
692 
693  // First process the single petsc options/flags
694  addPetscFlagsToPetscOptions(petsc_options, prefix, param_object, po);
695 
696  // Then process the option-value pairs
698  petsc_pair_options, fe_problem.mesh().dimension(), prefix, param_object, po);
699 }
700 
701 void
703 {
704  // Note: Options set in the Preconditioner block will override those set in the Executioner block
705  if (params.isParamValid("solve_type") && !params.isParamValid("_use_eigen_value"))
706  {
707  // Extract the solve type
708  const std::string & solve_type = params.get<MooseEnum>("solve_type");
709  for (const auto i : make_range(fe_problem.numNonlinearSystems()))
710  fe_problem.solverParams(i)._type = Moose::stringToEnum<Moose::SolveType>(solve_type);
711  }
712 }
713 
714 void
716 {
717  // Note: Options set in the Preconditioner block will override those set in the Executioner block
718  if (params.isParamValid("line_search"))
719  {
720  const auto & line_search = params.get<MooseEnum>("line_search");
721  for (const auto i : make_range(fe_problem.numNonlinearSystems()))
722  if (fe_problem.solverParams(i)._line_search == Moose::LS_INVALID || line_search != "default")
723  {
724  Moose::LineSearchType enum_line_search =
725  Moose::stringToEnum<Moose::LineSearchType>(line_search);
726  fe_problem.solverParams(i)._line_search = enum_line_search;
727  if (enum_line_search == LS_CONTACT || enum_line_search == LS_PROJECT)
728  {
729  NonlinearImplicitSystem * nl_system = dynamic_cast<NonlinearImplicitSystem *>(
730  &fe_problem.getNonlinearSystemBase(i).system());
731  if (!nl_system)
732  mooseError("You've requested a line search but you must be solving an EigenProblem. "
733  "These two things are not consistent.");
734  PetscNonlinearSolver<Real> * petsc_nonlinear_solver =
735  dynamic_cast<PetscNonlinearSolver<Real> *>(nl_system->nonlinear_solver.get());
736  if (!petsc_nonlinear_solver)
737  mooseError("Currently the MOOSE line searches all use Petsc, so you "
738  "must use Petsc as your non-linear solver.");
739  petsc_nonlinear_solver->linesearch_object =
740  std::make_unique<ComputeLineSearchObjectWrapper>(fe_problem);
741  }
742  }
743  }
744 }
745 
746 void
748 {
749  if (params.isParamValid("mffd_type"))
750  {
751  const auto & mffd_type = params.get<MooseEnum>("mffd_type");
752  for (const auto i : make_range(fe_problem.numNonlinearSystems()))
753  fe_problem.solverParams(i)._mffd_type = Moose::stringToEnum<Moose::MffdType>(mffd_type);
754  }
755 }
756 
757 template <typename T>
758 void
759 checkUserProvidedPetscOption(const T & option, const ParallelParamObject & param_object)
760 {
761  const auto & string_option = static_cast<const std::string &>(option);
762  if (string_option[0] != '-')
763  param_object.mooseError("PETSc option '", string_option, "' does not begin with '-'");
764 }
765 
766 void
768  std::string prefix,
769  const ParallelParamObject & param_object,
770  PetscOptions & po)
771 {
772  prefix.insert(prefix.begin(), '-');
773  checkPrefix(prefix);
774 
775  // Update the PETSc single flags
776  for (const auto & option : petsc_flags)
777  {
778  checkUserProvidedPetscOption(option, param_object);
779 
780  const std::string & string_option = option.name();
781 
788  if (option == "-log_summary" || option == "-log_view")
789  mooseError("The PETSc option \"-log_summary\" or \"-log_view\" can only be used on the "
790  "command line. Please "
791  "remove it from the input file");
792 
793  // Update the stored items, but do not create duplicates
794  const std::string prefixed_option = prefix + string_option.substr(1);
795  if (!po.flags.isValueSet(prefixed_option))
796  {
797  po.flags.setAdditionalValue(prefixed_option);
798  po.user_set_options.setAdditionalValue(prefixed_option);
799  }
800  }
801 }
802 
803 void
804 setConvergedReasonFlags(FEProblemBase & fe_problem, std::string prefix)
805 {
806  prefix.insert(prefix.begin(), '-');
807  checkPrefix(prefix);
808  libmesh_ignore(fe_problem); // avoid unused warnings for old PETSc
809 
810 #if !PETSC_VERSION_LESS_THAN(3, 14, 0)
811  // the boolean in these pairs denote whether the user has specified any of the reason flags in the
812  // input file
813  std::array<std::string, 2> reason_flags = {{"snes_converged_reason", "ksp_converged_reason"}};
814 
815  auto & po = fe_problem.getPetscOptions();
816 
817  for (const auto & reason_flag : reason_flags)
818  {
819  const auto full_flag = prefix + reason_flag;
820  if (!po.flags.isValueSet(full_flag) && !po.dont_add_these_options.contains(full_flag) &&
821  (std::find_if(po.pairs.begin(),
822  po.pairs.end(),
823  [&full_flag](auto & pair)
824  { return pair.first == (full_flag); }) == po.pairs.end()))
825  po.pairs.emplace_back(full_flag, "::failed");
826  }
827 #endif
828 }
829 
830 void
832  const std::vector<std::pair<MooseEnumItem, std::string>> & petsc_pair_options,
833  const unsigned int mesh_dimension,
834  std::string prefix,
835  const ParallelParamObject & param_object,
836  PetscOptions & po)
837 {
838  prefix.insert(prefix.begin(), '-');
839  checkPrefix(prefix);
840 
841  // Setup the name value pairs
842  bool boomeramg_found = false;
843  bool strong_threshold_found = false;
844 #if !PETSC_VERSION_LESS_THAN(3, 7, 0)
845  bool superlu_dist_found = false;
846  bool fact_pattern_found = false;
847  bool tiny_pivot_found = false;
848 #endif
849  std::string pc_description = "";
850 #if !PETSC_VERSION_LESS_THAN(3, 12, 0)
851  // If users use HMG, we would like to set
852  bool hmg_found = false;
853  bool matptap_found = false;
854  bool hmg_strong_threshold_found = false;
855 #endif
856  std::vector<std::pair<std::string, std::string>> new_options;
857 
858  for (const auto & [option_name, option_value] : petsc_pair_options)
859  {
860  checkUserProvidedPetscOption(option_name, param_object);
861 
862  new_options.clear();
863  const std::string prefixed_option_name =
864  prefix + static_cast<const std::string &>(option_name).substr(1);
865 
866  // Do not add duplicate settings
867  if (auto it =
868  MooseUtils::findPair(po.pairs, po.pairs.begin(), prefixed_option_name, MooseUtils::Any);
869  it == po.pairs.end())
870  {
871 #if !PETSC_VERSION_LESS_THAN(3, 9, 0)
872  if (option_name == "-pc_factor_mat_solver_package")
873  new_options.emplace_back(prefix + "pc_factor_mat_solver_type", option_value);
874 #else
875  if (option_name == "-pc_factor_mat_solver_type")
876  new_options.push_back(prefix + "pc_factor_mat_solver_package", option_value);
877 #endif
878 
879  // Look for a pc description
880  if (option_name == "-pc_type" || option_name == "-sub_pc_type" ||
881  option_name == "-pc_hypre_type")
882  pc_description += option_value + ' ';
883 
884 #if !PETSC_VERSION_LESS_THAN(3, 12, 0)
885  if (option_name == "-pc_type" && option_value == "hmg")
886  hmg_found = true;
887 
888  // MPIAIJ for PETSc 3.12.0: -matptap_via
889  // MAIJ for PETSc 3.12.0: -matmaijptap_via
890  // MPIAIJ for PETSc 3.13 to 3.16: -matptap_via, -matproduct_ptap_via
891  // MAIJ for PETSc 3.13 to 3.16: -matproduct_ptap_via
892  // MPIAIJ for PETSc 3.17 and higher: -matptap_via, -mat_product_algorithm
893  // MAIJ for PETSc 3.17 and higher: -mat_product_algorithm
894 #if !PETSC_VERSION_LESS_THAN(3, 17, 0)
895  if (hmg_found && (option_name == "-matptap_via" || option_name == "-matmaijptap_via" ||
896  option_name == "-matproduct_ptap_via"))
897  new_options.emplace_back(prefix + "mat_product_algorithm", option_value);
898 #elif !PETSC_VERSION_LESS_THAN(3, 13, 0)
899  if (hmg_found && (option_name == "-matptap_via" || option_name == "-matmaijptap_via"))
900  new_options.emplace_back(prefix + "matproduct_ptap_via", option_value);
901 #else
902  if (hmg_found && (option_name == "-matproduct_ptap_via"))
903  {
904  new_options.emplace_back(prefix + "matptap_via", option_value);
905  new_options.emplace_back(prefix + "matmaijptap_via", option_value);
906  }
907 #endif
908 
909  if (option_name == "-matptap_via" || option_name == "-matmaijptap_via" ||
910  option_name == "-matproduct_ptap_via" || option_name == "-mat_product_algorithm")
911  matptap_found = true;
912 
913  // For 3D problems, we need to set this 0.7
914  if (option_name == "-hmg_inner_pc_hypre_boomeramg_strong_threshold")
915  hmg_strong_threshold_found = true;
916 #endif
917  // This special case is common enough that we'd like to handle it for the user.
918  if (option_name == "-pc_hypre_type" && option_value == "boomeramg")
919  boomeramg_found = true;
920  if (option_name == "-pc_hypre_boomeramg_strong_threshold")
921  strong_threshold_found = true;
922 #if !PETSC_VERSION_LESS_THAN(3, 7, 0)
923  if ((option_name == "-pc_factor_mat_solver_package" ||
924  option_name == "-pc_factor_mat_solver_type") &&
925  option_value == "superlu_dist")
926  superlu_dist_found = true;
927  if (option_name == "-mat_superlu_dist_fact")
928  fact_pattern_found = true;
929  if (option_name == "-mat_superlu_dist_replacetinypivot")
930  tiny_pivot_found = true;
931 #endif
932 
933  if (!new_options.empty())
934  {
935  std::copy(new_options.begin(), new_options.end(), std::back_inserter(po.pairs));
936  for (const auto & option : new_options)
937  po.user_set_options.setAdditionalValue(option.first);
938  }
939  else
940  {
941  po.pairs.push_back(std::make_pair(prefixed_option_name, option_value));
942  po.user_set_options.setAdditionalValue(prefixed_option_name);
943  }
944  }
945  else
946  {
947  do
948  {
949  it->second = option_value;
950  it = MooseUtils::findPair(po.pairs, std::next(it), prefixed_option_name, MooseUtils::Any);
951  } while (it != po.pairs.end());
952  }
953  }
954 
955  // When running a 3D mesh with boomeramg, it is almost always best to supply a strong threshold
956  // value. We will provide that for the user here if they haven't supplied it themselves.
957  if (boomeramg_found && !strong_threshold_found && mesh_dimension == 3)
958  {
959  po.pairs.emplace_back(prefix + "pc_hypre_boomeramg_strong_threshold", "0.7");
960  pc_description += "strong_threshold: 0.7 (auto)";
961  }
962 
963 #if !PETSC_VERSION_LESS_THAN(3, 12, 0)
964  if (hmg_found && !hmg_strong_threshold_found && mesh_dimension == 3)
965  {
966  po.pairs.emplace_back(prefix + "hmg_inner_pc_hypre_boomeramg_strong_threshold", "0.7");
967  pc_description += "strong_threshold: 0.7 (auto)";
968  }
969 
970  // Default PETSc PtAP takes too much memory, and it is not quite useful
971  // Let us switch to use new algorithm
972  if (hmg_found && !matptap_found)
973  {
974 #if !PETSC_VERSION_LESS_THAN(3, 17, 0)
975  po.pairs.emplace_back(prefix + "mat_product_algorithm", "allatonce");
976 #elif !PETSC_VERSION_LESS_THAN(3, 13, 0)
977  po.pairs.emplace_back(prefix + "matproduct_ptap_via", "allatonce");
978 #else
979  po.pairs.emplace_back(prefix + "matptap_via", "allatonce");
980  po.pairs.emplace_back(prefix + "matmaijptap_via", "allatonce");
981 #endif
982  }
983 #endif
984 
985 #if !PETSC_VERSION_LESS_THAN(3, 7, 0)
986  // In PETSc-3.7.{0--4}, there is a bug when using superlu_dist, and we have to use
987  // SamePattern_SameRowPerm, otherwise we use whatever we have in PETSc
988  if (superlu_dist_found && !fact_pattern_found)
989  {
990  po.pairs.emplace_back(prefix + "mat_superlu_dist_fact",
991 #if PETSC_VERSION_LESS_THAN(3, 7, 5)
992  "SamePattern_SameRowPerm");
993  pc_description += "mat_superlu_dist_fact: SamePattern_SameRowPerm ";
994 #else
995  "SamePattern");
996  pc_description += "mat_superlu_dist_fact: SamePattern ";
997 #endif
998  }
999 
1000  // restore this superlu option
1001  if (superlu_dist_found && !tiny_pivot_found)
1002  {
1003  po.pairs.emplace_back(prefix + "mat_superlu_dist_replacetinypivot", "1");
1004  pc_description += " mat_superlu_dist_replacetinypivot: true ";
1005  }
1006 #endif
1007  // Set Preconditioner description
1008  if (!pc_description.empty() && prefix.size() > 1)
1009  po.pc_description += "[" + prefix.substr(1, prefix.size() - 2) + "]: ";
1010  po.pc_description += pc_description;
1011 }
1012 
1013 std::set<std::string>
1015 {
1016  return {"default", "shell", "none", "basic", "l2", "bt", "cp"};
1017 }
1018 
1021 {
1023 
1024  MooseEnum solve_type("PJFNK JFNK NEWTON FD LINEAR");
1025  params.addParam<MooseEnum>("solve_type",
1026  solve_type,
1027  "PJFNK: Preconditioned Jacobian-Free Newton Krylov "
1028  "JFNK: Jacobian-Free Newton Krylov "
1029  "NEWTON: Full Newton Solve "
1030  "FD: Use finite differences to compute Jacobian "
1031  "LINEAR: Solving a linear problem");
1032 
1033  MooseEnum mffd_type("wp ds", "wp");
1034  params.addParam<MooseEnum>("mffd_type",
1035  mffd_type,
1036  "Specifies the finite differencing type for "
1037  "Jacobian-free solve types. Note that the "
1038  "default is wp (for Walker and Pernice).");
1039 
1040  params.addParam<MultiMooseEnum>(
1041  "petsc_options", getCommonPetscFlags(), "Singleton PETSc options");
1042  params.addParam<MultiMooseEnum>(
1043  "petsc_options_iname", getCommonPetscKeys(), "Names of PETSc name/value pairs");
1044  params.addParam<std::vector<std::string>>(
1045  "petsc_options_value",
1046  "Values of PETSc name/value pairs (must correspond with \"petsc_options_iname\"");
1047  params.addParamNamesToGroup("solve_type petsc_options petsc_options_iname petsc_options_value "
1048  "mffd_type",
1049  "PETSc");
1050 
1051  return params;
1052 }
1053 
1056 {
1057  return MultiMooseEnum(
1058  "-ksp_monitor_snes_lg -snes_ksp_ew -snes_converged_reason "
1059  "-snes_ksp -snes_linesearch_monitor -snes_mf -snes_mf_operator -snes_monitor "
1060  "-snes_test_display -snes_view -snes_monitor_cancel",
1061  "",
1062  true);
1063 }
1064 
1067 {
1068  return MultiMooseEnum(
1069  "-ksp_converged_reason -ksp_gmres_modifiedgramschmidt -ksp_monitor", "", true);
1070 }
1071 
1074 {
1075  auto options = MultiMooseEnum("-dm_moose_print_embedding -dm_view", "", true);
1076  options.addValidName(getCommonKSPFlags());
1077  options.addValidName(getCommonSNESFlags());
1078  return options;
1079 }
1080 
1083 {
1084  return MultiMooseEnum("-snes_atol -snes_linesearch_type -snes_ls -snes_max_it -snes_rtol "
1085  "-snes_divergence_tolerance -snes_type",
1086  "",
1087  true);
1088 }
1089 
1092 {
1093  return MultiMooseEnum("-ksp_atol -ksp_gmres_restart -ksp_max_it -ksp_pc_side -ksp_rtol "
1094  "-ksp_type -sub_ksp_type",
1095  "",
1096  true);
1097 }
1100 {
1101  auto options = MultiMooseEnum("-mat_fd_coloring_err -mat_fd_type -mat_mffd_type "
1102  "-pc_asm_overlap -pc_factor_levels "
1103  "-pc_factor_mat_ordering_type -pc_hypre_boomeramg_grid_sweeps_all "
1104  "-pc_hypre_boomeramg_max_iter "
1105  "-pc_hypre_boomeramg_strong_threshold -pc_hypre_type -pc_type "
1106  "-sub_pc_type",
1107  "",
1108  true);
1109  options.addValidName(getCommonKSPKeys());
1110  options.addValidName(getCommonSNESKeys());
1111  return options;
1112 }
1113 
1114 bool
1116 {
1117  const PetscOptions & petsc = fe_problem.getPetscOptions();
1118 
1119  int argc;
1120  char ** args;
1121  LibmeshPetscCallA(fe_problem.comm().get(), PetscGetArgs(&argc, &args));
1122 
1123  std::vector<std::string> cml_arg;
1124  for (int i = 0; i < argc; i++)
1125  cml_arg.push_back(args[i]);
1126 
1127  if (MooseUtils::findPair(petsc.pairs, petsc.pairs.begin(), MooseUtils::Any, "vinewtonssls") ==
1128  petsc.pairs.end() &&
1129  MooseUtils::findPair(petsc.pairs, petsc.pairs.begin(), MooseUtils::Any, "vinewtonrsls") ==
1130  petsc.pairs.end() &&
1131  std::find(cml_arg.begin(), cml_arg.end(), "vinewtonssls") == cml_arg.end() &&
1132  std::find(cml_arg.begin(), cml_arg.end(), "vinewtonrsls") == cml_arg.end())
1133  return false;
1134 
1135  return true;
1136 }
1137 
1138 void
1139 setSinglePetscOption(const std::string & name,
1140  const std::string & value /*=""*/,
1141  FEProblemBase * const problem /*=nullptr*/)
1142 {
1143  static const TIMPI::Communicator comm_world(PETSC_COMM_WORLD);
1144  const TIMPI::Communicator & comm = problem ? problem->comm() : comm_world;
1145  LibmeshPetscCallA(comm.get(),
1146  PetscOptionsSetValue(LIBMESH_PETSC_NULLPTR,
1147  name.c_str(),
1148  value == "" ? LIBMESH_PETSC_NULLPTR : value.c_str()));
1149  // Create a single option data base so that we can use PETSC's internal option checking which
1150  // is case insensitive. This is better than re-implementing case-insensitive checks here in this
1151  // TU
1152  ::PetscOptions single_option;
1153  LibmeshPetscCallA(comm.get(), PetscOptionsCreate(&single_option));
1154  LibmeshPetscCallA(comm.get(),
1155  PetscOptionsSetValue(single_option,
1156  name.c_str(),
1157  value == "" ? LIBMESH_PETSC_NULLPTR : value.c_str()));
1158  auto check_problem = [problem, &name]()
1159  {
1160  if (!problem)
1161  mooseError(
1162  "Setting the option '",
1163  name,
1164  "' requires passing a 'problem' parameter. Contact a developer of your application "
1165  "to have them update their code. If in doubt, reach out to the MOOSE team on Github "
1166  "discussions");
1167  };
1168 
1169  // Select vector type from user-passed PETSc options
1170  if (petscOptionsHasName(single_option, "-vec_type"))
1171  {
1172  check_problem();
1173  applyVectorTypeOptions(*problem);
1174  }
1175  // First do a cheap suffix check so unrelated PETSc options do not pay for looping over every
1176  // solver system. Once we know the name looks like a matrix-type option, rely on PETSc's
1177  // option lookup for the actual case-insensitive and prefix-aware matching.
1178  else if (problem && mightBeMatTypeOption(name))
1179  {
1180  errorOnUnprefixedMatTypeOption(single_option, *problem);
1181 
1182  for (const auto i : index_range(problem->_solver_systems))
1183  {
1184  const auto & solver_sys_name = problem->_solver_sys_names[i];
1185  if (!petscOptionsHasName(single_option, "-mat_type", solver_sys_name + "_"))
1186  continue;
1187 
1188  if (problem->solverParams(i)._type == Moose::ST_JFNK)
1189  mooseError("Setting option '", name, "' is incompatible with a JFNK 'solve_type'");
1190 
1191  applyMatrixTypeOptions(*problem, i);
1192  break;
1193  }
1194  }
1195 
1196  LibmeshPetscCallA(comm.get(), PetscOptionsDestroy(&single_option));
1197 }
1198 
1199 void
1200 setSinglePetscOptionIfAppropriate(const MultiMooseEnum & dont_add_these_options,
1201  const std::string & name,
1202  const std::string & value /*=""*/,
1203  FEProblemBase * const problem /*=nullptr*/)
1204 {
1205  if (!dont_add_these_options.contains(name))
1206  setSinglePetscOption(name, value, problem);
1207 }
1208 
1209 void
1210 colorAdjacencyMatrix(PetscScalar * adjacency_matrix,
1211  unsigned int size,
1212  unsigned int colors,
1213  std::vector<unsigned int> & vertex_colors,
1214  const char * coloring_algorithm)
1215 {
1216  // Mat A will be a dense matrix from the incoming data structure
1217  Mat A;
1218  LibmeshPetscCallA(PETSC_COMM_SELF, MatCreate(PETSC_COMM_SELF, &A));
1219  LibmeshPetscCallA(PETSC_COMM_SELF, MatSetSizes(A, size, size, size, size));
1220  LibmeshPetscCallA(PETSC_COMM_SELF, MatSetType(A, MATSEQDENSE));
1221  // PETSc requires a non-const data array to populate the matrix
1222  LibmeshPetscCallA(PETSC_COMM_SELF, MatSeqDenseSetPreallocation(A, adjacency_matrix));
1223  LibmeshPetscCallA(PETSC_COMM_SELF, MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
1224  LibmeshPetscCallA(PETSC_COMM_SELF, MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
1225 
1226  // Convert A to a sparse matrix
1227 #if PETSC_VERSION_LESS_THAN(3, 7, 0)
1228  LibmeshPetscCallA(PETSC_COMM_SELF, MatConvert(A, MATAIJ, MAT_REUSE_MATRIX, &A));
1229 #else
1230  LibmeshPetscCallA(PETSC_COMM_SELF, MatConvert(A, MATAIJ, MAT_INPLACE_MATRIX, &A));
1231 #endif
1232 
1233  ISColoring iscoloring;
1234  MatColoring mc;
1235  LibmeshPetscCallA(PETSC_COMM_SELF, MatColoringCreate(A, &mc));
1236  LibmeshPetscCallA(PETSC_COMM_SELF, MatColoringSetType(mc, coloring_algorithm));
1237  LibmeshPetscCallA(PETSC_COMM_SELF, MatColoringSetMaxColors(mc, static_cast<PetscInt>(colors)));
1238 
1239  // Petsc normally colors by distance two (neighbors of neighbors), we just want one
1240  LibmeshPetscCallA(PETSC_COMM_SELF, MatColoringSetDistance(mc, 1));
1241  LibmeshPetscCallA(PETSC_COMM_SELF, MatColoringSetFromOptions(mc));
1242  LibmeshPetscCallA(PETSC_COMM_SELF, MatColoringApply(mc, &iscoloring));
1243 
1244  PetscInt nn;
1245  IS * is;
1246 #if PETSC_RELEASE_LESS_THAN(3, 12, 0)
1247  LibmeshPetscCallA(PETSC_COMM_SELF, ISColoringGetIS(iscoloring, &nn, &is));
1248 #else
1249  LibmeshPetscCallA(PETSC_COMM_SELF, ISColoringGetIS(iscoloring, PETSC_USE_POINTER, &nn, &is));
1250 #endif
1251 
1252  if (nn > static_cast<PetscInt>(colors))
1253  throw std::runtime_error("Not able to color with designated number of colors");
1254 
1255  for (int i = 0; i < nn; i++)
1256  {
1257  PetscInt isize;
1258  const PetscInt * indices;
1259  LibmeshPetscCallA(PETSC_COMM_SELF, ISGetLocalSize(is[i], &isize));
1260  LibmeshPetscCallA(PETSC_COMM_SELF, ISGetIndices(is[i], &indices));
1261  for (int j = 0; j < isize; j++)
1262  {
1263  mooseAssert(indices[j] < static_cast<PetscInt>(vertex_colors.size()), "Index out of bounds");
1264  vertex_colors[indices[j]] = i;
1265  }
1266  LibmeshPetscCallA(PETSC_COMM_SELF, ISRestoreIndices(is[i], &indices));
1267  }
1268 
1269  LibmeshPetscCallA(PETSC_COMM_SELF, MatDestroy(&A));
1270  LibmeshPetscCallA(PETSC_COMM_SELF, MatColoringDestroy(&mc));
1271  LibmeshPetscCallA(PETSC_COMM_SELF, ISColoringDestroy(&iscoloring));
1272 }
1273 
1274 void
1275 dontAddPetscFlag(const std::string & flag, PetscOptions & petsc_options)
1276 {
1277  if (!petsc_options.dont_add_these_options.contains(flag))
1278  petsc_options.dont_add_these_options.setAdditionalValue(flag);
1279 }
1280 
1281 void
1283 {
1284  dontAddPetscFlag("-snes_converged_reason", fe_problem.getPetscOptions());
1285 }
1286 
1287 void
1289 {
1290  dontAddPetscFlag("-ksp_converged_reason", fe_problem.getPetscOptions());
1291 }
1292 
1293 void
1295 {
1296  auto & petsc_options = fe_problem.getPetscOptions();
1297  for (const auto & flag : getCommonKSPFlags().getNames())
1298  dontAddPetscFlag(flag, petsc_options);
1299  for (const auto & key : getCommonKSPKeys().getNames())
1300  dontAddPetscFlag(key, petsc_options);
1301 }
1302 
1303 void
1305 {
1306  dontAddCommonSNESOptions(fe_problem, "");
1307 }
1308 
1309 void
1310 dontAddCommonSNESOptions(FEProblemBase & fe_problem, const std::string & prefix)
1311 {
1312  auto & petsc_options = fe_problem.getPetscOptions();
1313  for (const auto & flag : getCommonSNESFlags().getNames())
1314  dontAddPetscFlag("-" + prefix + flag.substr(1), petsc_options);
1315  for (const auto & key : getCommonSNESKeys().getNames())
1316  dontAddPetscFlag("-" + prefix + key.substr(1), petsc_options);
1317 }
1318 
1319 std::unique_ptr<PetscMatrix<Number>>
1321  Mat & mat,
1322  const std::string & binary_mat_file,
1323  const unsigned int mat_number_to_load)
1324 {
1325  LibmeshPetscCallA(comm.get(), MatCreate(comm.get(), &mat));
1326  PetscViewer matviewer;
1327  LibmeshPetscCallA(
1328  comm.get(),
1329  PetscViewerBinaryOpen(comm.get(), binary_mat_file.c_str(), FILE_MODE_READ, &matviewer));
1330  for (unsigned int i = 0; i < mat_number_to_load; ++i)
1331  LibmeshPetscCallA(comm.get(), MatLoad(mat, matviewer));
1332  LibmeshPetscCallA(comm.get(), PetscViewerDestroy(&matviewer));
1333 
1334  return std::make_unique<PetscMatrix<Number>>(mat, comm);
1335 }
1336 
1337 } // Namespace PetscSupport
1338 } // Namespace MOOSE
std::string name(const ElemQuality q)
MultiMooseEnum getCommonKSPKeys()
A helper function to produce a MultiMooseEnum with commonly used PETSc ksp option names (keys) ...
matrices_iterator matrices_begin()
MultiMooseEnum getCommonPetscKeys()
A helper function to produce a MultiMooseEnum with commonly used PETSc iname options (keys in key-val...
void resetFailNextNonlinearConvergenceCheck()
Tell the problem that the nonlinear convergence check(s) may proceed as normal.
bool isSNESVI(FEProblemBase &fe_problem)
check if SNES type is variational inequalities (VI) solver
vectors_iterator vectors_end()
const std::vector< ConvergenceName > & getNonlinearConvergenceNames() const
Gets the nonlinear system convergence object name(s).
Moose::PetscSupport::PetscOptions & getPetscOptions()
Retrieve a writable reference the PETSc options (used by PetscSupport)
void addPetscFlagsToPetscOptions(const MultiMooseEnum &petsc_flags, std::string prefix, const ParallelParamObject &param_object, PetscOptions &petsc_options)
Populate flags in a given PetscOptions object using a vector of input arguments.
Definition: PetscSupport.C:767
KSPNormType getPetscKSPNormType(Moose::MooseKSPNormType kspnorm)
Definition: PetscSupport.C:531
KOKKOS_INLINE_FUNCTION const T * find(const T &target, const T *const begin, const T *const end)
Find a value in an array.
Definition: KokkosUtils.h:40
void setMFFDTypeFromParams(FEProblemBase &fe_problem, const InputParameters &params)
Sets the FE problem&#39;s matrix-free finite difference type from the input params.
Definition: PetscSupport.C:747
std::unique_ptr< NonlinearSolver< Number > > nonlinear_solver
Full Newton Solve.
Definition: MooseTypes.h:895
const ExecFlagType EXEC_NONLINEAR_CONVERGENCE
Definition: Moose.C:34
static void petscSetupOutput()
Output string for setting up PETSC output.
Definition: Console.C:855
std::string _prefix
Definition: SolverParams.h:35
virtual std::size_t numNonlinearSystems() const override
std::set< std::string > getPetscValidLineSearches()
Returns the valid petsc line search options as a set of strings.
Moose::LineSearchType _line_search
Definition: SolverParams.h:20
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:311
void setAdditionalValue(const std::string &names)
Insert operators Operator to insert (push_back) values into the enum.
const ExecFlagType EXEC_LINEAR_CONVERGENCE
Definition: Moose.C:32
std::vector< std::pair< R1, R2 > > get(const std::string &param1, const std::string &param2) const
Combine two vector parameters into a single vector of pairs.
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)
Populate name and value pairs in a given PetscOptions object using vectors of input arguments...
Definition: PetscSupport.C:831
void petscSetDefaults(FEProblemBase &problem)
Sets the default options for PETSc.
Definition: PetscSupport.C:598
libMesh::LinearImplicitSystem & linearImplicitSystem()
Return a reference to the stored linear implicit system.
Definition: LinearSystem.h:93
virtual MooseConvergenceStatus checkConvergence(unsigned int iter)=0
Returns convergence status.
MultiMooseEnum getCommonSNESFlags()
A helper function to produce a MultiMooseEnum with commonly used PETSc snes single options (flags) ...
const InputParameters & parameters() const
Get the parameters of the object.
Definition: MooseBase.h:131
sys_type & system()
virtual void init(const char *name=nullptr) override
A struct for storing the various types of petsc options and values.
Definition: PetscSupport.h:44
MultiMooseEnum flags
Single value PETSc options (flags)
Definition: PetscSupport.h:56
virtual libMesh::System & system()=0
Get the reference to the libMesh system.
PetscFunctionBegin
void setSolveTypeFromParams(FEProblemBase &fe_problem, const InputParameters &params)
Sets the FE problem&#39;s solve type from the input params.
Definition: PetscSupport.C:702
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
const Parallel::Communicator & comm() const
void petscSetDefaultKSPNormType(FEProblemBase &problem, KSP ksp)
Set norm type.
Definition: PetscSupport.C:552
std::unique_ptr< PetscMatrix< Number > > createMatrixFromFile(const libMesh::Parallel::Communicator &comm, Mat &petsc_mat, const std::string &binary_mat_file, unsigned int mat_number_to_load=1)
Create a matrix from a binary file.
Solving a linear problem.
Definition: MooseTypes.h:897
void petscSetKSPDefaults(FEProblemBase &problem, KSP ksp)
Set the default options for a KSP.
Definition: PetscSupport.C:576
std::vector< std::shared_ptr< SolverSystem > > _solver_systems
Combined container to base pointer of every solver system.
std::vector< std::pair< std::string, std::string > > pairs
PETSc key-value pairs.
Definition: PetscSupport.h:53
virtual libMesh::NonlinearSolver< Number > * nonlinearSolver()=0
The following methods are specializations for using the libMesh::Parallel::packed_range_* routines fo...
vectors_iterator vectors_begin()
MffdType
Type of the matrix-free finite-differencing parameter.
Definition: MooseTypes.h:991
Specialization of SubProblem for solving nonlinear equations plus auxiliary equations.
bool hasLinearConvergenceObjects() const
Whether we have linear convergence objects.
InputParameters emptyInputParameters()
This class wraps provides and tracks access to command line parameters.
Definition: CommandLine.h:29
MooseKSPNormType
Norm type for converge test.
Definition: MooseTypes.h:879
Nonlinear system to be solved.
MPI_Status status
virtual const std::string & name() const
Definition: SystemBase.C:1342
PCSide getPetscPCSide(Moose::PCSideType pcs)
Definition: PetscSupport.C:514
void processSingletonMooseWrappedOptions(FEProblemBase &fe_problem, const InputParameters &params)
Process some MOOSE-wrapped PETSc options.
Definition: PetscSupport.C:662
void checkUserProvidedPetscOption(const T &option, const ParallelParamObject &param_object)
Definition: PetscSupport.C:759
void setConvergedReasonFlags(FEProblemBase &fe_problem, std::string prefix)
Set flags that will instruct the user on the reason their simulation diverged from PETSc&#39;s perspectiv...
Definition: PetscSupport.C:804
bool contains(const std::string &value) const
Methods for seeing if a value is set in the MultiMooseEnum.
std::vector< SolverSystemName > _solver_sys_names
The union of nonlinear and linear system names.
virtual void execute(const ExecFlagType &exec_type)
Convenience function for performing execution of MOOSE systems.
void dontAddCommonKSPOptions(FEProblemBase &fe_problem)
Function to ensure that common KSP options are not added to the PetscOptions storage object to be lat...
PetscErrorCode petscLinearConverged(KSP, PetscInt it, PetscReal, KSPConvergedReason *reason, void *ctx)
Definition: PetscSupport.C:464
void libmesh_ignore(const Args &...)
Use whatever we have in PETSc.
Definition: MooseTypes.h:873
PetscErrorCode petscNonlinearConverged(SNES, PetscInt it, PetscReal, PetscReal, PetscReal, SNESConvergedReason *reason, void *ctx)
Definition: PetscSupport.C:416
const T & get(std::string_view) const
MultiMooseEnum getCommonPetscFlags()
A helper function to produce a MultiMooseEnum with commonly used PETSc single options (flags) ...
Moose::MffdType _mffd_type
Definition: SolverParams.h:21
Real value(unsigned n, unsigned alpha, unsigned beta, Real x)
LineSearchType
Type of the line search.
Definition: MooseTypes.h:974
virtual Convergence & getConvergence(const std::string &name, const THREAD_ID tid=0) const
Gets a Convergence object.
void MooseMatView(SparseMatrix< Number > &mat)
Definition: PetscSupport.C:75
virtual unsigned int dimension() const
Returns MeshBase::mesh_dimension(), (not MeshBase::spatial_dimension()!) of the underlying libMesh me...
Definition: MooseMesh.C:3012
std::string prefix() const
Use whatever we have in PETSc.
Definition: MooseTypes.h:885
void dontAddPetscFlag(const std::string &flag, PetscOptions &petsc_options)
Function to ensure that a particular petsc option is not added to the PetscOptions storage object to ...
std::string stringify(const MffdType &t)
Definition: PetscSupport.C:248
NonlinearSystemBase & currentNonlinearSystem()
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
Jacobian-Free Newton Krylov.
Definition: MooseTypes.h:894
virtual libMesh::EquationSystems & es() override
void setSolverOptions(const SolverParams &solver_params, const MultiMooseEnum &dont_add_these_options)
Definition: PetscSupport.C:263
std::unique_ptr< NumericVector< Number > > solution
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition: MooseEnum.h:54
Moose::SolveType _type
Definition: SolverParams.h:19
PetscErrorCode PetscInt const PetscInt IS * is
Use finite differences to compute Jacobian.
Definition: MooseTypes.h:896
void addPetscOptionsFromCommandline(FEProblemBase *const problem=nullptr)
Insert command-line PETSc options into the active PETSc options database.
Definition: PetscSupport.C:309
NonlinearSystemBase & getNonlinearSystemBase(const unsigned int sys_num)
bool isValueSet(const std::string &value) const
Methods for seeing if a value is set in the MultiMooseEnum.
unsigned int number() const
Gets the number of this system.
Definition: SystemBase.C:1158
AuxiliarySystem & getAuxiliarySystem()
void petscSetOptions(const PetscOptions &po, const SolverParams &solver_params, FEProblemBase *const problem=nullptr)
A function for setting the PETSc options in PETSc from the options supplied to MOOSE.
Definition: PetscSupport.C:378
std::vector< std::string > getNames() const
Method for returning a vector of all valid enumeration names for this instance.
bool getFailNextSystemConvergenceCheck() const
Whether it will fail the next system convergence check(s), triggering failed step behavior...
LinearSystem & getLinearSystem(unsigned int sys_num)
Get non-constant reference to a linear system.
MooseConvergenceStatus
Status returned by calls to checkConvergence.
Definition: Convergence.h:33
void setLineSearchFromParams(FEProblemBase &fe_problem, const InputParameters &params)
Sets the FE problem&#39;s line search from the input params.
Definition: PetscSupport.C:715
void dontAddCommonSNESOptions(FEProblemBase &fe_problem)
Function to ensure that common SNES options are not added to the PetscOptions storage object to be la...
unsigned int get(unsigned int i) const
Indexing operator Operator to retrieve the id of an item from the MultiMooseEnum. ...
void setSinglePetscOption(const std::string &name, const std::string &value="", FEProblemBase *const problem=nullptr)
A wrapper function for dealing with different versions of PetscOptionsSetValue.
MultiMooseEnum getCommonKSPFlags()
A helper function to produce a MultiMooseEnum with commonly used PETSc ksp single options (flags) ...
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
InputParameters getPetscValidParams()
Returns the PETSc options that are common between Executioners and Preconditioners.
PetscErrorCode petscSetupOutput(CommandLine *cmd_line)
Definition: PetscSupport.C:399
std::unique_ptr< ComputeLineSearchObject > linesearch_object
Class for containing MooseEnum item information.
Definition: MooseEnumItem.h:18
void petscSetOptionsHelper(const PetscOptions &po, FEProblemBase *const problem)
Definition: PetscSupport.C:358
means not set
Definition: MooseTypes.h:993
void dontAddNonlinearConvergedReason(FEProblemBase &fe_problem)
Function to ensure that -snes_converged_reason is not added to the PetscOptions storage object to be ...
void colorAdjacencyMatrix(PetscScalar *adjacency_matrix, unsigned int size, unsigned int colors, std::vector< unsigned int > &vertex_colors, const char *coloring_algorithm)
This method takes an adjacency matrix, and a desired number of colors and applies a graph coloring al...
bool getFailNextNonlinearConvergenceCheck() const
Whether it will skip further residual evaluations and fail the next nonlinear convergence check(s) ...
IntRange< T > make_range(T beg, T end)
virtual MooseMesh & mesh() override
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type and optionally a file path to the top-level block p...
Definition: MooseBase.h:281
LinearSystem & currentLinearSystem()
Get a non-constant reference to the current linear system.
void resetFailNextSystemConvergenceCheck()
Tell the problem that the system convergence check(s) may proceed as normal.
PCSideType
Preconditioning side.
Definition: MooseTypes.h:868
SolverParams & solverParams(unsigned int solver_sys_num=0)
Get the solver parameters.
SolverSystem & getSolverSystem(unsigned int sys_num)
Get non-constant reference to a solver system.
std::unique_ptr< NumericVector< Number > > current_local_solution
MultiMooseEnum getCommonSNESKeys()
A helper function to produce a MultiMooseEnum with commonly used PETSc snes option names (keys) ...
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an optional parameter and a documentation string to the InputParameters object...
Linear system to be solved.
Definition: LinearSystem.h:39
void setSinglePetscOptionIfAppropriate(const MultiMooseEnum &dont_add_these_options, const std::string &name, const std::string &value="", FEProblemBase *const problem=nullptr)
Same as setSinglePetscOption, but does not set the option if it doesn&#39;t make sense for the current si...
void dontAddLinearConvergedReason(FEProblemBase &fe_problem)
Function to ensure that -ksp_converged_reason is not added to the PetscOptions storage object to be l...
void * ctx
Preconditioned Jacobian-Free Newton Krylov.
Definition: MooseTypes.h:893
virtual std::size_t numLinearSystems() const override
MOOSE now contains C++17 code, so give a reasonable error message stating what the user can do to add...
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type...
means not set
Definition: MooseTypes.h:976
virtual libMesh::System & system() override
Get the reference to the libMesh system.
void storePetscOptions(FEProblemBase &fe_problem, const std::string &prefix, const ParallelParamObject &param_object)
Stores the PETSc options supplied from the parameter object on the problem.
Definition: PetscSupport.C:677
std::string pc_description
Preconditioner description.
Definition: PetscSupport.h:65
MultiMooseEnum dont_add_these_options
Flags to explicitly not set, even if they are specified programmatically.
Definition: PetscSupport.h:59
Moose::MooseKSPNormType getMooseKSPNormType()
Get the norm in which the linear convergence is measured.
Definition: SolverSystem.h:102
void prefix_with_name(bool value)
Base class shared by both Action and MooseObject.
PetscFunctionReturn(LIBMESH_PETSC_SUCCESS)
void MooseVecView(NumericVector< Number > &vector)
Definition: PetscSupport.C:68
virtual std::size_t numSolverSystems() const override
MultiMooseEnum user_set_options
Options that are set by the user at the input level.
Definition: PetscSupport.h:62
matrices_iterator matrices_end()
auto index_range(const T &sizable)
const std::vector< std::string > & getArguments()
Definition: CommandLine.h:138
Moose::PCSideType getPCSide()
Get the current preconditioner side.
Definition: SolverSystem.h:91
void petscSetDefaultPCSide(FEProblemBase &problem, KSP ksp)
Setup which side we want to apply preconditioner.
Definition: PetscSupport.C:563
const std::vector< ConvergenceName > & getLinearConvergenceNames() const
Gets the linear convergence object name(s).
void addParamNamesToGroup(const std::string &space_delim_names, const std::string group_name)
This method takes a space delimited list of parameter names and adds them to the specified group name...
bool isParamValid(const std::string &name) const
This method returns parameters that have been initialized in one fashion or another, i.e.
virtual libMesh::System & system() override
Get the reference to the libMesh system.