LCOV - code coverage report
Current view: top level - src/systems - NonlinearEigenSystem.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 203 235 86.4 %
Date: 2025-07-17 01:28:37 Functions: 22 29 75.9 %
Legend: Lines: hit not hit

          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 */

Generated by: LCOV version 1.14