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 "NonlinearEigenSystem.h"
11 :
12 : // MOOSE includes
13 : #include "DirichletBC.h"
14 : #include "EigenDirichletBC.h"
15 : #include "ArrayDirichletBC.h"
16 : #include "EigenArrayDirichletBC.h"
17 : #include "EigenProblem.h"
18 : #include "IntegratedBC.h"
19 : #include "KernelBase.h"
20 : #include "NodalBC.h"
21 : #include "TimeIntegrator.h"
22 : #include "SlepcSupport.h"
23 : #include "DGKernelBase.h"
24 : #include "ScalarKernelBase.h"
25 : #include "MooseVariableScalar.h"
26 : #include "ResidualObject.h"
27 :
28 : #include "libmesh/libmesh_config.h"
29 : #include "libmesh/petsc_matrix.h"
30 : #include "libmesh/sparse_matrix.h"
31 : #include "libmesh/diagonal_matrix.h"
32 : #include "libmesh/petsc_shell_matrix.h"
33 : #include "libmesh/petsc_solver_exception.h"
34 : #include "libmesh/slepc_eigen_solver.h"
35 :
36 : using namespace libMesh;
37 :
38 : #ifdef LIBMESH_HAVE_SLEPC
39 :
40 : namespace Moose
41 : {
42 :
43 : void
44 55 : assemble_matrix(EquationSystems & es, const std::string & system_name)
45 : {
46 55 : EigenProblem * p = es.parameters.get<EigenProblem *>("_eigen_problem");
47 55 : CondensedEigenSystem & eigen_system = es.get_system<CondensedEigenSystem>(system_name);
48 : NonlinearEigenSystem & eigen_nl =
49 55 : p->getNonlinearEigenSystem(/*nl_sys_num=*/eigen_system.number());
50 :
51 : // If this is a nonlinear eigenvalue problem,
52 : // we do not need to assemble anything
53 55 : if (p->isNonlinearEigenvalueSolver(eigen_nl.number()))
54 : {
55 : // If you want an efficient eigensolver,
56 : // please use PETSc 3.13 or newer.
57 : // We need to do an unnecessary assembly,
58 : // if you use PETSc that is older than 3.13.
59 : #if PETSC_RELEASE_LESS_THAN(3, 13, 0)
60 : if (eigen_system.has_matrix_B())
61 : p->computeJacobianTag(*eigen_system.current_local_solution,
62 : eigen_system.get_matrix_B(),
63 : eigen_nl.eigenMatrixTag());
64 : #endif
65 0 : return;
66 : }
67 :
68 : #if !PETSC_RELEASE_LESS_THAN(3, 13, 0)
69 : // If we use shell matrices and do not use a shell preconditioning matrix,
70 : // we only need to form a preconditioning matrix
71 55 : if (eigen_system.use_shell_matrices() && !eigen_system.use_shell_precond_matrix())
72 : {
73 0 : p->computeJacobianTag(*eigen_system.current_local_solution,
74 : eigen_system.get_precond_matrix(),
75 : eigen_nl.precondMatrixTag());
76 0 : return;
77 : }
78 : #endif
79 : // If it is a linear generalized eigenvalue problem,
80 : // we assemble A and B together
81 55 : if (eigen_system.generalized())
82 : {
83 22 : p->computeJacobianAB(*eigen_system.current_local_solution,
84 : eigen_system.get_matrix_A(),
85 : eigen_system.get_matrix_B(),
86 : eigen_nl.nonEigenMatrixTag(),
87 : eigen_nl.eigenMatrixTag());
88 : #if LIBMESH_HAVE_SLEPC
89 22 : if (p->negativeSignEigenKernel())
90 22 : LibmeshPetscCallA(
91 : p->comm().get(),
92 : MatScale(static_cast<PetscMatrix<Number> &>(eigen_system.get_matrix_B()).mat(), -1.0));
93 : #endif
94 22 : return;
95 : }
96 :
97 : // If it is a linear eigenvalue problem, we assemble matrix A
98 : {
99 33 : p->computeJacobianTag(*eigen_system.current_local_solution,
100 : eigen_system.get_matrix_A(),
101 : eigen_nl.nonEigenMatrixTag());
102 :
103 33 : return;
104 : }
105 : }
106 : }
107 :
108 562 : NonlinearEigenSystem::NonlinearEigenSystem(EigenProblem & eigen_problem, const std::string & name)
109 : : NonlinearSystemBase(
110 562 : eigen_problem, eigen_problem.es().add_system<CondensedEigenSystem>(name), name),
111 562 : _eigen_sys(eigen_problem.es().get_system<CondensedEigenSystem>(name)),
112 562 : _eigen_problem(eigen_problem),
113 562 : _solver_configuration(nullptr),
114 562 : _n_eigen_pairs_required(eigen_problem.getNEigenPairsRequired()),
115 562 : _work_rhs_vector_AX(addVector("work_rhs_vector_Ax", false, PARALLEL)),
116 562 : _work_rhs_vector_BX(addVector("work_rhs_vector_Bx", false, PARALLEL)),
117 562 : _precond_matrix_includes_eigen(false),
118 562 : _preconditioner(nullptr),
119 1686 : _num_constrained_dofs(0)
120 : {
121 : SlepcEigenSolver<Number> * solver =
122 562 : cast_ptr<SlepcEigenSolver<Number> *>(_eigen_sys.eigen_solver.get());
123 :
124 562 : if (!solver)
125 0 : mooseError("A slepc eigen solver is required");
126 :
127 : // setup of our class @SlepcSolverConfiguration
128 : _solver_configuration =
129 562 : std::make_unique<SlepcEigenSolverConfiguration>(eigen_problem, *solver, *this);
130 :
131 562 : solver->set_solver_configuration(*_solver_configuration);
132 :
133 562 : _Ax_tag = eigen_problem.addVectorTag("Ax_tag");
134 :
135 562 : _Bx_tag = eigen_problem.addVectorTag("Eigen");
136 :
137 562 : _A_tag = eigen_problem.addMatrixTag("A_tag");
138 :
139 562 : _B_tag = eigen_problem.addMatrixTag("Eigen");
140 :
141 : // By default, _precond_tag and _A_tag will share the same
142 : // objects. If we want to include eigen contributions to
143 : // the preconditioning matrix, and then _precond_tag will
144 : // point to part of "B" objects
145 562 : _precond_tag = eigen_problem.addMatrixTag("Eigen_precond");
146 :
147 : // We do not rely on creating submatrices in the solve routine
148 562 : _eigen_sys.dont_create_submatrices_in_solve();
149 562 : }
150 :
151 : void
152 3201 : NonlinearEigenSystem::postAddResidualObject(ResidualObject & object)
153 : {
154 : // If it is an eigen dirichlet boundary condition, we should skip it because their
155 : // contributions should be zero. If we do not skip it, preconditioning matrix will
156 : // be singular because boundary elements are zero.
157 3329 : if (_precond_matrix_includes_eigen && !dynamic_cast<EigenDirichletBC *>(&object) &&
158 128 : !dynamic_cast<EigenArrayDirichletBC *>(&object))
159 128 : object.useMatrixTag(_precond_tag, {});
160 :
161 3201 : auto & vtags = object.getVectorTags({});
162 3201 : auto & mtags = object.getMatrixTags({});
163 :
164 3201 : const bool eigen = (vtags.find(_Bx_tag) != vtags.end()) || (mtags.find(_B_tag) != mtags.end());
165 :
166 3201 : if (eigen && !_eigen_sys.generalized())
167 4 : object.mooseError("This object has been marked as contributing to B or Bx but the eigen "
168 : "problem type is not a generalized one");
169 :
170 : // If it is an eigen kernel, mark its variable as eigen
171 3197 : if (eigen)
172 : {
173 : // Note: the object may be on the displaced system
174 1346 : auto sys = object.parameters().get<SystemBase *>("_sys");
175 1346 : auto vname = object.variable().name();
176 1346 : if (hasScalarVariable(vname))
177 0 : sys->getScalarVariable(0, vname).eigen(true);
178 : else
179 1346 : sys->getVariable(0, vname).eigen(true);
180 :
181 : // Associate the eigen matrix tag and the vector tag
182 : // if this is a eigen kernel
183 1346 : object.useMatrixTag(_B_tag, {});
184 1346 : object.useVectorTag(_Bx_tag, {});
185 1346 : }
186 : else
187 : {
188 : // Noneigen Vector tag
189 1851 : object.useVectorTag(_Ax_tag, {});
190 : // Noneigen Matrix tag
191 1851 : object.useMatrixTag(_A_tag, {});
192 : // Noneigen Kernels
193 1851 : object.useMatrixTag(_precond_tag, {});
194 : }
195 3197 : }
196 :
197 : void
198 554 : NonlinearEigenSystem::initializeCondensedMatrices()
199 : {
200 554 : if (!(_num_constrained_dofs = dofMap().n_constrained_dofs()))
201 530 : return;
202 :
203 24 : _eigen_sys.initialize_condensed_dofs();
204 24 : const auto m = cast_int<numeric_index_type>(_eigen_sys.local_non_condensed_dofs_vector.size());
205 24 : auto M = m;
206 24 : _communicator.sum(M);
207 24 : if (_eigen_sys.has_condensed_matrix_A())
208 : {
209 12 : _eigen_sys.get_condensed_matrix_A().init(M, M, m, m);
210 : // A bit ludicrously MatCopy requires the matrix being copied to to be assembled
211 12 : _eigen_sys.get_condensed_matrix_A().close();
212 : }
213 24 : if (_eigen_sys.has_condensed_matrix_B())
214 : {
215 12 : _eigen_sys.get_condensed_matrix_B().init(M, M, m, m);
216 12 : _eigen_sys.get_condensed_matrix_B().close();
217 : }
218 24 : if (_eigen_sys.has_condensed_precond_matrix())
219 : {
220 12 : _eigen_sys.get_condensed_precond_matrix().init(M, M, m, m);
221 12 : _eigen_sys.get_condensed_precond_matrix().close();
222 : }
223 : }
224 :
225 : void
226 554 : NonlinearEigenSystem::postInit()
227 : {
228 554 : NonlinearSystemBase::postInit();
229 554 : initializeCondensedMatrices();
230 554 : }
231 :
232 : void
233 0 : NonlinearEigenSystem::reinit()
234 : {
235 0 : NonlinearSystemBase::reinit();
236 0 : initializeCondensedMatrices();
237 0 : }
238 :
239 : void
240 1233 : NonlinearEigenSystem::solve()
241 : {
242 1233 : const bool presolve_succeeded = preSolve();
243 1233 : if (!presolve_succeeded)
244 0 : return;
245 :
246 1233 : std::unique_ptr<NumericVector<Number>> subvec;
247 :
248 : // We apply initial guess for only nonlinear solver
249 1233 : if (_eigen_problem.isNonlinearEigenvalueSolver(number()))
250 : {
251 1178 : if (_num_constrained_dofs)
252 : {
253 44 : subvec = solution().get_subvector(_eigen_sys.local_non_condensed_dofs_vector);
254 44 : _eigen_sys.set_initial_space(*subvec);
255 : }
256 : else
257 1134 : _eigen_sys.set_initial_space(solution());
258 : }
259 :
260 1233 : const bool time_integrator_solve = std::any_of(_time_integrators.begin(),
261 : _time_integrators.end(),
262 0 : [](auto & ti) { return ti->overridesSolve(); });
263 : if (time_integrator_solve)
264 : mooseAssert(_time_integrators.size() == 1,
265 : "If solve is overridden, then there must be only one time integrator");
266 :
267 1233 : if (time_integrator_solve)
268 0 : _time_integrators.front()->solve();
269 : else
270 1233 : system().solve();
271 :
272 1233 : for (auto & ti : _time_integrators)
273 : {
274 0 : if (!ti->overridesSolve())
275 0 : ti->setNumIterationsLastSolve();
276 0 : ti->postSolve();
277 : }
278 :
279 : // store eigenvalues
280 1233 : unsigned int n_converged_eigenvalues = getNumConvergedEigenvalues();
281 :
282 1233 : _n_eigen_pairs_required = _eigen_problem.getNEigenPairsRequired();
283 :
284 1233 : if (_n_eigen_pairs_required < n_converged_eigenvalues)
285 11 : n_converged_eigenvalues = _n_eigen_pairs_required;
286 :
287 1233 : _eigen_values.resize(n_converged_eigenvalues);
288 2511 : for (unsigned int n = 0; n < n_converged_eigenvalues; n++)
289 1278 : _eigen_values[n] = getConvergedEigenvalue(n);
290 :
291 : // Update the solution vector to the active eigenvector
292 1233 : if (n_converged_eigenvalues)
293 1223 : getConvergedEigenpair(_eigen_problem.activeEigenvalueIndex());
294 :
295 1233 : if (_eigen_problem.isNonlinearEigenvalueSolver(number()) && _num_constrained_dofs)
296 44 : solution().restore_subvector(std::move(subvec), _eigen_sys.local_non_condensed_dofs_vector);
297 1233 : }
298 :
299 : void
300 704 : NonlinearEigenSystem::attachSLEPcCallbacks()
301 : {
302 : // Tell libmesh not to close matrices before solve
303 704 : _eigen_sys.get_eigen_solver().set_close_matrix_before_solve(false);
304 :
305 704 : if (_num_constrained_dofs)
306 : {
307 : // Condensed Matrix A
308 22 : if (_eigen_sys.has_condensed_matrix_A())
309 : {
310 11 : Mat mat = static_cast<PetscMatrix<Number> &>(_eigen_sys.get_condensed_matrix_A()).mat();
311 :
312 11 : Moose::SlepcSupport::attachCallbacksToMat(_eigen_problem, mat, false);
313 : }
314 :
315 : // Condensed Matrix B
316 22 : if (_eigen_sys.has_condensed_matrix_B())
317 : {
318 11 : Mat mat = static_cast<PetscMatrix<Number> &>(_eigen_sys.get_condensed_matrix_B()).mat();
319 :
320 11 : Moose::SlepcSupport::attachCallbacksToMat(_eigen_problem, mat, true);
321 : }
322 :
323 : // Condensed Preconditioning matrix
324 22 : if (_eigen_sys.has_condensed_precond_matrix())
325 : {
326 11 : Mat mat = static_cast<PetscMatrix<Number> &>(_eigen_sys.get_condensed_precond_matrix()).mat();
327 :
328 11 : Moose::SlepcSupport::attachCallbacksToMat(_eigen_problem, mat, true);
329 : }
330 : }
331 : else
332 : {
333 : // Matrix A
334 682 : if (_eigen_sys.has_matrix_A())
335 : {
336 141 : Mat mat = static_cast<PetscMatrix<Number> &>(_eigen_sys.get_matrix_A()).mat();
337 :
338 141 : Moose::SlepcSupport::attachCallbacksToMat(_eigen_problem, mat, false);
339 : }
340 :
341 : // Matrix B
342 682 : if (_eigen_sys.has_matrix_B())
343 : {
344 108 : Mat mat = static_cast<PetscMatrix<Number> &>(_eigen_sys.get_matrix_B()).mat();
345 :
346 108 : Moose::SlepcSupport::attachCallbacksToMat(_eigen_problem, mat, true);
347 : }
348 :
349 : // Preconditioning matrix
350 682 : if (_eigen_sys.has_precond_matrix())
351 : {
352 501 : Mat mat = static_cast<PetscMatrix<Number> &>(_eigen_sys.get_precond_matrix()).mat();
353 :
354 501 : Moose::SlepcSupport::attachCallbacksToMat(_eigen_problem, mat, true);
355 : }
356 : }
357 :
358 : // Shell matrix A
359 704 : if (_eigen_sys.has_shell_matrix_A())
360 : {
361 552 : Mat mat = static_cast<PetscShellMatrix<Number> &>(_eigen_sys.get_shell_matrix_A()).mat();
362 :
363 : // Attach callbacks for nonlinear eigenvalue solver
364 552 : Moose::SlepcSupport::attachCallbacksToMat(_eigen_problem, mat, false);
365 :
366 : // Set MatMult operations for shell
367 552 : Moose::SlepcSupport::setOperationsForShellMat(_eigen_problem, mat, false);
368 : }
369 :
370 : // Shell matrix B
371 704 : if (_eigen_sys.has_shell_matrix_B())
372 : {
373 552 : Mat mat = static_cast<PetscShellMatrix<Number> &>(_eigen_sys.get_shell_matrix_B()).mat();
374 :
375 552 : Moose::SlepcSupport::attachCallbacksToMat(_eigen_problem, mat, true);
376 :
377 : // Set MatMult operations for shell
378 552 : Moose::SlepcSupport::setOperationsForShellMat(_eigen_problem, mat, true);
379 : }
380 :
381 : // Shell preconditioning matrix
382 704 : if (_eigen_sys.has_shell_precond_matrix())
383 : {
384 40 : Mat mat = static_cast<PetscShellMatrix<Number> &>(_eigen_sys.get_shell_precond_matrix()).mat();
385 :
386 40 : Moose::SlepcSupport::attachCallbacksToMat(_eigen_problem, mat, true);
387 : }
388 704 : }
389 :
390 : void
391 0 : NonlinearEigenSystem::stopSolve(const ExecFlagType &, const std::set<TagID> &)
392 : {
393 0 : mooseError("did not implement yet \n");
394 : }
395 :
396 : void
397 0 : NonlinearEigenSystem::setupFiniteDifferencedPreconditioner()
398 : {
399 0 : mooseError("did not implement yet \n");
400 : }
401 :
402 : bool
403 704 : NonlinearEigenSystem::converged()
404 : {
405 704 : return _eigen_sys.get_n_converged();
406 : }
407 :
408 : unsigned int
409 0 : NonlinearEigenSystem::getCurrentNonlinearIterationNumber()
410 : {
411 0 : mooseError("did not implement yet \n");
412 : return 0;
413 : }
414 :
415 : NumericVector<Number> &
416 30 : NonlinearEigenSystem::RHS()
417 : {
418 30 : return _work_rhs_vector_BX;
419 : }
420 :
421 : NumericVector<Number> &
422 396 : NonlinearEigenSystem::residualVectorAX()
423 : {
424 396 : return _work_rhs_vector_AX;
425 : }
426 :
427 : NumericVector<Number> &
428 1773 : NonlinearEigenSystem::residualVectorBX()
429 : {
430 1773 : return _work_rhs_vector_BX;
431 : }
432 :
433 : NonlinearSolver<Number> *
434 0 : NonlinearEigenSystem::nonlinearSolver()
435 : {
436 0 : mooseError("did not implement yet \n");
437 : return NULL;
438 : }
439 :
440 : SNES
441 5911 : NonlinearEigenSystem::getSNES()
442 : {
443 5911 : EPS eps = getEPS();
444 :
445 5911 : if (_eigen_problem.isNonlinearEigenvalueSolver(number()))
446 : {
447 5911 : SNES snes = nullptr;
448 5911 : LibmeshPetscCall(Moose::SlepcSupport::mooseSlepcEPSGetSNES(eps, &snes));
449 5911 : return snes;
450 : }
451 : else
452 0 : mooseError("There is no SNES in linear eigen solver");
453 : }
454 :
455 : EPS
456 11736 : NonlinearEigenSystem::getEPS()
457 : {
458 : SlepcEigenSolver<Number> * solver =
459 11736 : cast_ptr<SlepcEigenSolver<Number> *>(&(*_eigen_sys.eigen_solver));
460 :
461 11736 : if (!solver)
462 0 : mooseError("Unable to retrieve eigen solver");
463 :
464 11736 : return solver->eps();
465 : }
466 :
467 : void
468 554 : NonlinearEigenSystem::checkIntegrity()
469 : {
470 554 : if (_nodal_bcs.hasActiveObjects())
471 : {
472 500 : const auto & nodal_bcs = _nodal_bcs.getActiveObjects();
473 1844 : for (const auto & nodal_bc : nodal_bcs)
474 : {
475 : // If this is a dirichlet boundary condition
476 1352 : auto nbc = std::dynamic_pointer_cast<DirichletBC>(nodal_bc);
477 : // If this is a eigen Dirichlet boundary condition
478 1352 : auto eigen_nbc = std::dynamic_pointer_cast<EigenDirichletBC>(nodal_bc);
479 : // ArrayDirichletBC
480 1352 : auto anbc = std::dynamic_pointer_cast<ArrayDirichletBC>(nodal_bc);
481 : // EigenArrayDirichletBC
482 1352 : auto aeigen_nbc = std::dynamic_pointer_cast<EigenArrayDirichletBC>(nodal_bc);
483 : // If it is a Dirichlet boundary condition, then value has to be zero
484 1352 : if (nbc && nbc->variable().eigen() && nbc->getParam<Real>("value"))
485 4 : mooseError(
486 : "Can't set an inhomogeneous Dirichlet boundary condition for eigenvalue problems.");
487 : // If it is an array Dirichlet boundary condition, all values should be zero
488 1348 : else if (anbc)
489 : {
490 112 : auto & values = anbc->getParam<RealEigenVector>("values");
491 336 : for (MooseIndex(values) i = 0; i < values.size(); i++)
492 : {
493 224 : if (values(i))
494 0 : mooseError("Can't set an inhomogeneous array Dirichlet boundary condition for "
495 : "eigenvalue problems.");
496 : }
497 : }
498 1236 : else if (!nbc && !eigen_nbc && !anbc && !aeigen_nbc)
499 4 : mooseError(
500 : "Invalid NodalBC for eigenvalue problems, please use homogeneous (array) Dirichlet.");
501 1344 : }
502 : }
503 546 : }
504 :
505 : std::pair<Real, Real>
506 1586 : NonlinearEigenSystem::getConvergedEigenvalue(dof_id_type n) const
507 : {
508 1586 : unsigned int n_converged_eigenvalues = getNumConvergedEigenvalues();
509 1586 : if (n >= n_converged_eigenvalues)
510 0 : mooseError(n, " not in [0, ", n_converged_eigenvalues, ")");
511 3172 : return _eigen_sys.get_eigenvalue(n);
512 : }
513 :
514 : std::pair<Real, Real>
515 1223 : NonlinearEigenSystem::getConvergedEigenpair(dof_id_type n) const
516 : {
517 1223 : unsigned int n_converged_eigenvalues = getNumConvergedEigenvalues();
518 :
519 1223 : if (n >= n_converged_eigenvalues)
520 0 : mooseError(n, " not in [0, ", n_converged_eigenvalues, ")");
521 :
522 2446 : return _eigen_sys.get_eigenpair(n);
523 : }
524 :
525 : void
526 50 : NonlinearEigenSystem::attachPreconditioner(Preconditioner<Number> * preconditioner)
527 : {
528 50 : _preconditioner = preconditioner;
529 :
530 : // If we have a customized preconditioner,
531 : // We need to let PETSc know that
532 50 : if (_preconditioner)
533 : {
534 50 : LibmeshPetscCall(Moose::SlepcSupport::registerPCToPETSc());
535 : // Mark this, and then we can setup correct petsc options
536 50 : _eigen_problem.solverParams(number())._customized_pc_for_eigen = true;
537 50 : _eigen_problem.solverParams(number())._type = Moose::ST_JFNK;
538 : }
539 50 : }
540 :
541 : void
542 50 : NonlinearEigenSystem::turnOffJacobian()
543 : {
544 : // Let us do nothing at the current moment
545 50 : }
546 :
547 : void
548 0 : NonlinearEigenSystem::residualAndJacobianTogether()
549 : {
550 0 : mooseError(
551 : "NonlinearEigenSystem::residualAndJacobianTogether is not implemented. It might even be "
552 : "nonsensical. If it is sensical and you want this capability, please contact a MOOSE "
553 : "developer.");
554 : }
555 :
556 : void
557 10 : NonlinearEigenSystem::computeScalingJacobian()
558 : {
559 10 : _eigen_problem.computeJacobianTag(*_current_solution, *_scaling_matrix, precondMatrixTag());
560 10 : }
561 :
562 : void
563 10 : NonlinearEigenSystem::computeScalingResidual()
564 : {
565 10 : _eigen_problem.computeResidualTag(*_current_solution, RHS(), nonEigenVectorTag());
566 10 : }
567 :
568 : std::set<TagID>
569 30376 : NonlinearEigenSystem::defaultVectorTags() const
570 : {
571 30376 : auto tags = NonlinearSystemBase::defaultVectorTags();
572 30376 : tags.insert(eigenVectorTag());
573 30376 : tags.insert(nonEigenVectorTag());
574 30376 : return tags;
575 0 : }
576 :
577 : std::set<TagID>
578 3853 : NonlinearEigenSystem::defaultMatrixTags() const
579 : {
580 3853 : auto tags = NonlinearSystemBase::defaultMatrixTags();
581 3853 : tags.insert(eigenMatrixTag());
582 3853 : tags.insert(nonEigenMatrixTag());
583 3853 : return tags;
584 0 : }
585 :
586 : #else
587 :
588 : NonlinearEigenSystem::NonlinearEigenSystem(EigenProblem & eigen_problem,
589 : const std::string & /*name*/)
590 : : libMesh::ParallelObject(eigen_problem)
591 : {
592 : mooseError("Need to install SLEPc to solve eigenvalue problems, please reconfigure libMesh\n");
593 : }
594 :
595 : #endif /* LIBMESH_HAVE_SLEPC */
|