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
65using namespace libMesh;
66
67void
69{
70 PetscVector<Number> & petsc_vec = static_cast<PetscVector<Number> &>(vector);
71 LibmeshPetscCallA(vector.comm().get(), VecView(petsc_vec.vec(), 0));
72}
73
74void
76{
77 PetscMatrixBase<Number> & petsc_mat = static_cast<PetscMatrix<Number> &>(mat);
78 LibmeshPetscCallA(mat.comm().get(), MatView(petsc_mat.mat(), 0));
79}
80
81void
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
89void
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
97namespace Moose
98{
99namespace PetscSupport
100{
101
102PetscOptionsScope::PetscOptionsScope(FEProblemBase & problem) : _problem(problem), _pushed(false)
103{
104#if !PETSC_RELEASE_LESS_THAN(3, 12, 0)
106 {
107 LibmeshPetscCallA(_problem.comm().get(), PetscOptionsPush(_problem.petscOptionsDatabase()));
108 _pushed = true;
109 }
110#endif
111}
112
114{
115#if !PETSC_RELEASE_LESS_THAN(3, 12, 0)
116 if (_pushed)
117 PetscCallAbort(_problem.comm().get(), PetscOptionsPop());
118#endif
119}
120
121namespace
122{
123
124void
125applySystemVectorTypeOptions(FEProblemBase & problem, libMesh::System & lm_sys)
126{
127 for (auto & [_, vec] : as_range(lm_sys.vectors_begin(), lm_sys.vectors_end()))
128 {
129 auto * const petsc_vec = cast_ptr<PetscVector<Number> *>(vec.get());
130 LibmeshPetscCallA(problem.comm().get(), VecSetFromOptions(petsc_vec->vec()));
131 }
132
133 // The solution vectors aren't included in the system vectors storage.
134 auto * petsc_vec = cast_ptr<PetscVector<Number> *>(lm_sys.solution.get());
135 LibmeshPetscCallA(problem.comm().get(), VecSetFromOptions(petsc_vec->vec()));
136 petsc_vec = cast_ptr<PetscVector<Number> *>(lm_sys.current_local_solution.get());
137 LibmeshPetscCallA(problem.comm().get(), VecSetFromOptions(petsc_vec->vec()));
138}
139
140void
141applyVectorTypeOptions(FEProblemBase & problem)
142{
143 for (const auto sys_index : make_range(problem.numSolverSystems()))
144 applySystemVectorTypeOptions(problem, problem.getSolverSystem(sys_index).system());
145
146 applySystemVectorTypeOptions(problem, problem.getAuxiliarySystem().system());
147}
148
149bool
150petscOptionsHasName(::PetscOptions options,
151 const std::string & name,
152 const std::string & prefix = "")
153{
154 PetscBool found = PETSC_FALSE;
155 const char * const prefix_ptr = prefix.empty() ? nullptr : prefix.c_str();
156 LibmeshPetscCallA(PETSC_COMM_WORLD,
157 PetscOptionsHasName(options, prefix_ptr, name.c_str(), &found));
158 return found;
159}
160
161bool
162hasMatrixFreeSolveType(const FEProblemBase & problem)
163{
164 for (const auto sys_index : make_range(problem.numSolverSystems()))
165 if (const auto solve_type = problem.solverParams(sys_index)._type;
166 solve_type == Moose::ST_JFNK || solve_type == Moose::ST_PJFNK)
167 return true;
168
169 return false;
170}
171
172bool
173mightBeMatTypeOption(const std::string & name)
174{
175 static constexpr std::string_view mat_type_suffix = "mat_type";
176 return name.size() >= mat_type_suffix.size() &&
177 std::equal(mat_type_suffix.rbegin(),
178 mat_type_suffix.rend(),
179 name.rbegin(),
180 [](const char left, const char right)
181 // tolower requires representability by unsigned char
182 {
183 return static_cast<int>(left) ==
184 std::tolower(libMesh::cast_int<unsigned char>(right));
185 });
186}
187
188void
189errorOnUnprefixedMatTypeOption(::PetscOptions options, FEProblemBase & problem)
190{
191 if (!petscOptionsHasName(options, "-mat_type"))
192 return;
193
194 std::string error_string =
195 "Setting option '-mat_type' is not supported without a solver-system prefix. Use an option "
196 "such as '-" +
197 problem.getSolverSystem(0).name() + "_mat_type' for assembled libMesh matrices.";
198 if (hasMatrixFreeSolveType(problem))
199 error_string +=
200 " Attempting to change the matrix "
201 "type for the MFFD matrix type used to represent the Jacobian for (P)JFNK solve "
202 "types is not supported.";
203 mooseError(error_string);
204}
205
206// Allow iterating over all systems or allowing caller to specify a specific system for which to
207// apply matrix type options
208void
209applyMatrixTypeOptions(FEProblemBase & problem,
210 const std::optional<std::size_t> system_index = std::nullopt)
211{
212 const auto begin = system_index.value_or(0);
213 const auto end = system_index ? begin + 1 : problem.numSolverSystems();
214
215 for (const auto sys_index : make_range(begin, end))
216 {
217 auto & solver_system = problem.getSolverSystem(sys_index);
218 auto & lm_sys = solver_system.system();
219
220 // Even in matrix-free modes the libMesh matrix wrappers can exist before the PETSc Mat does.
221 if (problem.solverParams(sys_index)._type == Moose::ST_JFNK)
222 continue;
223
224 for (auto & [_, mat] : as_range(lm_sys.matrices_begin(), lm_sys.matrices_end()))
225 if (auto * const petsc_mat = dynamic_cast<PetscMatrixBase<Number> *>(mat.get()); petsc_mat)
226 {
227 LibmeshPetscCallA(
228 problem.comm().get(),
229 MatSetOptionsPrefix(petsc_mat->mat(), (solver_system.name() + "_").c_str()));
230 LibmeshPetscCallA(problem.comm().get(), MatSetFromOptions(petsc_mat->mat()));
231 }
232 }
233}
234
235} // namespace
236
237std::string
239{
240 switch (t)
241 {
242 case LS_BASIC:
243 return "basic";
244 case LS_DEFAULT:
245 return "default";
246 case LS_NONE:
247 return "none";
248 case LS_SHELL:
249 return "shell";
250 case LS_L2:
251 return "l2";
252 case LS_BT:
253 return "bt";
254 case LS_CP:
255 return "cp";
256 case LS_CONTACT:
257 return "contact";
258 case LS_PROJECT:
259 return "project";
260 case LS_INVALID:
261 mooseError("Invalid LineSearchType");
262 }
263 return "";
264}
265
266std::string
268{
269 switch (t)
270 {
271 case MFFD_WP:
272 return "wp";
273 case MFFD_DS:
274 return "ds";
275 case MFFD_INVALID:
276 mooseError("Invalid MffdType");
277 }
278 return "";
279}
280
281void
282setSolverOptions(const SolverParams & solver_params, const MultiMooseEnum & dont_add_these_options)
283{
284 const auto prefix_with_dash = '-' + solver_params._prefix;
285 // set PETSc options implied by a solve type
286 switch (solver_params._type)
287 {
288 case Moose::ST_PJFNK:
289 setSinglePetscOptionIfAppropriate(dont_add_these_options,
290 prefix_with_dash + "snes_mf_operator");
291 setSinglePetscOptionIfAppropriate(dont_add_these_options,
292 prefix_with_dash + "mat_mffd_type",
293 stringify(solver_params._mffd_type));
294 break;
295
296 case Moose::ST_JFNK:
297 setSinglePetscOptionIfAppropriate(dont_add_these_options, prefix_with_dash + "snes_mf");
298 setSinglePetscOptionIfAppropriate(dont_add_these_options,
299 prefix_with_dash + "mat_mffd_type",
300 stringify(solver_params._mffd_type));
301 break;
302
303 case Moose::ST_NEWTON:
304 break;
305
306 case Moose::ST_FD:
307 setSinglePetscOptionIfAppropriate(dont_add_these_options, prefix_with_dash + "snes_fd");
308 break;
309
310 case Moose::ST_LINEAR:
312 dont_add_these_options, prefix_with_dash + "snes_type", "ksponly");
313 setSinglePetscOptionIfAppropriate(dont_add_these_options,
314 prefix_with_dash + "snes_monitor_cancel");
315 break;
316 }
317
318 Moose::LineSearchType ls_type = solver_params._line_search;
319 if (ls_type == Moose::LS_NONE)
320 ls_type = Moose::LS_BASIC;
321
322 if (ls_type != Moose::LS_DEFAULT && ls_type != Moose::LS_CONTACT && ls_type != Moose::LS_PROJECT)
324 dont_add_these_options, prefix_with_dash + "snes_linesearch_type", stringify(ls_type));
325}
326
327void
329{
330 // commandline options always win
331 // the options from a user commandline will overwrite the existing ones if any conflicts
332 int argc;
333 char ** args;
334
335 LibmeshPetscCallA(PETSC_COMM_WORLD, PetscGetArgs(&argc, &args));
336 std::vector<const char *> cl_args(args + 1, args + argc);
337 const auto cl_argc = libMesh::cast_int<int>(cl_args.size());
338
339 ::PetscOptions command_line_options;
340 LibmeshPetscCallA(PETSC_COMM_WORLD, PetscOptionsCreate(&command_line_options));
341 LibmeshPetscCallA(PETSC_COMM_WORLD,
342 PetscOptionsInsertArgs(command_line_options, cl_argc, cl_args.data()));
343 LibmeshPetscCallA(PETSC_COMM_WORLD,
344 PetscOptionsInsertArgs(LIBMESH_PETSC_NULLPTR, cl_argc, cl_args.data()));
345
346 if (!problem)
347 {
348 LibmeshPetscCallA(PETSC_COMM_WORLD, PetscOptionsDestroy(&command_line_options));
349 return;
350 }
351
352 errorOnUnprefixedMatTypeOption(command_line_options, *problem);
353
354 // Some vector/matrix-type options may have been consumed before the PETSc database rebuild.
355 // Replay only the command-line-controlled applications so input-file options handled through
356 // setSinglePetscOption() do not pay the cost twice.
357 const bool have_vec_type = petscOptionsHasName(command_line_options, "-vec_type");
358 bool have_mat_type = false;
359
360 for (const auto sys_index : make_range(problem->numSolverSystems()))
361 {
362 have_mat_type = petscOptionsHasName(
363 command_line_options, "-mat_type", problem->getSolverSystem(sys_index).name() + "_");
364 if (have_mat_type)
365 break;
366 }
367
368 if (have_vec_type)
369 applyVectorTypeOptions(*problem);
370 if (have_mat_type)
371 applyMatrixTypeOptions(*problem);
372
373 LibmeshPetscCallA(PETSC_COMM_WORLD, PetscOptionsDestroy(&command_line_options));
374}
375
376void
378{
379 // Add any additional options specified in the input file
380 for (const auto & flag : po.flags)
381 // Need to use name method here to pass a str instead of an EnumItem because
382 // we don't care if the id attributes match
383 if (!po.dont_add_these_options.contains(flag.name()) ||
384 po.user_set_options.contains(flag.name()))
385 setSinglePetscOption(flag.rawName().c_str());
386
387 // Add option pairs
388 for (auto & option : po.pairs)
389 if (!po.dont_add_these_options.contains(option.first) ||
390 po.user_set_options.contains(option.first))
391 setSinglePetscOption(option.first, option.second, problem);
392
394}
395
396void
398 const SolverParams & solver_params,
399 FEProblemBase * const problem)
400{
401 PetscCallAbort(PETSC_COMM_WORLD, PetscOptionsClear(LIBMESH_PETSC_NULLPTR));
402 setSolverOptions(solver_params, po.dont_add_these_options);
403 petscSetOptionsHelper(po, problem);
404}
405
406void
408 const std::vector<SolverParams> & solver_params_vec,
409 FEProblemBase * const problem)
410{
411 PetscCallAbort(PETSC_COMM_WORLD, PetscOptionsClear(LIBMESH_PETSC_NULLPTR));
412 for (const auto & solver_params : solver_params_vec)
413 setSolverOptions(solver_params, po.dont_add_these_options);
414 petscSetOptionsHelper(po, problem);
415}
416
417PetscErrorCode
419{
421 char code[10] = {45, 45, 109, 111, 111, 115, 101};
422 const std::vector<std::string> argv = cmd_line->getArguments();
423 for (const auto & arg : argv)
424 {
425 if (arg.compare(code) == 0)
426 {
428 break;
429 }
430 }
431 PetscFunctionReturn(PETSC_SUCCESS);
432}
433
434PetscErrorCode
436 PetscInt it,
437 PetscReal /*xnorm*/,
438 PetscReal /*snorm*/,
439 PetscReal /*fnorm*/,
440 SNESConvergedReason * reason,
441 void * ctx)
442{
444 FEProblemBase & problem = *static_cast<FEProblemBase *>(ctx);
445
446 // execute objects that may be used in convergence check
448
449 // perform the convergence check
452 {
455 }
456 else
457 {
458 auto & convergence = problem.getConvergence(
460 status = convergence.checkConvergence(it);
461 }
462
463 // convert convergence status to PETSc converged reason
464 switch (status)
465 {
467 *reason = SNES_CONVERGED_ITERATING;
468 break;
469
471 *reason = SNES_CONVERGED_FNORM_ABS;
472 break;
473
475 *reason = SNES_DIVERGED_DTOL;
476 break;
477 }
478
479 PetscFunctionReturn(PETSC_SUCCESS);
480}
481
482PetscErrorCode
484 KSP /*ksp*/, PetscInt it, PetscReal /*norm*/, KSPConvergedReason * reason, void * ctx)
485{
487 FEProblemBase & problem = *static_cast<FEProblemBase *>(ctx);
488
489 // execute objects that may be used in convergence check
490 // Right now, setting objects to execute on this flag would be ignored except in the
491 // linear-system-only use case.
493
494 // perform the convergence check
497 {
500 }
501 else
502 {
503 auto & convergence = problem.getConvergence(
505 status = convergence.checkConvergence(it);
506 }
507
508 // convert convergence status to PETSc converged reason
509 switch (status)
510 {
512 *reason = KSP_CONVERGED_ITERATING;
513 break;
514
515 // TODO: find a KSP code that works better for this case
517#if PETSC_VERSION_LESS_THAN(3, 24, 0)
518 *reason = KSP_CONVERGED_RTOL_NORMAL;
519#else
520 *reason = KSP_CONVERGED_RTOL_NORMAL_EQUATIONS;
521#endif
522 break;
523
525 *reason = KSP_DIVERGED_DTOL;
526 break;
527 }
528
529 PetscFunctionReturn(PETSC_SUCCESS);
530}
531
532PCSide
534{
535 switch (pcs)
536 {
537 case Moose::PCS_LEFT:
538 return PC_LEFT;
539 case Moose::PCS_RIGHT:
540 return PC_RIGHT;
542 return PC_SYMMETRIC;
543 default:
544 mooseError("Unknown PC side requested.");
545 break;
546 }
547}
548
549KSPNormType
551{
552 switch (kspnorm)
553 {
554 case Moose::KSPN_NONE:
555 return KSP_NORM_NONE;
557 return KSP_NORM_PRECONDITIONED;
559 return KSP_NORM_UNPRECONDITIONED;
561 return KSP_NORM_NATURAL;
563 return KSP_NORM_DEFAULT;
564 default:
565 mooseError("Unknown KSP norm type requested.");
566 break;
567 }
568}
569
570void
572{
573 for (const auto i : make_range(problem.numSolverSystems()))
574 {
575 SolverSystem & sys = problem.getSolverSystem(i);
576 LibmeshPetscCallA(problem.comm().get(),
577 KSPSetNormType(ksp, getPetscKSPNormType(sys.getMooseKSPNormType())));
578 }
579}
580
581void
583{
584 for (const auto i : make_range(problem.numSolverSystems()))
585 {
586 SolverSystem & sys = problem.getSolverSystem(i);
587
588 // PETSc 3.2.x+
589 if (sys.getPCSide() != Moose::PCS_DEFAULT)
590 LibmeshPetscCallA(problem.comm().get(), KSPSetPCSide(ksp, getPetscPCSide(sys.getPCSide())));
591 }
592}
593
594void
596{
597 auto & es = problem.es();
598
599 PetscReal rtol = es.parameters.get<Real>("linear solver tolerance");
600 PetscReal atol = es.parameters.get<Real>("linear solver absolute tolerance");
601
602 // MOOSE defaults this to -1 for some dumb reason
603 if (atol < 0)
604 atol = 1e-50;
605
606 PetscReal maxits = es.parameters.get<unsigned int>("linear solver maximum iterations");
607
608 // 1e100 is because we don't use divtol currently
609 LibmeshPetscCallA(problem.comm().get(), KSPSetTolerances(ksp, rtol, atol, 1e100, maxits));
610
611 petscSetDefaultPCSide(problem, ksp);
612
613 petscSetDefaultKSPNormType(problem, ksp);
614}
615
616void
618{
619 // Apply matrix-type options once the per-system matrix prefixes are known. This is different
620 // from vectors: libMesh/PETSc vector construction already sees a global '-vec_type' option,
621 // but prefixed matrix options such as '-nl0_mat_type' cannot match anything until we set the
622 // matrix prefix here. Without this, a matrix may be constructed with the default type and keep
623 // that type for the rest of the solve, unless we not only set the options prefix but also apply
624 // the options to the matrix in this function call.
625 applyMatrixTypeOptions(problem);
626
627 for (const auto nl_index : make_range(problem.numNonlinearSystems()))
628 {
629 NonlinearSystemBase & nl = problem.getNonlinearSystemBase(nl_index);
630
631 // dig out PETSc solver
632 auto * const petsc_solver = cast_ptr<PetscNonlinearSolver<Number> *>(nl.nonlinearSolver());
633
634 // Ensure we properly prefix SNES which in turn prefixes its KSP
635 const char * snes_prefix = nullptr;
636 std::string snes_prefix_str;
637 if (nl.system().prefix_with_name())
638 {
639 snes_prefix_str = nl.system().prefix();
640 snes_prefix = snes_prefix_str.c_str();
641 }
642 SNES snes = petsc_solver->snes(snes_prefix);
643 KSP ksp;
644 LibmeshPetscCallA(nl.comm().get(), SNESGetKSP(snes, &ksp));
645 LibmeshPetscCallA(nl.comm().get(), SNESSetMaxLinearSolveFailures(snes, 1000000));
646 LibmeshPetscCallA(nl.comm().get(), SNESSetCheckJacobianDomainError(snes, PETSC_TRUE));
647 LibmeshPetscCallA(
648 nl.comm().get(),
649 SNESSetConvergenceTest(snes, petscNonlinearConverged, &problem, LIBMESH_PETSC_NULLPTR));
650
651 petscSetKSPDefaults(problem, ksp);
652 }
653
654 for (auto sys_index : make_range(problem.numLinearSystems()))
655 {
656 // dig out PETSc solver
657 LinearSystem & lin_sys = problem.getLinearSystem(sys_index);
658 auto & lm_lin_sys = lin_sys.linearImplicitSystem();
659 auto * const petsc_solver =
660 dynamic_cast<PetscLinearSolver<Number> *>(lm_lin_sys.get_linear_solver());
661 // Ensure we properly prefix KSP
662 if (lm_lin_sys.prefix_with_name())
663 petsc_solver->init(lm_lin_sys.prefix().c_str());
664 else
665 petsc_solver->init();
666 // The KSP call here would initialize without a prefix if we hadn't "manually" performed
667 // initialization above
668 KSP ksp = petsc_solver->ksp();
669
670 if (problem.hasLinearConvergenceObjects())
671 LibmeshPetscCallA(
672 lin_sys.comm().get(),
673 KSPSetConvergenceTest(ksp, petscLinearConverged, &problem, LIBMESH_PETSC_NULLPTR));
674
675 // We dont set the KSP defaults here because they seem to clash with the linear solve parameters
676 // set in FEProblemBase::solveLinearSystem
677 }
678}
679
680void
682{
683 setSolveTypeFromParams(fe_problem, params);
684 setLineSearchFromParams(fe_problem, params);
685 setMFFDTypeFromParams(fe_problem, params);
686}
687
688#define checkPrefix(prefix) \
689 mooseAssert(prefix[0] == '-', \
690 "Leading prefix character must be a '-'. Current prefix is '" << prefix << "'"); \
691 mooseAssert((prefix.size() == 1) || (prefix.back() == '_'), \
692 "Terminating prefix character must be a '_'. Current prefix is '" << prefix << "'"); \
693 mooseAssert(MooseUtils::isAllLowercase(prefix), "PETSc prefixes should be all lower-case")
694
695void
697 const std::string & prefix,
698 const ParallelParamObject & param_object)
699{
700 const auto & params = param_object.parameters();
701 processSingletonMooseWrappedOptions(fe_problem, params);
702
703 // The parameters contained in the Action
704 const auto & petsc_options = params.get<MultiMooseEnum>("petsc_options");
705 const auto & petsc_pair_options =
706 params.get<MooseEnumItem, std::string>("petsc_options_iname", "petsc_options_value");
707
708 // A reference to the PetscOptions object that contains the settings that will be used in the
709 // solve
710 auto & po = fe_problem.getPetscOptions();
711
712 // First process the single petsc options/flags
713 addPetscFlagsToPetscOptions(petsc_options, prefix, param_object, po);
714
715 // Then process the option-value pairs
717 petsc_pair_options, fe_problem.mesh().dimension(), prefix, param_object, po);
718}
719
720void
722{
723 // Note: Options set in the Preconditioner block will override those set in the Executioner block
724 if (params.isParamValid("solve_type") && !params.isParamValid("_use_eigen_value"))
725 {
726 // Extract the solve type
727 const std::string & solve_type = params.get<MooseEnum>("solve_type");
728 for (const auto i : make_range(fe_problem.numNonlinearSystems()))
729 fe_problem.solverParams(i)._type = Moose::stringToEnum<Moose::SolveType>(solve_type);
730 }
731}
732
733void
735{
736 // Note: Options set in the Preconditioner block will override those set in the Executioner block
737 if (params.isParamValid("line_search"))
738 {
739 const auto & line_search = params.get<MooseEnum>("line_search");
740 for (const auto i : make_range(fe_problem.numNonlinearSystems()))
741 if (fe_problem.solverParams(i)._line_search == Moose::LS_INVALID || line_search != "default")
742 {
743 Moose::LineSearchType enum_line_search =
744 Moose::stringToEnum<Moose::LineSearchType>(line_search);
745 fe_problem.solverParams(i)._line_search = enum_line_search;
746 if (enum_line_search == LS_CONTACT || enum_line_search == LS_PROJECT)
747 {
748 NonlinearImplicitSystem * nl_system = dynamic_cast<NonlinearImplicitSystem *>(
749 &fe_problem.getNonlinearSystemBase(i).system());
750 if (!nl_system)
751 mooseError("You've requested a line search but you must be solving an EigenProblem. "
752 "These two things are not consistent.");
753 PetscNonlinearSolver<Real> * petsc_nonlinear_solver =
754 dynamic_cast<PetscNonlinearSolver<Real> *>(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:32
const ExecFlagType EXEC_NONLINEAR_CONVERGENCE
Definition Moose.C:34
PetscFunctionBegin
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:855
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()
const std::vector< ConvergenceName > & getNonlinearConvergenceNames() const
Gets the nonlinear system convergence object name(s).
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:2986
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.
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
std::unique_ptr< NonlinearSolver< Number > > nonlinear_solver
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...
PetscFunctionReturn(LIBMESH_PETSC_SUCCESS)
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
auto index_range(const T &sizable)
void * ctx
void libmesh_ignore(const Args &...)
if(subdm)
Real Number
PetscErrorCode PetscInt const PetscInt IS * is
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
IntRange< T > make_range(T beg, T end)