LCOV - code coverage report
Current view: top level - include/problems - EigenProblem.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 419b9d Lines: 25 26 96.2 %
Date: 2025-08-08 20:01:16 Functions: 18 18 100.0 %
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             : #pragma once
      11             : 
      12             : // MOOSE Includes
      13             : #include "FEProblemBase.h"
      14             : #include "Eigenvalue.h"
      15             : 
      16             : class NonlinearEigenSystem;
      17             : 
      18             : /**
      19             :  * Problem for solving eigenvalue problems
      20             :  */
      21             : class EigenProblem : public FEProblemBase
      22             : {
      23             : public:
      24             :   static InputParameters validParams();
      25             : 
      26             :   EigenProblem(const InputParameters & parameters);
      27             : 
      28             :   virtual std::string solverTypeString(unsigned int solver_sys_num = 0) override;
      29             : 
      30             : #ifdef LIBMESH_HAVE_SLEPC
      31             :   virtual void solve(const unsigned int nl_sys_num) override;
      32             : 
      33             :   virtual void init() override;
      34             : 
      35             :   virtual bool solverSystemConverged(const unsigned int solver_sys_num) override;
      36             : 
      37        1894 :   unsigned int getNEigenPairsRequired() const { return _n_eigen_pairs_required; }
      38         588 :   void setNEigenPairsRequired(unsigned int n_eigen_pairs)
      39             :   {
      40         588 :     _n_eigen_pairs_required = n_eigen_pairs;
      41         588 :   }
      42             :   bool isGeneralizedEigenvalueProblem() const { return _generalized_eigenvalue_problem; }
      43             :   bool isNonlinearEigenvalueSolver(unsigned int eigen_sys_num) const;
      44             :   // silences warning in debug mode about the other computeJacobian signature being hidden
      45             :   using FEProblemBase::computeJacobian;
      46             : 
      47             :   NonlinearEigenSystem & getNonlinearEigenSystem(const unsigned int nl_sys_num);
      48             :   NonlinearEigenSystem & getCurrentNonlinearEigenSystem();
      49             : 
      50             :   virtual void checkProblemIntegrity() override;
      51             : 
      52             :   /**
      53             :    * A flag indicates if a negative sign is used in eigen kernels.
      54             :    * If the negative sign is used, eigen kernels are consistent in nonlinear solver.
      55             :    * In nonlinear solver, RHS kernels always have a negative sign.
      56             :    */
      57       19230 :   bool negativeSignEigenKernel() const { return _negative_sign_eigen_kernel; }
      58             : 
      59             :   /**
      60             :    * Set postprocessor and normalization factor
      61             :    * 'Postprocessor' is often used to compute an integral of physics variables
      62             :    */
      63             :   void setNormalization(const PostprocessorName & pp,
      64             :                         const Real value = std::numeric_limits<Real>::max());
      65             : 
      66             :   /**
      67             :    * Set an initial eigenvalue for initial normalization
      68             :    */
      69         584 :   void setInitialEigenvalue(const Real initial_eigenvalue)
      70             :   {
      71         584 :     _initial_eigenvalue = initial_eigenvalue;
      72         584 :   }
      73             : 
      74             :   /**
      75             :    * Whether or not we are doing free power iteration. It is used in convergence check.
      76             :    * We need to mark the solver as "converged" when doing free power to retrieve
      77             :    * the final solution from SLPEc
      78             :    */
      79        2988 :   bool doFreePowerIteration() const { return _do_free_power_iteration; }
      80             : 
      81             :   /**
      82             :    * Set a flag to indicate whether or not we are doing free power iterations.
      83             :    */
      84        1116 :   void doFreePowerIteration(bool do_power) { _do_free_power_iteration = do_power; }
      85             : 
      86             :   /**
      87             :    * Eigenvector need to be scaled back if it was scaled in an earlier stage
      88             :    * Scaling eigen vector does not affect solution (eigenvalue, eigenvector),
      89             :    * but it does affect the convergence rate. To have an optimal convergence rate,
      90             :    * We pre-scale eigen vector using the same factor as the one computed in
      91             :    * "postScaleEigenVector"
      92             :    */
      93             :   void preScaleEigenVector(const std::pair<Real, Real> & eig);
      94             : 
      95             :   /**
      96             :    * Normalize eigen vector. Scale eigen vector such as ||x|| = _normal_factor
      97             :    * This might be useful when coupling to other physics
      98             :    */
      99             :   void postScaleEigenVector();
     100             : 
     101             :   /**
     102             :    * Scale eigenvector. Scaling_factor is often computed based on physics.
     103             :    */
     104             :   void scaleEigenvector(const Real scaling_factor);
     105             : 
     106             :   /**
     107             :    * Set eigen problem type. Don't need to use this if we use Newton eigenvalue solver.
     108             :    */
     109             :   void setEigenproblemType(Moose::EigenProblemType eigen_problem_type);
     110             : 
     111             :   /**
     112             :    * Compute the residual of Ax - \lambda Bx. If there is no \lambda yet, "1" will
     113             :    * be used.
     114             :    */
     115             :   virtual Real computeResidualL2Norm() override;
     116             : 
     117             :   /**
     118             :    * Form a Jacobian matrix for all kernels and BCs with a given tag
     119             :    */
     120             :   virtual void computeJacobianTag(const NumericVector<Number> & soln,
     121             :                                   SparseMatrix<Number> & jacobian,
     122             :                                   TagID tag) override;
     123             : 
     124             :   /**
     125             :    * Form several matrices simultaneously
     126             :    */
     127             :   void computeMatricesTags(const NumericVector<Number> & soln,
     128             :                            const std::vector<SparseMatrix<Number> *> & jacobians,
     129             :                            const std::set<TagID> & tags);
     130             : 
     131             :   /**
     132             :    * Form two Jacobian matrices, where each is associated with one tag, through one
     133             :    * element-loop.
     134             :    */
     135             :   void computeJacobianAB(const NumericVector<Number> & soln,
     136             :                          SparseMatrix<Number> & jacobianA,
     137             :                          SparseMatrix<Number> & jacobianB,
     138             :                          TagID tagA,
     139             :                          TagID tagB);
     140             : 
     141             :   virtual void computeJacobianBlocks(std::vector<JacobianBlock *> & blocks,
     142             :                                      const unsigned int nl_sys_num) override;
     143             : 
     144             :   /**
     145             :    * Form a vector for all kernels and BCs with a given tag
     146             :    */
     147             :   virtual void computeResidualTag(const NumericVector<Number> & soln,
     148             :                                   NumericVector<Number> & residual,
     149             :                                   TagID tag) override;
     150             : 
     151             :   /**
     152             :    * Form two vetors, where each is associated with one tag, through one
     153             :    * element-loop.
     154             :    */
     155             :   void computeResidualAB(const NumericVector<Number> & soln,
     156             :                          NumericVector<Number> & residualA,
     157             :                          NumericVector<Number> & residualB,
     158             :                          TagID tagA,
     159             :                          TagID tagB);
     160             : 
     161             :   /**
     162             :    * Convenience function for performing execution of MOOSE systems.
     163             :    * We override this function to perform an initial scaling.
     164             :    */
     165             :   virtual void execute(const ExecFlagType & exec_type) override;
     166             : 
     167             :   /**
     168             :    * For nonlinear eigen solver, a good initial value can help convergence.
     169             :    * Should set initial values for only eigen variables.
     170             :    */
     171             :   void initEigenvector(const Real initial_value);
     172             : 
     173             :   /**
     174             :    * Which eigenvalue is active
     175             :    */
     176        1296 :   unsigned int activeEigenvalueIndex() const { return _active_eigen_index; }
     177             : 
     178             :   /**
     179             :    * Hook up monitors for SNES and KSP
     180             :    */
     181             :   virtual void initPetscOutputAndSomeSolverSettings() override;
     182             : 
     183             :   /**
     184             :    * Whether or not to output eigenvalue inverse. The inverse is useful for
     185             :    * neutronics community
     186             :    */
     187        5112 :   bool outputInverseEigenvalue() const { return _output_inverse_eigenvalue; }
     188             : 
     189             :   /**
     190             :    * Set a flag to indicate whether or not to output eigenvalue inverse.
     191             :    */
     192          10 :   void outputInverseEigenvalue(bool inverse) { _output_inverse_eigenvalue = inverse; }
     193             : 
     194             :   /**
     195             :    * Whether or not we are in a linear solver iteration
     196             :    */
     197        9128 :   bool onLinearSolver() const { return _on_linear_solver; }
     198             : 
     199             :   /**
     200             :    * Set a flag to indicate whether or not we are in a linear solver iteration
     201             :    */
     202        9272 :   void onLinearSolver(bool ols) { _on_linear_solver = ols; }
     203             : 
     204             :   /**
     205             :    * Whether or not matrices are constant
     206             :    */
     207        8448 :   bool constantMatrices() const { return _constant_matrices; }
     208             : 
     209             :   /**
     210             :    * Set a flag to indicate whether or not we use constant matrices
     211             :    */
     212         588 :   void constantMatrices(bool cm) { _constant_matrices = cm; }
     213             : 
     214             :   /**
     215             :    * Whether or not constant matrices were already formed
     216             :    */
     217        3412 :   bool wereMatricesFormed() const { return _matrices_formed; }
     218             : 
     219             :   /**
     220             :    * Set a flag to indicate whether or not constant matrices were already formed
     221             :    */
     222         380 :   void wereMatricesFormed(bool mf) { _matrices_formed = mf; }
     223             : 
     224             :   /**
     225             :    * Form the Bx norm
     226             :    */
     227             :   Real formNorm();
     228             : 
     229             :   /**
     230             :    * Whether a Bx norm postprocessor has been provided
     231             :    */
     232        8056 :   bool bxNormProvided() const { return _bx_norm_name.has_value(); }
     233             : 
     234             :   /**
     235             :    * Set the Bx norm postprocessor programatically
     236             :    */
     237             :   void setBxNorm(const PostprocessorName & bx_norm) { _bx_norm_name = bx_norm; }
     238             : 
     239             : protected:
     240             :   unsigned int _n_eigen_pairs_required;
     241             :   bool _generalized_eigenvalue_problem;
     242             :   std::shared_ptr<NonlinearEigenSystem> _nl_eigen;
     243             : 
     244             :   /// Whether or not use negative sign for Bx. Use negative sign by default to
     245             :   /// make the eigen system consistent with nonlinear system
     246             :   bool _negative_sign_eigen_kernel;
     247             :   /// Which eigenvalue is used to compute residual. By default the zeroth eigenvalue
     248             :   /// is used.
     249             :   unsigned int _active_eigen_index;
     250             : 
     251             :   /// Whether or not we are doing free power iteration. Free power iteration is
     252             :   /// often used to compute initial guess for Newton eigen solver. It is automatically
     253             :   /// triggered by Eigenvalue Executioner
     254             :   bool _do_free_power_iteration;
     255             :   /// Whether or not output eigenvalue as its inverse. By default, we output regular eigenvalue.
     256             :   bool _output_inverse_eigenvalue;
     257             :   /// Whether or not we are in linear solver
     258             :   bool _on_linear_solver;
     259             :   /// Whether or not matrices had been formed
     260             :   bool _matrices_formed;
     261             :   /// Whether or not require constant matrices
     262             :   bool _constant_matrices;
     263             :   /// Whether or not we normalize eigenvector
     264             :   bool _has_normalization;
     265             :   /// Postprocessor used to compute a factor from eigenvector
     266             :   PostprocessorName _normalization;
     267             :   /// Postprocessor target value. The value of postprocessor should equal to
     268             :   /// '_normal_factor' by adjusting eigenvector
     269             :   Real _normal_factor;
     270             :   /// A flag to indicate if it is the first time calling the solve
     271             :   bool & _first_solve;
     272             :   /// A value used for initial normalization
     273             :   Real _initial_eigenvalue;
     274             : 
     275             : private:
     276             :   /**
     277             :    * Do some free/extra power iterations
     278             :    */
     279             :   void doFreeNonlinearPowerIterations(unsigned int free_power_iterations);
     280             : 
     281             :   /**
     282             :    * Adjust eigen vector by either scaling the existing values or setting new values
     283             :    * The operations are applied for only eigen variables
     284             :    */
     285             :   void adjustEigenVector(const Real value, bool scaling);
     286             : 
     287             :   /// The name of the Postprocessor providing the Bx norm. This may be empty in which case the
     288             :   /// default L2 norm of Bx will be used as the Bx norm
     289             :   std::optional<PostprocessorName> _bx_norm_name;
     290             : 
     291             : #endif
     292             : 
     293             :   using FEProblemBase::_nl;
     294             : };
     295             : 
     296             : #ifdef LIBMESH_HAVE_SLEPC
     297             : 
     298             : inline NonlinearEigenSystem &
     299         644 : EigenProblem::getNonlinearEigenSystem(const unsigned int nl_sys_num)
     300             : {
     301         644 :   if (nl_sys_num > 0)
     302           0 :     mooseError("eigen problems do not currently support multiple nonlinear eigen systems");
     303         644 :   return *_nl_eigen;
     304             : }
     305             : 
     306             : inline NonlinearEigenSystem &
     307       69374 : EigenProblem::getCurrentNonlinearEigenSystem()
     308             : {
     309       69374 :   return *_nl_eigen;
     310             : }
     311             : 
     312             : #endif

Generated by: LCOV version 1.14