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