Line data Source code
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 "DisplacedProblem.h"
19 : #include "PenetrationLocator.h"
20 : #include "NearestNodeLocator.h"
21 : #include "MooseTypes.h"
22 : #include "MooseUtils.h"
23 : #include "CommandLine.h"
24 : #include "Console.h"
25 : #include "MultiMooseEnum.h"
26 : #include "Conversion.h"
27 : #include "Executioner.h"
28 : #include "MooseMesh.h"
29 : #include "ComputeLineSearchObjectWrapper.h"
30 : #include "Convergence.h"
31 : #include "ParallelParamObject.h"
32 :
33 : #include "libmesh/equation_systems.h"
34 : #include "libmesh/linear_implicit_system.h"
35 : #include "libmesh/nonlinear_implicit_system.h"
36 : #include "libmesh/petsc_linear_solver.h"
37 : #include "libmesh/petsc_matrix.h"
38 : #include "libmesh/petsc_nonlinear_solver.h"
39 : #include "libmesh/petsc_preconditioner.h"
40 : #include "libmesh/petsc_vector.h"
41 : #include "libmesh/sparse_matrix.h"
42 : #include "libmesh/petsc_solver_exception.h"
43 : #include "libmesh/simple_range.h"
44 :
45 : // PETSc includes
46 : #include <petsc.h>
47 : #include <petscsnes.h>
48 : #include <petscksp.h>
49 :
50 : // For graph coloring
51 : #include <petscmat.h>
52 : #include <petscis.h>
53 : #include <petscdm.h>
54 :
55 : // PetscDMMoose include
56 : #include "PetscDMMoose.h"
57 :
58 : // Standard includes
59 : #include <ostream>
60 : #include <fstream>
61 : #include <string>
62 :
63 : using namespace libMesh;
64 :
65 : void
66 0 : MooseVecView(NumericVector<Number> & vector)
67 : {
68 0 : PetscVector<Number> & petsc_vec = static_cast<PetscVector<Number> &>(vector);
69 0 : LibmeshPetscCallA(vector.comm().get(), VecView(petsc_vec.vec(), 0));
70 0 : }
71 :
72 : void
73 0 : MooseMatView(SparseMatrix<Number> & mat)
74 : {
75 0 : PetscMatrixBase<Number> & petsc_mat = static_cast<PetscMatrix<Number> &>(mat);
76 0 : LibmeshPetscCallA(mat.comm().get(), MatView(petsc_mat.mat(), 0));
77 0 : }
78 :
79 : void
80 0 : MooseVecView(const NumericVector<Number> & vector)
81 : {
82 0 : PetscVector<Number> & petsc_vec =
83 : static_cast<PetscVector<Number> &>(const_cast<NumericVector<Number> &>(vector));
84 0 : LibmeshPetscCallA(vector.comm().get(), VecView(petsc_vec.vec(), 0));
85 0 : }
86 :
87 : void
88 0 : MooseMatView(const SparseMatrix<Number> & mat)
89 : {
90 0 : PetscMatrixBase<Number> & petsc_mat =
91 : static_cast<PetscMatrix<Number> &>(const_cast<SparseMatrix<Number> &>(mat));
92 0 : LibmeshPetscCallA(mat.comm().get(), MatView(petsc_mat.mat(), 0));
93 0 : }
94 :
95 : namespace Moose
96 : {
97 : namespace PetscSupport
98 : {
99 :
100 : std::string
101 3061 : stringify(const LineSearchType & t)
102 : {
103 3061 : switch (t)
104 : {
105 2966 : case LS_BASIC:
106 5932 : return "basic";
107 0 : case LS_DEFAULT:
108 0 : return "default";
109 0 : case LS_NONE:
110 0 : return "none";
111 0 : case LS_SHELL:
112 0 : return "shell";
113 0 : case LS_L2:
114 0 : return "l2";
115 23 : case LS_BT:
116 46 : return "bt";
117 72 : case LS_CP:
118 144 : return "cp";
119 0 : case LS_CONTACT:
120 0 : return "contact";
121 0 : case LS_PROJECT:
122 0 : return "project";
123 0 : case LS_INVALID:
124 0 : mooseError("Invalid LineSearchType");
125 : }
126 0 : return "";
127 : }
128 :
129 : std::string
130 29350 : stringify(const MffdType & t)
131 : {
132 29350 : switch (t)
133 : {
134 29340 : case MFFD_WP:
135 58680 : return "wp";
136 10 : case MFFD_DS:
137 20 : return "ds";
138 0 : case MFFD_INVALID:
139 0 : mooseError("Invalid MffdType");
140 : }
141 0 : return "";
142 : }
143 :
144 : void
145 43286 : setSolverOptions(const SolverParams & solver_params, const MultiMooseEnum & dont_add_these_options)
146 : {
147 43286 : const auto prefix_with_dash = '-' + solver_params._prefix;
148 : // set PETSc options implied by a solve type
149 43286 : switch (solver_params._type)
150 : {
151 29228 : case Moose::ST_PJFNK:
152 58456 : setSinglePetscOptionIfAppropriate(dont_add_these_options,
153 58456 : prefix_with_dash + "snes_mf_operator");
154 29228 : setSinglePetscOptionIfAppropriate(dont_add_these_options,
155 58456 : prefix_with_dash + "mat_mffd_type",
156 58456 : stringify(solver_params._mffd_type));
157 29228 : break;
158 :
159 122 : case Moose::ST_JFNK:
160 122 : setSinglePetscOptionIfAppropriate(dont_add_these_options, prefix_with_dash + "snes_mf");
161 122 : setSinglePetscOptionIfAppropriate(dont_add_these_options,
162 244 : prefix_with_dash + "mat_mffd_type",
163 244 : stringify(solver_params._mffd_type));
164 122 : break;
165 :
166 11619 : case Moose::ST_NEWTON:
167 11619 : break;
168 :
169 0 : case Moose::ST_FD:
170 0 : setSinglePetscOptionIfAppropriate(dont_add_these_options, prefix_with_dash + "snes_fd");
171 0 : break;
172 :
173 2317 : case Moose::ST_LINEAR:
174 6951 : setSinglePetscOptionIfAppropriate(
175 4634 : dont_add_these_options, prefix_with_dash + "snes_type", "ksponly");
176 4634 : setSinglePetscOptionIfAppropriate(dont_add_these_options,
177 4634 : prefix_with_dash + "snes_monitor_cancel");
178 2317 : break;
179 : }
180 :
181 43286 : Moose::LineSearchType ls_type = solver_params._line_search;
182 43286 : if (ls_type == Moose::LS_NONE)
183 2812 : ls_type = Moose::LS_BASIC;
184 :
185 43286 : if (ls_type != Moose::LS_DEFAULT && ls_type != Moose::LS_CONTACT && ls_type != Moose::LS_PROJECT)
186 3061 : setSinglePetscOptionIfAppropriate(
187 6122 : dont_add_these_options, prefix_with_dash + "snes_linesearch_type", stringify(ls_type));
188 43286 : }
189 :
190 : void
191 43610 : addPetscOptionsFromCommandline()
192 : {
193 : // commandline options always win
194 : // the options from a user commandline will overwrite the existing ones if any conflicts
195 : { // Get any options specified on the command-line
196 : int argc;
197 : char ** args;
198 :
199 43610 : LibmeshPetscCallA(PETSC_COMM_WORLD, PetscGetArgs(&argc, &args));
200 : #if PETSC_VERSION_LESS_THAN(3, 7, 0)
201 : LibmeshPetscCallA(PETSC_COMM_WORLD, PetscOptionsInsert(&argc, &args, NULL));
202 : #else
203 43610 : LibmeshPetscCallA(PETSC_COMM_WORLD,
204 : PetscOptionsInsert(LIBMESH_PETSC_NULLPTR, &argc, &args, NULL));
205 : #endif
206 : }
207 43610 : }
208 :
209 : void
210 43052 : petscSetOptionsHelper(const PetscOptions & po, FEProblemBase * const problem)
211 : {
212 : // Add any additional options specified in the input file
213 45662 : for (const auto & flag : po.flags)
214 : // Need to use name method here to pass a str instead of an EnumItem because
215 : // we don't care if the id attributes match
216 2610 : if (!po.dont_add_these_options.contains(flag.name()) ||
217 0 : po.user_set_options.contains(flag.name()))
218 10440 : setSinglePetscOption(flag.rawName().c_str());
219 :
220 : // Add option pairs
221 182279 : for (auto & option : po.pairs)
222 140750 : if (!po.dont_add_these_options.contains(option.first) ||
223 1523 : po.user_set_options.contains(option.first))
224 137714 : setSinglePetscOption(option.first, option.second, problem);
225 :
226 43052 : addPetscOptionsFromCommandline();
227 43052 : }
228 :
229 : void
230 1815 : petscSetOptions(const PetscOptions & po,
231 : const SolverParams & solver_params,
232 : FEProblemBase * const problem)
233 : {
234 1815 : PetscCallAbort(PETSC_COMM_WORLD, PetscOptionsClear(LIBMESH_PETSC_NULLPTR));
235 1815 : setSolverOptions(solver_params, po.dont_add_these_options);
236 1815 : petscSetOptionsHelper(po, problem);
237 1815 : }
238 :
239 : void
240 41237 : petscSetOptions(const PetscOptions & po,
241 : const std::vector<SolverParams> & solver_params_vec,
242 : FEProblemBase * const problem)
243 : {
244 41237 : PetscCallAbort(PETSC_COMM_WORLD, PetscOptionsClear(LIBMESH_PETSC_NULLPTR));
245 82708 : for (const auto & solver_params : solver_params_vec)
246 41471 : setSolverOptions(solver_params, po.dont_add_these_options);
247 41237 : petscSetOptionsHelper(po, problem);
248 41237 : }
249 :
250 : PetscErrorCode
251 48795 : petscSetupOutput(CommandLine * cmd_line)
252 : {
253 : PetscFunctionBegin;
254 48795 : char code[10] = {45, 45, 109, 111, 111, 115, 101};
255 48795 : const std::vector<std::string> argv = cmd_line->getArguments();
256 567234 : for (const auto & arg : argv)
257 : {
258 518439 : if (arg.compare(code) == 0)
259 : {
260 0 : Console::petscSetupOutput();
261 0 : break;
262 : }
263 : }
264 48795 : PetscFunctionReturn(PETSC_SUCCESS);
265 48795 : }
266 :
267 : PetscErrorCode
268 816586 : petscNonlinearConverged(SNES /*snes*/,
269 : PetscInt it,
270 : PetscReal /*xnorm*/,
271 : PetscReal /*snorm*/,
272 : PetscReal /*fnorm*/,
273 : SNESConvergedReason * reason,
274 : void * ctx)
275 : {
276 : PetscFunctionBegin;
277 816586 : FEProblemBase & problem = *static_cast<FEProblemBase *>(ctx);
278 :
279 : // execute objects that may be used in convergence check
280 816586 : problem.execute(EXEC_NONLINEAR_CONVERGENCE);
281 :
282 : // perform the convergence check
283 : Convergence::MooseConvergenceStatus status;
284 816586 : if (problem.getFailNextNonlinearConvergenceCheck())
285 : {
286 212 : status = Convergence::MooseConvergenceStatus::DIVERGED;
287 212 : problem.resetFailNextNonlinearConvergenceCheck();
288 : }
289 : else
290 : {
291 816374 : auto & convergence = problem.getConvergence(
292 816374 : problem.getNonlinearConvergenceNames()[problem.currentNonlinearSystem().number()]);
293 816374 : status = convergence.checkConvergence(it);
294 : }
295 :
296 : // convert convergence status to PETSc converged reason
297 816582 : switch (status)
298 : {
299 508626 : case Convergence::MooseConvergenceStatus::ITERATING:
300 508626 : *reason = SNES_CONVERGED_ITERATING;
301 508626 : break;
302 :
303 307692 : case Convergence::MooseConvergenceStatus::CONVERGED:
304 307692 : *reason = SNES_CONVERGED_FNORM_ABS;
305 307692 : break;
306 :
307 264 : case Convergence::MooseConvergenceStatus::DIVERGED:
308 264 : *reason = SNES_DIVERGED_DTOL;
309 264 : break;
310 : }
311 :
312 816582 : PetscFunctionReturn(PETSC_SUCCESS);
313 : }
314 :
315 : PetscErrorCode
316 2634 : petscLinearConverged(
317 : KSP /*ksp*/, PetscInt it, PetscReal /*norm*/, KSPConvergedReason * reason, void * ctx)
318 : {
319 : PetscFunctionBegin;
320 2634 : FEProblemBase & problem = *static_cast<FEProblemBase *>(ctx);
321 :
322 : // execute objects that may be used in convergence check
323 : // Right now, setting objects to execute on this flag would be ignored except in the
324 : // linear-system-only use case.
325 2634 : problem.execute(EXEC_LINEAR_CONVERGENCE);
326 :
327 : // perform the convergence check
328 : Convergence::MooseConvergenceStatus status;
329 2634 : if (problem.getFailNextSystemConvergenceCheck())
330 : {
331 0 : status = Convergence::MooseConvergenceStatus::DIVERGED;
332 0 : problem.resetFailNextSystemConvergenceCheck();
333 : }
334 : else
335 : {
336 2634 : auto & convergence = problem.getConvergence(
337 2634 : problem.getLinearConvergenceNames()[problem.currentLinearSystem().number()]);
338 2634 : status = convergence.checkConvergence(it);
339 : }
340 :
341 : // convert convergence status to PETSc converged reason
342 2634 : switch (status)
343 : {
344 2201 : case Convergence::MooseConvergenceStatus::ITERATING:
345 2201 : *reason = KSP_CONVERGED_ITERATING;
346 2201 : break;
347 :
348 : // TODO: find a KSP code that works better for this case
349 433 : case Convergence::MooseConvergenceStatus::CONVERGED:
350 433 : *reason = KSP_CONVERGED_RTOL_NORMAL;
351 433 : break;
352 :
353 0 : case Convergence::MooseConvergenceStatus::DIVERGED:
354 0 : *reason = KSP_DIVERGED_DTOL;
355 0 : break;
356 : }
357 :
358 2634 : PetscFunctionReturn(PETSC_SUCCESS);
359 : }
360 :
361 : PCSide
362 0 : getPetscPCSide(Moose::PCSideType pcs)
363 : {
364 0 : switch (pcs)
365 : {
366 0 : case Moose::PCS_LEFT:
367 0 : return PC_LEFT;
368 0 : case Moose::PCS_RIGHT:
369 0 : return PC_RIGHT;
370 0 : case Moose::PCS_SYMMETRIC:
371 0 : return PC_SYMMETRIC;
372 0 : default:
373 0 : mooseError("Unknown PC side requested.");
374 : break;
375 : }
376 : }
377 :
378 : KSPNormType
379 406284 : getPetscKSPNormType(Moose::MooseKSPNormType kspnorm)
380 : {
381 406284 : switch (kspnorm)
382 : {
383 0 : case Moose::KSPN_NONE:
384 0 : return KSP_NORM_NONE;
385 0 : case Moose::KSPN_PRECONDITIONED:
386 0 : return KSP_NORM_PRECONDITIONED;
387 406284 : case Moose::KSPN_UNPRECONDITIONED:
388 406284 : return KSP_NORM_UNPRECONDITIONED;
389 0 : case Moose::KSPN_NATURAL:
390 0 : return KSP_NORM_NATURAL;
391 0 : case Moose::KSPN_DEFAULT:
392 0 : return KSP_NORM_DEFAULT;
393 0 : default:
394 0 : mooseError("Unknown KSP norm type requested.");
395 : break;
396 : }
397 : }
398 :
399 : void
400 379626 : petscSetDefaultKSPNormType(FEProblemBase & problem, KSP ksp)
401 : {
402 785910 : for (const auto i : make_range(problem.numSolverSystems()))
403 : {
404 406284 : SolverSystem & sys = problem.getSolverSystem(i);
405 406284 : LibmeshPetscCallA(problem.comm().get(),
406 : KSPSetNormType(ksp, getPetscKSPNormType(sys.getMooseKSPNormType())));
407 : }
408 379626 : }
409 :
410 : void
411 379626 : petscSetDefaultPCSide(FEProblemBase & problem, KSP ksp)
412 : {
413 785910 : for (const auto i : make_range(problem.numSolverSystems()))
414 : {
415 406284 : SolverSystem & sys = problem.getSolverSystem(i);
416 :
417 : // PETSc 3.2.x+
418 406284 : if (sys.getPCSide() != Moose::PCS_DEFAULT)
419 0 : LibmeshPetscCallA(problem.comm().get(), KSPSetPCSide(ksp, getPetscPCSide(sys.getPCSide())));
420 : }
421 379626 : }
422 :
423 : void
424 378380 : petscSetKSPDefaults(FEProblemBase & problem, KSP ksp)
425 : {
426 378380 : auto & es = problem.es();
427 :
428 378380 : PetscReal rtol = es.parameters.get<Real>("linear solver tolerance");
429 378380 : PetscReal atol = es.parameters.get<Real>("linear solver absolute tolerance");
430 :
431 : // MOOSE defaults this to -1 for some dumb reason
432 378380 : if (atol < 0)
433 0 : atol = 1e-50;
434 :
435 378380 : PetscReal maxits = es.parameters.get<unsigned int>("linear solver maximum iterations");
436 :
437 : // 1e100 is because we don't use divtol currently
438 378380 : LibmeshPetscCallA(problem.comm().get(), KSPSetTolerances(ksp, rtol, atol, 1e100, maxits));
439 :
440 378380 : petscSetDefaultPCSide(problem, ksp);
441 :
442 378380 : petscSetDefaultKSPNormType(problem, ksp);
443 378380 : }
444 :
445 : void
446 370379 : petscSetDefaults(FEProblemBase & problem)
447 : {
448 : // We care about both nonlinear and linear systems when setting the SNES prefix because
449 : // SNESSetOptionsPrefix will also set its KSP prefix which could compete with linear system KSPs
450 748439 : for (const auto nl_index : make_range(problem.numNonlinearSystems()))
451 : {
452 378060 : NonlinearSystemBase & nl = problem.getNonlinearSystemBase(nl_index);
453 :
454 : //
455 : // prefix system matrices
456 : //
457 :
458 378060 : auto & lm_sys = nl.system();
459 : // This check is necessary because we still have at least the system matrix lying around even
460 : // when doing matrix-free, but critically even though the libmesh object(s) exist, the wrapped
461 : // PETSc Mat(s) do not
462 378060 : if (problem.solverParams(nl_index)._type != Moose::ST_JFNK)
463 756850 : for (auto & [mat_name, mat] : as_range(lm_sys.matrices_begin(), lm_sys.matrices_end()))
464 : {
465 378923 : libmesh_ignore(mat_name);
466 378923 : if (auto * const petsc_mat = dynamic_cast<PetscMatrixBase<Number> *>(mat.get()); petsc_mat)
467 : {
468 378923 : LibmeshPetscCallA(nl.comm().get(),
469 : MatSetOptionsPrefix(petsc_mat->mat(), (nl.name() + "_").c_str()));
470 : // We should call this here to ensure that options from the command line are properly
471 : // applied
472 378923 : LibmeshPetscCallA(nl.comm().get(), MatSetFromOptions(petsc_mat->mat()));
473 : }
474 : }
475 :
476 : //
477 : // prefix SNES/KSP
478 : //
479 :
480 : // dig out PETSc solver
481 378060 : auto * const petsc_solver = cast_ptr<PetscNonlinearSolver<Number> *>(nl.nonlinearSolver());
482 378060 : const char * snes_prefix = nullptr;
483 378060 : std::string snes_prefix_str;
484 378060 : if (nl.system().prefix_with_name())
485 : {
486 26658 : snes_prefix_str = nl.system().prefix();
487 26658 : snes_prefix = snes_prefix_str.c_str();
488 : }
489 378060 : SNES snes = petsc_solver->snes(snes_prefix);
490 : KSP ksp;
491 378060 : LibmeshPetscCallA(nl.comm().get(), SNESGetKSP(snes, &ksp));
492 :
493 378060 : LibmeshPetscCallA(nl.comm().get(), SNESSetMaxLinearSolveFailures(snes, 1000000));
494 :
495 378060 : LibmeshPetscCallA(nl.comm().get(), SNESSetCheckJacobianDomainError(snes, PETSC_TRUE));
496 :
497 : // In 3.0.0, the context pointer must actually be used, and the
498 : // final argument to KSPSetConvergenceTest() is a pointer to a
499 : // routine for destroying said private data context. In this case,
500 : // we use the default context provided by PETSc in addition to
501 : // a few other tests.
502 : {
503 378060 : LibmeshPetscCallA(
504 : nl.comm().get(),
505 : SNESSetConvergenceTest(snes, petscNonlinearConverged, &problem, LIBMESH_PETSC_NULLPTR));
506 : }
507 :
508 378060 : petscSetKSPDefaults(problem, ksp);
509 378060 : }
510 :
511 376476 : for (auto sys_index : make_range(problem.numLinearSystems()))
512 : {
513 : // dig out PETSc solver
514 6097 : LinearSystem & lin_sys = problem.getLinearSystem(sys_index);
515 6097 : PetscLinearSolver<Number> * petsc_solver = dynamic_cast<PetscLinearSolver<Number> *>(
516 6097 : lin_sys.linearImplicitSystem().get_linear_solver());
517 6097 : KSP ksp = petsc_solver->ksp();
518 :
519 6097 : if (problem.hasLinearConvergenceObjects())
520 447 : LibmeshPetscCallA(
521 : lin_sys.comm().get(),
522 : KSPSetConvergenceTest(ksp, petscLinearConverged, &problem, LIBMESH_PETSC_NULLPTR));
523 :
524 : // We dont set the KSP defaults here because they seem to clash with the linear solve parameters
525 : // set in FEProblemBase::solveLinearSystem
526 : }
527 370379 : }
528 :
529 : void
530 77633 : processSingletonMooseWrappedOptions(FEProblemBase & fe_problem, const InputParameters & params)
531 : {
532 77633 : setSolveTypeFromParams(fe_problem, params);
533 77633 : setLineSearchFromParams(fe_problem, params);
534 77633 : setMFFDTypeFromParams(fe_problem, params);
535 77633 : }
536 :
537 : #define checkPrefix(prefix) \
538 : mooseAssert(prefix[0] == '-', \
539 : "Leading prefix character must be a '-'. Current prefix is '" << prefix << "'"); \
540 : mooseAssert((prefix.size() == 1) || (prefix.back() == '_'), \
541 : "Terminating prefix character must be a '_'. Current prefix is '" << prefix << "'"); \
542 : mooseAssert(MooseUtils::isAllLowercase(prefix), "PETSc prefixes should be all lower-case")
543 :
544 : void
545 77633 : storePetscOptions(FEProblemBase & fe_problem,
546 : const std::string & prefix,
547 : const ParallelParamObject & param_object)
548 : {
549 77633 : const auto & params = param_object.parameters();
550 77633 : processSingletonMooseWrappedOptions(fe_problem, params);
551 :
552 : // The parameters contained in the Action
553 77633 : const auto & petsc_options = params.get<MultiMooseEnum>("petsc_options");
554 : const auto & petsc_pair_options =
555 232899 : params.get<MooseEnumItem, std::string>("petsc_options_iname", "petsc_options_value");
556 :
557 : // A reference to the PetscOptions object that contains the settings that will be used in the
558 : // solve
559 77633 : auto & po = fe_problem.getPetscOptions();
560 :
561 : // First process the single petsc options/flags
562 77633 : addPetscFlagsToPetscOptions(petsc_options, prefix, param_object, po);
563 :
564 : // Then process the option-value pairs
565 155266 : addPetscPairsToPetscOptions(
566 77633 : petsc_pair_options, fe_problem.mesh().dimension(), prefix, param_object, po);
567 77633 : }
568 :
569 : void
570 92266 : setSolveTypeFromParams(FEProblemBase & fe_problem, const InputParameters & params)
571 : {
572 : // Note: Options set in the Preconditioner block will override those set in the Executioner block
573 353366 : if (params.isParamValid("solve_type") && !params.isParamValid("_use_eigen_value"))
574 : {
575 : // Extract the solve type
576 37696 : const std::string & solve_type = params.get<MooseEnum>("solve_type");
577 75838 : for (const auto i : make_range(fe_problem.numNonlinearSystems()))
578 38142 : fe_problem.solverParams(i)._type = Moose::stringToEnum<Moose::SolveType>(solve_type);
579 37696 : }
580 92266 : }
581 :
582 : void
583 77633 : setLineSearchFromParams(FEProblemBase & fe_problem, const InputParameters & params)
584 : {
585 : // Note: Options set in the Preconditioner block will override those set in the Executioner block
586 155266 : if (params.isParamValid("line_search"))
587 : {
588 62870 : const auto & line_search = params.get<MooseEnum>("line_search");
589 124922 : for (const auto i : make_range(fe_problem.numNonlinearSystems()))
590 62052 : if (fe_problem.solverParams(i)._line_search == Moose::LS_INVALID || line_search != "default")
591 : {
592 : Moose::LineSearchType enum_line_search =
593 61666 : Moose::stringToEnum<Moose::LineSearchType>(line_search);
594 61666 : fe_problem.solverParams(i)._line_search = enum_line_search;
595 61666 : if (enum_line_search == LS_CONTACT || enum_line_search == LS_PROJECT)
596 : {
597 0 : NonlinearImplicitSystem * nl_system = dynamic_cast<NonlinearImplicitSystem *>(
598 0 : &fe_problem.getNonlinearSystemBase(i).system());
599 0 : if (!nl_system)
600 0 : mooseError("You've requested a line search but you must be solving an EigenProblem. "
601 : "These two things are not consistent.");
602 : PetscNonlinearSolver<Real> * petsc_nonlinear_solver =
603 0 : dynamic_cast<PetscNonlinearSolver<Real> *>(nl_system->nonlinear_solver.get());
604 0 : if (!petsc_nonlinear_solver)
605 0 : mooseError("Currently the MOOSE line searches all use Petsc, so you "
606 : "must use Petsc as your non-linear solver.");
607 : petsc_nonlinear_solver->linesearch_object =
608 0 : std::make_unique<ComputeLineSearchObjectWrapper>(fe_problem);
609 : }
610 : }
611 : }
612 77633 : }
613 :
614 : void
615 77633 : setMFFDTypeFromParams(FEProblemBase & fe_problem, const InputParameters & params)
616 : {
617 155266 : if (params.isParamValid("mffd_type"))
618 : {
619 77053 : const auto & mffd_type = params.get<MooseEnum>("mffd_type");
620 153556 : for (const auto i : make_range(fe_problem.numNonlinearSystems()))
621 76503 : fe_problem.solverParams(i)._mffd_type = Moose::stringToEnum<Moose::MffdType>(mffd_type);
622 : }
623 77633 : }
624 :
625 : template <typename T>
626 : void
627 59460 : checkUserProvidedPetscOption(const T & option, const ParallelParamObject & param_object)
628 : {
629 59460 : const auto & string_option = static_cast<const std::string &>(option);
630 59460 : if (string_option[0] != '-')
631 0 : param_object.mooseError("PETSc option '", string_option, "' does not begin with '-'");
632 59460 : }
633 :
634 : void
635 77633 : addPetscFlagsToPetscOptions(const MultiMooseEnum & petsc_flags,
636 : std::string prefix,
637 : const ParallelParamObject & param_object,
638 : PetscOptions & po)
639 : {
640 77633 : prefix.insert(prefix.begin(), '-');
641 : checkPrefix(prefix);
642 :
643 : // Update the PETSc single flags
644 80360 : for (const auto & option : petsc_flags)
645 : {
646 2727 : checkUserProvidedPetscOption(option, param_object);
647 :
648 2727 : const std::string & string_option = option.name();
649 :
650 : /**
651 : * "-log_summary" cannot be used in the input file. This option needs to be set when PETSc is
652 : * initialized
653 : * which happens before the parser is even created. We'll throw an error if somebody attempts
654 : * to add this option later.
655 : */
656 2727 : if (option == "-log_summary" || option == "-log_view")
657 0 : mooseError("The PETSc option \"-log_summary\" or \"-log_view\" can only be used on the "
658 : "command line. Please "
659 : "remove it from the input file");
660 :
661 : // Update the stored items, but do not create duplicates
662 2727 : const std::string prefixed_option = prefix + string_option.substr(1);
663 2727 : if (!po.flags.isValueSet(prefixed_option))
664 : {
665 2727 : po.flags.setAdditionalValue(prefixed_option);
666 2727 : po.user_set_options.setAdditionalValue(prefixed_option);
667 : }
668 2727 : }
669 77633 : }
670 :
671 : void
672 62870 : setConvergedReasonFlags(FEProblemBase & fe_problem, std::string prefix)
673 : {
674 62870 : prefix.insert(prefix.begin(), '-');
675 : checkPrefix(prefix);
676 62870 : libmesh_ignore(fe_problem); // avoid unused warnings for old PETSc
677 :
678 : #if !PETSC_VERSION_LESS_THAN(3, 14, 0)
679 : // the boolean in these pairs denote whether the user has specified any of the reason flags in the
680 : // input file
681 125740 : std::array<std::string, 2> reason_flags = {{"snes_converged_reason", "ksp_converged_reason"}};
682 :
683 62870 : auto & po = fe_problem.getPetscOptions();
684 :
685 188610 : for (const auto & reason_flag : reason_flags)
686 376363 : if (!po.flags.isValueSet(prefix + reason_flag) &&
687 124883 : (std::find_if(po.pairs.begin(),
688 : po.pairs.end(),
689 176405 : [&reason_flag, &prefix](auto & pair)
690 551911 : { return pair.first == (prefix + reason_flag); }) == po.pairs.end()))
691 124883 : po.pairs.emplace_back(prefix + reason_flag, "::failed");
692 : #endif
693 62870 : }
694 :
695 : void
696 77875 : addPetscPairsToPetscOptions(
697 : const std::vector<std::pair<MooseEnumItem, std::string>> & petsc_pair_options,
698 : const unsigned int mesh_dimension,
699 : std::string prefix,
700 : const ParallelParamObject & param_object,
701 : PetscOptions & po)
702 : {
703 77875 : prefix.insert(prefix.begin(), '-');
704 : checkPrefix(prefix);
705 :
706 : // Setup the name value pairs
707 77875 : bool boomeramg_found = false;
708 77875 : bool strong_threshold_found = false;
709 : #if !PETSC_VERSION_LESS_THAN(3, 7, 0)
710 77875 : bool superlu_dist_found = false;
711 77875 : bool fact_pattern_found = false;
712 77875 : bool tiny_pivot_found = false;
713 : #endif
714 77875 : std::string pc_description = "";
715 : #if !PETSC_VERSION_LESS_THAN(3, 12, 0)
716 : // If users use HMG, we would like to set
717 77875 : bool hmg_found = false;
718 77875 : bool matptap_found = false;
719 77875 : bool hmg_strong_threshold_found = false;
720 : #endif
721 77875 : std::vector<std::pair<std::string, std::string>> new_options;
722 :
723 134608 : for (const auto & [option_name, option_value] : petsc_pair_options)
724 : {
725 56733 : checkUserProvidedPetscOption(option_name, param_object);
726 :
727 56733 : new_options.clear();
728 : const std::string prefixed_option_name =
729 56733 : prefix + static_cast<const std::string &>(option_name).substr(1);
730 :
731 : // Do not add duplicate settings
732 56733 : if (auto it =
733 56733 : MooseUtils::findPair(po.pairs, po.pairs.begin(), prefixed_option_name, MooseUtils::Any);
734 56733 : it == po.pairs.end())
735 : {
736 : #if !PETSC_VERSION_LESS_THAN(3, 9, 0)
737 56613 : if (option_name == "-pc_factor_mat_solver_package")
738 156 : new_options.emplace_back(prefix + "pc_factor_mat_solver_type", option_value);
739 : #else
740 : if (option_name == "-pc_factor_mat_solver_type")
741 : new_options.push_back(prefix + "pc_factor_mat_solver_package", option_value);
742 : #endif
743 :
744 : // Look for a pc description
745 85193 : if (option_name == "-pc_type" || option_name == "-sub_pc_type" ||
746 28580 : option_name == "-pc_hypre_type")
747 49830 : pc_description += option_value + ' ';
748 :
749 : #if !PETSC_VERSION_LESS_THAN(3, 12, 0)
750 56613 : if (option_name == "-pc_type" && option_value == "hmg")
751 42 : hmg_found = true;
752 :
753 : // MPIAIJ for PETSc 3.12.0: -matptap_via
754 : // MAIJ for PETSc 3.12.0: -matmaijptap_via
755 : // MPIAIJ for PETSc 3.13 to 3.16: -matptap_via, -matproduct_ptap_via
756 : // MAIJ for PETSc 3.13 to 3.16: -matproduct_ptap_via
757 : // MPIAIJ for PETSc 3.17 and higher: -matptap_via, -mat_product_algorithm
758 : // MAIJ for PETSc 3.17 and higher: -mat_product_algorithm
759 : #if !PETSC_VERSION_LESS_THAN(3, 17, 0)
760 56739 : if (hmg_found && (option_name == "-matptap_via" || option_name == "-matmaijptap_via" ||
761 126 : option_name == "-matproduct_ptap_via"))
762 0 : new_options.emplace_back(prefix + "mat_product_algorithm", option_value);
763 : #elif !PETSC_VERSION_LESS_THAN(3, 13, 0)
764 : if (hmg_found && (option_name == "-matptap_via" || option_name == "-matmaijptap_via"))
765 : new_options.emplace_back(prefix + "matproduct_ptap_via", option_value);
766 : #else
767 : if (hmg_found && (option_name == "-matproduct_ptap_via"))
768 : {
769 : new_options.emplace_back(prefix + "matptap_via", option_value);
770 : new_options.emplace_back(prefix + "matmaijptap_via", option_value);
771 : }
772 : #endif
773 :
774 113226 : if (option_name == "-matptap_via" || option_name == "-matmaijptap_via" ||
775 113226 : option_name == "-matproduct_ptap_via" || option_name == "-mat_product_algorithm")
776 0 : matptap_found = true;
777 :
778 : // For 3D problems, we need to set this 0.7
779 56613 : if (option_name == "-hmg_inner_pc_hypre_boomeramg_strong_threshold")
780 0 : hmg_strong_threshold_found = true;
781 : #endif
782 : // This special case is common enough that we'd like to handle it for the user.
783 56613 : if (option_name == "-pc_hypre_type" && option_value == "boomeramg")
784 21797 : boomeramg_found = true;
785 56613 : if (option_name == "-pc_hypre_boomeramg_strong_threshold")
786 0 : strong_threshold_found = true;
787 : #if !PETSC_VERSION_LESS_THAN(3, 7, 0)
788 56613 : if ((option_name == "-pc_factor_mat_solver_package" ||
789 57575 : option_name == "-pc_factor_mat_solver_type") &&
790 962 : option_value == "superlu_dist")
791 311 : superlu_dist_found = true;
792 56613 : if (option_name == "-mat_superlu_dist_fact")
793 0 : fact_pattern_found = true;
794 56613 : if (option_name == "-mat_superlu_dist_replacetinypivot")
795 0 : tiny_pivot_found = true;
796 : #endif
797 :
798 56613 : if (!new_options.empty())
799 : {
800 156 : std::copy(new_options.begin(), new_options.end(), std::back_inserter(po.pairs));
801 312 : for (const auto & option : new_options)
802 156 : po.user_set_options.setAdditionalValue(option.first);
803 : }
804 : else
805 : {
806 56457 : po.pairs.push_back(std::make_pair(prefixed_option_name, option_value));
807 56457 : po.user_set_options.setAdditionalValue(prefixed_option_name);
808 : }
809 : }
810 : else
811 : {
812 : do
813 : {
814 120 : it->second = option_value;
815 120 : it = MooseUtils::findPair(po.pairs, std::next(it), prefixed_option_name, MooseUtils::Any);
816 120 : } while (it != po.pairs.end());
817 : }
818 56733 : }
819 :
820 : // When running a 3D mesh with boomeramg, it is almost always best to supply a strong threshold
821 : // value. We will provide that for the user here if they haven't supplied it themselves.
822 77875 : if (boomeramg_found && !strong_threshold_found && mesh_dimension == 3)
823 : {
824 984 : po.pairs.emplace_back(prefix + "pc_hypre_boomeramg_strong_threshold", "0.7");
825 984 : pc_description += "strong_threshold: 0.7 (auto)";
826 : }
827 :
828 : #if !PETSC_VERSION_LESS_THAN(3, 12, 0)
829 77875 : if (hmg_found && !hmg_strong_threshold_found && mesh_dimension == 3)
830 : {
831 28 : po.pairs.emplace_back(prefix + "hmg_inner_pc_hypre_boomeramg_strong_threshold", "0.7");
832 28 : pc_description += "strong_threshold: 0.7 (auto)";
833 : }
834 :
835 : // Default PETSc PtAP takes too much memory, and it is not quite useful
836 : // Let us switch to use new algorithm
837 77875 : if (hmg_found && !matptap_found)
838 : {
839 : #if !PETSC_VERSION_LESS_THAN(3, 17, 0)
840 42 : po.pairs.emplace_back(prefix + "mat_product_algorithm", "allatonce");
841 : #elif !PETSC_VERSION_LESS_THAN(3, 13, 0)
842 : po.pairs.emplace_back(prefix + "matproduct_ptap_via", "allatonce");
843 : #else
844 : po.pairs.emplace_back(prefix + "matptap_via", "allatonce");
845 : po.pairs.emplace_back(prefix + "matmaijptap_via", "allatonce");
846 : #endif
847 : }
848 : #endif
849 :
850 : #if !PETSC_VERSION_LESS_THAN(3, 7, 0)
851 : // In PETSc-3.7.{0--4}, there is a bug when using superlu_dist, and we have to use
852 : // SamePattern_SameRowPerm, otherwise we use whatever we have in PETSc
853 77875 : if (superlu_dist_found && !fact_pattern_found)
854 : {
855 311 : po.pairs.emplace_back(prefix + "mat_superlu_dist_fact",
856 : #if PETSC_VERSION_LESS_THAN(3, 7, 5)
857 : "SamePattern_SameRowPerm");
858 : pc_description += "mat_superlu_dist_fact: SamePattern_SameRowPerm ";
859 : #else
860 : "SamePattern");
861 311 : pc_description += "mat_superlu_dist_fact: SamePattern ";
862 : #endif
863 : }
864 :
865 : // restore this superlu option
866 77875 : if (superlu_dist_found && !tiny_pivot_found)
867 : {
868 311 : po.pairs.emplace_back(prefix + "mat_superlu_dist_replacetinypivot", "1");
869 311 : pc_description += " mat_superlu_dist_replacetinypivot: true ";
870 : }
871 : #endif
872 : // Set Preconditioner description
873 77875 : if (!pc_description.empty() && prefix.size() > 1)
874 810 : po.pc_description += "[" + prefix.substr(1, prefix.size() - 2) + "]: ";
875 77875 : po.pc_description += pc_description;
876 77875 : }
877 :
878 : std::set<std::string>
879 297171 : getPetscValidLineSearches()
880 : {
881 297171 : return {"default", "shell", "none", "basic", "l2", "bt", "cp"};
882 : }
883 :
884 : InputParameters
885 426320 : getPetscValidParams()
886 : {
887 426320 : InputParameters params = emptyInputParameters();
888 :
889 1705280 : MooseEnum solve_type("PJFNK JFNK NEWTON FD LINEAR");
890 1705280 : params.addParam<MooseEnum>("solve_type",
891 : solve_type,
892 : "PJFNK: Preconditioned Jacobian-Free Newton Krylov "
893 : "JFNK: Jacobian-Free Newton Krylov "
894 : "NEWTON: Full Newton Solve "
895 : "FD: Use finite differences to compute Jacobian "
896 : "LINEAR: Solving a linear problem");
897 :
898 1705280 : MooseEnum mffd_type("wp ds", "wp");
899 1705280 : params.addParam<MooseEnum>("mffd_type",
900 : mffd_type,
901 : "Specifies the finite differencing type for "
902 : "Jacobian-free solve types. Note that the "
903 : "default is wp (for Walker and Pernice).");
904 :
905 1278960 : params.addParam<MultiMooseEnum>(
906 852640 : "petsc_options", getCommonPetscFlags(), "Singleton PETSc options");
907 1278960 : params.addParam<MultiMooseEnum>(
908 852640 : "petsc_options_iname", getCommonPetscKeys(), "Names of PETSc name/value pairs");
909 1705280 : params.addParam<std::vector<std::string>>(
910 : "petsc_options_value",
911 : "Values of PETSc name/value pairs (must correspond with \"petsc_options_iname\"");
912 1278960 : params.addParamNamesToGroup("solve_type petsc_options petsc_options_iname petsc_options_value "
913 : "mffd_type",
914 : "PETSc");
915 :
916 852640 : return params;
917 426320 : }
918 :
919 : MultiMooseEnum
920 442907 : getCommonSNESFlags()
921 : {
922 : return MultiMooseEnum(
923 : "-ksp_monitor_snes_lg -snes_ksp_ew -ksp_snes_ew -snes_converged_reason "
924 : "-snes_ksp -snes_linesearch_monitor -snes_mf -snes_mf_operator -snes_monitor "
925 : "-snes_test_display -snes_view -snes_monitor_cancel",
926 : "",
927 885814 : true);
928 : }
929 :
930 : MultiMooseEnum
931 442243 : getCommonKSPFlags()
932 : {
933 : return MultiMooseEnum(
934 884486 : "-ksp_converged_reason -ksp_gmres_modifiedgramschmidt -ksp_monitor", "", true);
935 : }
936 :
937 : MultiMooseEnum
938 442243 : getCommonPetscFlags()
939 : {
940 442243 : auto options = MultiMooseEnum("-dm_moose_print_embedding -dm_view", "", true);
941 442243 : options.addValidName(getCommonKSPFlags());
942 442243 : options.addValidName(getCommonSNESFlags());
943 442243 : return options;
944 0 : }
945 :
946 : MultiMooseEnum
947 442907 : getCommonSNESKeys()
948 : {
949 : return MultiMooseEnum("-snes_atol -snes_linesearch_type -snes_ls -snes_max_it -snes_rtol "
950 : "-snes_divergence_tolerance -snes_type",
951 : "",
952 885814 : true);
953 : }
954 :
955 : MultiMooseEnum
956 442243 : getCommonKSPKeys()
957 : {
958 : return MultiMooseEnum("-ksp_atol -ksp_gmres_restart -ksp_max_it -ksp_pc_side -ksp_rtol "
959 : "-ksp_type -sub_ksp_type",
960 : "",
961 884486 : true);
962 : }
963 : MultiMooseEnum
964 442243 : getCommonPetscKeys()
965 : {
966 : auto options = MultiMooseEnum("-mat_fd_coloring_err -mat_fd_type -mat_mffd_type "
967 : "-pc_asm_overlap -pc_factor_levels "
968 : "-pc_factor_mat_ordering_type -pc_hypre_boomeramg_grid_sweeps_all "
969 : "-pc_hypre_boomeramg_max_iter "
970 : "-pc_hypre_boomeramg_strong_threshold -pc_hypre_type -pc_type "
971 : "-sub_pc_type",
972 : "",
973 442243 : true);
974 442243 : options.addValidName(getCommonKSPKeys());
975 442243 : options.addValidName(getCommonSNESKeys());
976 442243 : return options;
977 0 : }
978 :
979 : bool
980 604 : isSNESVI(FEProblemBase & fe_problem)
981 : {
982 604 : const PetscOptions & petsc = fe_problem.getPetscOptions();
983 :
984 : int argc;
985 : char ** args;
986 604 : LibmeshPetscCallA(fe_problem.comm().get(), PetscGetArgs(&argc, &args));
987 :
988 604 : std::vector<std::string> cml_arg;
989 7504 : for (int i = 0; i < argc; i++)
990 13800 : cml_arg.push_back(args[i]);
991 :
992 604 : if (MooseUtils::findPair(petsc.pairs, petsc.pairs.begin(), MooseUtils::Any, "vinewtonssls") ==
993 1208 : petsc.pairs.end() &&
994 604 : MooseUtils::findPair(petsc.pairs, petsc.pairs.begin(), MooseUtils::Any, "vinewtonrsls") ==
995 648 : petsc.pairs.end() &&
996 1252 : std::find(cml_arg.begin(), cml_arg.end(), "vinewtonssls") == cml_arg.end() &&
997 648 : std::find(cml_arg.begin(), cml_arg.end(), "vinewtonrsls") == cml_arg.end())
998 44 : return false;
999 :
1000 560 : return true;
1001 604 : }
1002 :
1003 : void
1004 235360 : setSinglePetscOption(const std::string & name,
1005 : const std::string & value /*=""*/,
1006 : FEProblemBase * const problem /*=nullptr*/)
1007 : {
1008 235360 : static const TIMPI::Communicator comm_world(PETSC_COMM_WORLD);
1009 235360 : const TIMPI::Communicator & comm = problem ? problem->comm() : comm_world;
1010 235360 : LibmeshPetscCallA(comm.get(),
1011 : PetscOptionsSetValue(LIBMESH_PETSC_NULLPTR,
1012 : name.c_str(),
1013 : value == "" ? LIBMESH_PETSC_NULLPTR : value.c_str()));
1014 235360 : const auto lower_case_name = MooseUtils::toLower(name);
1015 20 : auto check_problem = [problem, &lower_case_name]()
1016 : {
1017 20 : if (!problem)
1018 0 : mooseError(
1019 : "Setting the option '",
1020 : lower_case_name,
1021 : "' requires passing a 'problem' parameter. Contact a developer of your application "
1022 : "to have them update their code. If in doubt, reach out to the MOOSE team on Github "
1023 : "discussions");
1024 235380 : };
1025 :
1026 : // Select vector type from user-passed PETSc options
1027 235360 : if (lower_case_name.find("-vec_type") != std::string::npos)
1028 : {
1029 10 : check_problem();
1030 20 : for (auto & solver_system : problem->_solver_systems)
1031 : {
1032 10 : auto & lm_sys = solver_system->system();
1033 30 : for (auto & [vec_name, vec] : as_range(lm_sys.vectors_begin(), lm_sys.vectors_end()))
1034 : {
1035 20 : libmesh_ignore(vec_name);
1036 20 : auto * const petsc_vec = cast_ptr<PetscVector<Number> *>(vec.get());
1037 20 : LibmeshPetscCallA(comm.get(), VecSetFromOptions(petsc_vec->vec()));
1038 : }
1039 : // The solution vectors aren't included in the system vectors storage
1040 10 : auto * petsc_vec = cast_ptr<PetscVector<Number> *>(lm_sys.solution.get());
1041 10 : LibmeshPetscCallA(comm.get(), VecSetFromOptions(petsc_vec->vec()));
1042 10 : petsc_vec = cast_ptr<PetscVector<Number> *>(lm_sys.current_local_solution.get());
1043 10 : LibmeshPetscCallA(comm.get(), VecSetFromOptions(petsc_vec->vec()));
1044 : }
1045 : }
1046 : // Select matrix type from user-passed PETSc options
1047 235350 : else if (lower_case_name.find("mat_type") != std::string::npos)
1048 : {
1049 10 : check_problem();
1050 :
1051 10 : bool found_matching_prefix = false;
1052 10 : for (const auto i : index_range(problem->_solver_systems))
1053 : {
1054 10 : const auto & solver_sys_name = problem->_solver_sys_names[i];
1055 10 : if (lower_case_name.find("-" + MooseUtils::toLower(solver_sys_name) + "_mat_type") ==
1056 : std::string::npos)
1057 0 : continue;
1058 :
1059 10 : if (problem->solverParams(i)._type == Moose::ST_JFNK)
1060 0 : mooseError(
1061 : "Setting option '", lower_case_name, "' is incompatible with a JFNK 'solve_type'");
1062 :
1063 10 : auto & lm_sys = problem->_solver_systems[i]->system();
1064 20 : for (auto & [mat_name, mat] : as_range(lm_sys.matrices_begin(), lm_sys.matrices_end()))
1065 : {
1066 10 : libmesh_ignore(mat_name);
1067 10 : if (auto * const petsc_mat = dynamic_cast<PetscMatrixBase<Number> *>(mat.get()); petsc_mat)
1068 : {
1069 : #ifdef DEBUG
1070 : const char * mat_prefix;
1071 : LibmeshPetscCallA(comm.get(), MatGetOptionsPrefix(petsc_mat->mat(), &mat_prefix));
1072 : mooseAssert(strcmp(mat_prefix, (solver_sys_name + "_").c_str()) == 0,
1073 : "We should have prefixed these matrices previously");
1074 : #endif
1075 10 : LibmeshPetscCallA(comm.get(), MatSetFromOptions(petsc_mat->mat()));
1076 : }
1077 : }
1078 10 : found_matching_prefix = true;
1079 10 : break;
1080 : }
1081 :
1082 10 : if (!found_matching_prefix)
1083 0 : mooseError("We did not find a matching solver system name for the petsc option '",
1084 : lower_case_name,
1085 : "'");
1086 : }
1087 235360 : }
1088 :
1089 : void
1090 72306 : setSinglePetscOptionIfAppropriate(const MultiMooseEnum & dont_add_these_options,
1091 : const std::string & name,
1092 : const std::string & value /*=""*/,
1093 : FEProblemBase * const problem /*=nullptr*/)
1094 : {
1095 72306 : if (!dont_add_these_options.contains(name))
1096 70869 : setSinglePetscOption(name, value, problem);
1097 72306 : }
1098 :
1099 : void
1100 0 : colorAdjacencyMatrix(PetscScalar * adjacency_matrix,
1101 : unsigned int size,
1102 : unsigned int colors,
1103 : std::vector<unsigned int> & vertex_colors,
1104 : const char * coloring_algorithm)
1105 : {
1106 : // Mat A will be a dense matrix from the incoming data structure
1107 : Mat A;
1108 0 : LibmeshPetscCallA(PETSC_COMM_SELF, MatCreate(PETSC_COMM_SELF, &A));
1109 0 : LibmeshPetscCallA(PETSC_COMM_SELF, MatSetSizes(A, size, size, size, size));
1110 0 : LibmeshPetscCallA(PETSC_COMM_SELF, MatSetType(A, MATSEQDENSE));
1111 : // PETSc requires a non-const data array to populate the matrix
1112 0 : LibmeshPetscCallA(PETSC_COMM_SELF, MatSeqDenseSetPreallocation(A, adjacency_matrix));
1113 0 : LibmeshPetscCallA(PETSC_COMM_SELF, MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
1114 0 : LibmeshPetscCallA(PETSC_COMM_SELF, MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
1115 :
1116 : // Convert A to a sparse matrix
1117 : #if PETSC_VERSION_LESS_THAN(3, 7, 0)
1118 : LibmeshPetscCallA(PETSC_COMM_SELF, MatConvert(A, MATAIJ, MAT_REUSE_MATRIX, &A));
1119 : #else
1120 0 : LibmeshPetscCallA(PETSC_COMM_SELF, MatConvert(A, MATAIJ, MAT_INPLACE_MATRIX, &A));
1121 : #endif
1122 :
1123 : ISColoring iscoloring;
1124 : MatColoring mc;
1125 0 : LibmeshPetscCallA(PETSC_COMM_SELF, MatColoringCreate(A, &mc));
1126 0 : LibmeshPetscCallA(PETSC_COMM_SELF, MatColoringSetType(mc, coloring_algorithm));
1127 0 : LibmeshPetscCallA(PETSC_COMM_SELF, MatColoringSetMaxColors(mc, static_cast<PetscInt>(colors)));
1128 :
1129 : // Petsc normally colors by distance two (neighbors of neighbors), we just want one
1130 0 : LibmeshPetscCallA(PETSC_COMM_SELF, MatColoringSetDistance(mc, 1));
1131 0 : LibmeshPetscCallA(PETSC_COMM_SELF, MatColoringSetFromOptions(mc));
1132 0 : LibmeshPetscCallA(PETSC_COMM_SELF, MatColoringApply(mc, &iscoloring));
1133 :
1134 : PetscInt nn;
1135 : IS * is;
1136 : #if PETSC_RELEASE_LESS_THAN(3, 12, 0)
1137 : LibmeshPetscCallA(PETSC_COMM_SELF, ISColoringGetIS(iscoloring, &nn, &is));
1138 : #else
1139 0 : LibmeshPetscCallA(PETSC_COMM_SELF, ISColoringGetIS(iscoloring, PETSC_USE_POINTER, &nn, &is));
1140 : #endif
1141 :
1142 0 : if (nn > static_cast<PetscInt>(colors))
1143 0 : throw std::runtime_error("Not able to color with designated number of colors");
1144 :
1145 0 : for (int i = 0; i < nn; i++)
1146 : {
1147 : PetscInt isize;
1148 : const PetscInt * indices;
1149 0 : LibmeshPetscCallA(PETSC_COMM_SELF, ISGetLocalSize(is[i], &isize));
1150 0 : LibmeshPetscCallA(PETSC_COMM_SELF, ISGetIndices(is[i], &indices));
1151 0 : for (int j = 0; j < isize; j++)
1152 : {
1153 : mooseAssert(indices[j] < static_cast<PetscInt>(vertex_colors.size()), "Index out of bounds");
1154 0 : vertex_colors[indices[j]] = i;
1155 : }
1156 0 : LibmeshPetscCallA(PETSC_COMM_SELF, ISRestoreIndices(is[i], &indices));
1157 : }
1158 :
1159 0 : LibmeshPetscCallA(PETSC_COMM_SELF, MatDestroy(&A));
1160 0 : LibmeshPetscCallA(PETSC_COMM_SELF, MatColoringDestroy(&mc));
1161 0 : LibmeshPetscCallA(PETSC_COMM_SELF, ISColoringDestroy(&iscoloring));
1162 0 : }
1163 :
1164 : void
1165 3748 : dontAddPetscFlag(const std::string & flag, PetscOptions & petsc_options)
1166 : {
1167 3748 : if (!petsc_options.dont_add_these_options.contains(flag))
1168 3748 : petsc_options.dont_add_these_options.setAdditionalValue(flag);
1169 3748 : }
1170 :
1171 : void
1172 656 : dontAddNonlinearConvergedReason(FEProblemBase & fe_problem)
1173 : {
1174 1312 : dontAddPetscFlag("-snes_converged_reason", fe_problem.getPetscOptions());
1175 656 : }
1176 :
1177 : void
1178 666 : dontAddLinearConvergedReason(FEProblemBase & fe_problem)
1179 : {
1180 1332 : dontAddPetscFlag("-ksp_converged_reason", fe_problem.getPetscOptions());
1181 666 : }
1182 :
1183 : void
1184 0 : dontAddCommonKSPOptions(FEProblemBase & fe_problem)
1185 : {
1186 0 : auto & petsc_options = fe_problem.getPetscOptions();
1187 0 : for (const auto & flag : getCommonKSPFlags().getNames())
1188 0 : dontAddPetscFlag(flag, petsc_options);
1189 0 : for (const auto & key : getCommonKSPKeys().getNames())
1190 0 : dontAddPetscFlag(key, petsc_options);
1191 0 : }
1192 :
1193 : void
1194 664 : dontAddCommonSNESOptions(FEProblemBase & fe_problem)
1195 : {
1196 664 : auto & petsc_options = fe_problem.getPetscOptions();
1197 8632 : for (const auto & flag : getCommonSNESFlags().getNames())
1198 7968 : if (!petsc_options.dont_add_these_options.contains(flag))
1199 4648 : petsc_options.dont_add_these_options.setAdditionalValue(flag);
1200 5312 : for (const auto & key : getCommonSNESKeys().getNames())
1201 4648 : if (!petsc_options.dont_add_these_options.contains(key))
1202 2988 : petsc_options.dont_add_these_options.setAdditionalValue(key);
1203 664 : }
1204 :
1205 : std::unique_ptr<PetscMatrix<Number>>
1206 48 : createMatrixFromFile(const libMesh::Parallel::Communicator & comm,
1207 : Mat & mat,
1208 : const std::string & binary_mat_file,
1209 : const unsigned int mat_number_to_load)
1210 : {
1211 48 : LibmeshPetscCallA(comm.get(), MatCreate(comm.get(), &mat));
1212 : PetscViewer matviewer;
1213 48 : LibmeshPetscCallA(
1214 : comm.get(),
1215 : PetscViewerBinaryOpen(comm.get(), binary_mat_file.c_str(), FILE_MODE_READ, &matviewer));
1216 96 : for (unsigned int i = 0; i < mat_number_to_load; ++i)
1217 48 : LibmeshPetscCallA(comm.get(), MatLoad(mat, matviewer));
1218 48 : LibmeshPetscCallA(comm.get(), PetscViewerDestroy(&matviewer));
1219 :
1220 96 : return std::make_unique<PetscMatrix<Number>>(mat, comm);
1221 : }
1222 :
1223 : } // Namespace PetscSupport
1224 : } // Namespace MOOSE
|