LCOV - code coverage report
Current view: top level - src/LinearSolvers - Preconditioner.h (source / functions) Coverage Total Hit
Test: report.info Lines: 0.0 % 203 0
Test Date: 2025-05-21 12:05:18 Functions: 0.0 % 26 0
Branches: 0.0 % 406 0

             Branch data     Line data    Source code
       1                 :             : //
       2                 :             : // General pre-conditioners for the pre-conditioned Conjugate Gradient Solver
       3                 :             : // such as Jacobi, Polynomial Newton, Polynomial Chebyshev, Richardson, Gauss-Seidel
       4                 :             : // provides a function operator() that returns the preconditioned field
       5                 :             : //
       6                 :             : 
       7                 :             : #ifndef IPPL_PRECONDITIONER_H
       8                 :             : #define IPPL_PRECONDITIONER_H
       9                 :             : 
      10                 :             : #include "Expression/IpplOperations.h"  // get the function apply()
      11                 :             : 
      12                 :             : // Expands to a lambda that acts as a wrapper for a differential operator
      13                 :             : // fun: the function for which to create the wrapper, such as ippl::laplace
      14                 :             : // type: the argument type, which should match the LHS type for the solver
      15                 :             : #define IPPL_SOLVER_OPERATOR_WRAPPER(fun, type) \
      16                 :             :     [](type arg) {                              \
      17                 :             :         return fun(arg);                        \
      18                 :             :     }
      19                 :             : 
      20                 :             : namespace ippl {
      21                 :             :     template <typename Field>
      22                 :             :     struct preconditioner {
      23                 :             :         constexpr static unsigned Dim = Field::dim;
      24                 :             :         using mesh_type               = typename Field::Mesh_t;
      25                 :             :         using layout_type             = typename Field::Layout_t;
      26                 :             : 
      27                 :           0 :         preconditioner()
      28         [ #  # ]:           0 :             : type_m("Identity") {}
      29                 :             : 
      30                 :           0 :         preconditioner(std::string name)
      31                 :           0 :             : type_m(name) {}
      32                 :             : 
      33                 :           0 :         virtual ~preconditioner() = default;
      34                 :             : 
      35                 :             :         // Placeholder for the function operator, actually implemented in the derived classes
      36                 :           0 :         virtual Field operator()(Field& u) {
      37                 :           0 :             Field res = u.deepCopy();
      38                 :           0 :             return res;
      39                 :             :         }
      40                 :             : 
      41                 :             :         // Placeholder for setting additional fields, actually implemented in the derived classes
      42                 :           0 :         virtual void init_fields(Field& b) {
      43         [ #  # ]:           0 :             Field res = b.deepCopy();
      44                 :           0 :             return;
      45                 :           0 :         }
      46                 :             : 
      47                 :             :         std::string get_type() { return type_m; };
      48                 :             : 
      49                 :             :     protected:
      50                 :             :         std::string type_m;
      51                 :             :     };
      52                 :             : 
      53                 :             :     /*!
      54                 :             :      * Jacobi preconditioner
      55                 :             :      * M = w*diag{A} // w is a damping factor
      56                 :             :      */
      57                 :             :     template <typename Field, typename InvDiagF>
      58                 :             :     struct jacobi_preconditioner : public preconditioner<Field> {
      59                 :             :         constexpr static unsigned Dim = Field::dim;
      60                 :             :         using mesh_type               = typename Field::Mesh_t;
      61                 :             :         using layout_type             = typename Field::Layout_t;
      62                 :             : 
      63                 :           0 :         jacobi_preconditioner(InvDiagF&& inverse_diagonal, double w = 1.0)
      64                 :             :             : preconditioner<Field>("jacobi")
      65   [ #  #  #  # ]:           0 :             , w_m(w) {
      66                 :           0 :             inverse_diagonal_m = std::move(inverse_diagonal);
      67                 :           0 :         }
      68                 :             : 
      69                 :           0 :         Field operator()(Field& u) override {
      70                 :           0 :             mesh_type& mesh     = u.get_mesh();
      71                 :           0 :             layout_type& layout = u.getLayout();
      72                 :           0 :             Field res(mesh, layout);
      73                 :             : 
      74   [ #  #  #  #  :           0 :             res = inverse_diagonal_m(u);
                   #  # ]
      75   [ #  #  #  # ]:           0 :             res = w_m * res;
      76                 :           0 :             return res;
      77                 :           0 :         }
      78                 :             : 
      79                 :             :     protected:
      80                 :             :         InvDiagF inverse_diagonal_m;
      81                 :             :         double w_m;  // Damping factor
      82                 :             :     };
      83                 :             : 
      84                 :             :     /*!
      85                 :             :      * Polynomial Newton Preconditioner
      86                 :             :      * Computes iteratively approximations for A^-1
      87                 :             :      */
      88                 :             :     template <typename Field, typename OperatorF>
      89                 :             :     struct polynomial_newton_preconditioner : public preconditioner<Field> {
      90                 :             :         constexpr static unsigned Dim = Field::dim;
      91                 :             :         using mesh_type               = typename Field::Mesh_t;
      92                 :             :         using layout_type             = typename Field::Layout_t;
      93                 :             : 
      94                 :           0 :         polynomial_newton_preconditioner(OperatorF&& op, double alpha, double beta,
      95                 :             :                                          unsigned int max_level = 6, double zeta = 1e-3,
      96                 :             :                                          double* eta = nullptr)
      97                 :             :             : preconditioner<Field>("polynomial_newton")
      98                 :           0 :             , alpha_m(alpha)
      99                 :           0 :             , beta_m(beta)
     100                 :           0 :             , level_m(max_level)
     101                 :           0 :             , zeta_m(zeta)
     102   [ #  #  #  # ]:           0 :             , eta_m(eta) {
     103                 :           0 :             op_m = std::move(op);
     104                 :           0 :         }
     105                 :             : 
     106                 :             :         // Memory management is needed because of runtime defined eta_m
     107                 :           0 :         ~polynomial_newton_preconditioner() {
     108                 :           0 :             if (eta_m != nullptr) {
     109         [ #  # ]:           0 :                 delete[] eta_m;
     110                 :           0 :                 eta_m = nullptr;
     111                 :             :             }
     112         [ #  # ]:           0 :         }
     113                 :             : 
     114                 :             :         polynomial_newton_preconditioner(const polynomial_newton_preconditioner& other)
     115                 :             :             : preconditioner<Field>("polynomial_newton")
     116                 :             :             , level_m(other.level_m)
     117                 :             :             , alpha_m(other.alpha_m)
     118                 :             :             , beta_m(other.beta_m)
     119                 :             :             , zeta_m(other.zeta_m)
     120                 :             :             , eta_m(other.eta_m) {
     121                 :             :             op_m = std::move(other.op_m);
     122                 :             :         }
     123                 :             : 
     124                 :             :         polynomial_newton_preconditioner& operator=(const polynomial_newton_preconditioner& other) {
     125                 :             :             return *this = polynomial_newton_preconditioner(other);
     126                 :             :         }
     127                 :             : 
     128                 :           0 :         Field recursive_preconditioner(Field& u, unsigned int level) {
     129                 :           0 :             mesh_type& mesh     = u.get_mesh();
     130         [ #  # ]:           0 :             layout_type& layout = u.getLayout();
     131                 :             :             // Define etas if not defined yet
     132         [ #  # ]:           0 :             if (eta_m == nullptr) {
     133                 :             :                 // Precompute the etas for later use
     134   [ #  #  #  # ]:           0 :                 eta_m    = new double[level_m + 1];
     135                 :           0 :                 eta_m[0] = 2.0 / ((alpha_m + beta_m) * (1.0 + zeta_m));
     136         [ #  # ]:           0 :                 if (level_m > 0) {
     137                 :           0 :                     eta_m[1] =
     138                 :             :                         2.0
     139                 :           0 :                         / (1.0 + 2 * alpha_m * eta_m[0] - alpha_m * eta_m[0] * alpha_m * eta_m[0]);
     140                 :             :                 }
     141         [ #  # ]:           0 :                 for (unsigned int i = 2; i < level_m + 1; ++i) {
     142                 :           0 :                     eta_m[i] = 2.0 / (1.0 + 2 * eta_m[i - 1] - eta_m[i - 1] * eta_m[i - 1]);
     143                 :             :                 }
     144                 :             :             }
     145                 :             : 
     146         [ #  # ]:           0 :             Field res(mesh, layout);
     147                 :             :             // Base case
     148         [ #  # ]:           0 :             if (level == 0) {
     149   [ #  #  #  # ]:           0 :                 res = eta_m[0] * u;
     150                 :           0 :                 return res;
     151                 :             :             }
     152                 :             :             // Recursive case
     153         [ #  # ]:           0 :             Field PAPr(mesh, layout);
     154         [ #  # ]:           0 :             Field Pr(mesh, layout);
     155                 :             : 
     156   [ #  #  #  # ]:           0 :             Pr   = recursive_preconditioner(u, level - 1);
     157   [ #  #  #  #  :           0 :             PAPr = op_m(Pr);
                   #  # ]
     158   [ #  #  #  # ]:           0 :             PAPr = recursive_preconditioner(PAPr, level - 1);
     159   [ #  #  #  #  :           0 :             res  = eta_m[level] * (2.0 * Pr - PAPr);
             #  #  #  # ]
     160                 :           0 :             return res;
     161                 :           0 :         }
     162                 :             : 
     163                 :           0 :         Field operator()(Field& u) override { return recursive_preconditioner(u, level_m); }
     164                 :             : 
     165                 :             :     protected:
     166                 :             :         OperatorF op_m;        // Operator to be preconditioned
     167                 :             :         double alpha_m;        // Smallest Eigenvalue
     168                 :             :         double beta_m;         // Largest Eigenvalue
     169                 :             :         unsigned int level_m;  // Number of recursive calls
     170                 :             :         double zeta_m;  // smallest (alpha + beta) is multiplied by (1+zeta) to avoid clustering of
     171                 :             :                         // Eigenvalues
     172                 :             :         double* eta_m = nullptr;  // Size is determined at runtime
     173                 :             :     };
     174                 :             : 
     175                 :             :     /*!
     176                 :             :      * Polynomial Chebyshev Preconditioner
     177                 :             :      * Computes iteratively approximations for A^-1
     178                 :             :      */
     179                 :             :     template <typename Field, typename OperatorF>
     180                 :             :     struct polynomial_chebyshev_preconditioner : public preconditioner<Field> {
     181                 :             :         constexpr static unsigned Dim = Field::dim;
     182                 :             :         using mesh_type               = typename Field::Mesh_t;
     183                 :             :         using layout_type             = typename Field::Layout_t;
     184                 :             : 
     185                 :           0 :         polynomial_chebyshev_preconditioner(OperatorF&& op, double alpha, double beta,
     186                 :             :                                             unsigned int degree = 63, double zeta = 1e-3)
     187                 :             :             : preconditioner<Field>("polynomial_chebyshev")
     188                 :           0 :             , alpha_m(alpha)
     189                 :           0 :             , beta_m(beta)
     190                 :           0 :             , degree_m(degree)
     191                 :           0 :             , zeta_m(zeta)
     192   [ #  #  #  # ]:           0 :             , rho_m(nullptr) {
     193                 :           0 :             op_m = std::move(op);
     194                 :           0 :         }
     195                 :             : 
     196                 :             :         // Memory management is needed because of runtime defined rho_m
     197                 :           0 :         ~polynomial_chebyshev_preconditioner() {
     198                 :           0 :             if (rho_m != nullptr) {
     199         [ #  # ]:           0 :                 delete[] rho_m;
     200                 :           0 :                 rho_m = nullptr;
     201                 :             :             }
     202         [ #  # ]:           0 :         }
     203                 :             : 
     204                 :             :         polynomial_chebyshev_preconditioner(const polynomial_chebyshev_preconditioner& other)
     205                 :             :             : preconditioner<Field>("polynomial_chebyshev")
     206                 :             :             , degree_m(other.degree_m)
     207                 :             :             , theta_m(other.theta_m)
     208                 :             :             , sigma_m(other.sigma_m)
     209                 :             :             , delta_m(other.delta_m)
     210                 :             :             , alpha_m(other.delta_m)
     211                 :             :             , beta_m(other.delta_m)
     212                 :             :             , zeta_m(other.zeta_m)
     213                 :             :             , rho_m(other.rho_m) {
     214                 :             :             op_m = std::move(other.op_m);
     215                 :             :         }
     216                 :             : 
     217                 :             :         polynomial_chebyshev_preconditioner& operator=(
     218                 :             :             const polynomial_chebyshev_preconditioner& other) {
     219                 :             :             return *this = polynomial_chebyshev_preconditioner(other);
     220                 :             :         }
     221                 :             : 
     222                 :           0 :         Field operator()(Field& r) override {
     223                 :           0 :             mesh_type& mesh     = r.get_mesh();
     224         [ #  # ]:           0 :             layout_type& layout = r.getLayout();
     225                 :             : 
     226         [ #  # ]:           0 :             Field res(mesh, layout);
     227         [ #  # ]:           0 :             Field x(mesh, layout);
     228         [ #  # ]:           0 :             Field x_old(mesh, layout);
     229         [ #  # ]:           0 :             Field A(mesh, layout);
     230         [ #  # ]:           0 :             Field z(mesh, layout);
     231                 :             : 
     232                 :             :             // Precompute the coefficients if not done yet
     233         [ #  # ]:           0 :             if (rho_m == nullptr) {
     234                 :             :                 // Start precomputing the coefficients
     235                 :           0 :                 theta_m = (beta_m + alpha_m) / 2.0 * (1.0 + zeta_m);
     236                 :           0 :                 delta_m = (beta_m - alpha_m) / 2.0;
     237                 :           0 :                 sigma_m = theta_m / delta_m;
     238                 :             : 
     239   [ #  #  #  # ]:           0 :                 rho_m    = new double[degree_m + 1];
     240                 :           0 :                 rho_m[0] = 1.0 / sigma_m;
     241         [ #  # ]:           0 :                 for (unsigned int i = 1; i < degree_m + 1; ++i) {
     242                 :           0 :                     rho_m[i] = 1.0 / (2.0 * sigma_m - rho_m[i - 1]);
     243                 :             :                 }
     244                 :             :             }  // End of precomputing the coefficients
     245                 :             : 
     246   [ #  #  #  # ]:           0 :             res = r.deepCopy();
     247                 :             : 
     248   [ #  #  #  # ]:           0 :             x_old = r / theta_m;
     249   [ #  #  #  #  :           0 :             A     = op_m(r);
                   #  # ]
     250   [ #  #  #  #  :           0 :             x     = 2.0 * rho_m[1] / delta_m * (2.0 * r - A / theta_m);
          #  #  #  #  #  
                      # ]
     251                 :             : 
     252         [ #  # ]:           0 :             if (degree_m == 0) {
     253         [ #  # ]:           0 :                 return x_old;
     254                 :             :             }
     255                 :             : 
     256         [ #  # ]:           0 :             if (degree_m == 1) {
     257         [ #  # ]:           0 :                 return x;
     258                 :             :             }
     259         [ #  # ]:           0 :             for (unsigned int i = 2; i < degree_m + 1; ++i) {
     260   [ #  #  #  #  :           0 :                 A     = op_m(x);
                   #  # ]
     261   [ #  #  #  #  :           0 :                 z     = 2.0 / delta_m * (r - A);
                   #  # ]
     262   [ #  #  #  #  :           0 :                 res   = rho_m[i] * (2 * sigma_m * x - rho_m[i - 1] * x_old + z);
          #  #  #  #  #  
                #  #  # ]
     263   [ #  #  #  # ]:           0 :                 x_old = x.deepCopy();
     264   [ #  #  #  # ]:           0 :                 x     = res.deepCopy();
     265                 :             :             }
     266         [ #  # ]:           0 :             return res;
     267                 :           0 :         }
     268                 :             : 
     269                 :             :     protected:
     270                 :             :         OperatorF op_m;
     271                 :             :         double alpha_m;
     272                 :             :         double beta_m;
     273                 :             :         double delta_m;
     274                 :             :         double theta_m;
     275                 :             :         double sigma_m;
     276                 :             :         unsigned degree_m;
     277                 :             :         double zeta_m;
     278                 :             :         double* rho_m = nullptr;  // Size is determined at runtime
     279                 :             :     };
     280                 :             : 
     281                 :             :     /*!
     282                 :             :      * Richardson preconditioner
     283                 :             :      */
     284                 :             :     template <typename Field, typename UpperAndLowerF, typename InvDiagF>
     285                 :             :     struct richardson_preconditioner : public preconditioner<Field> {
     286                 :             :         constexpr static unsigned Dim = Field::dim;
     287                 :             :         using mesh_type               = typename Field::Mesh_t;
     288                 :             :         using layout_type             = typename Field::Layout_t;
     289                 :             : 
     290                 :           0 :         richardson_preconditioner(UpperAndLowerF&& upper_and_lower, InvDiagF&& inverse_diagonal,
     291                 :             :                                   unsigned innerloops = 5)
     292                 :             :             : preconditioner<Field>("Richardson")
     293   [ #  #  #  #  :           0 :             , innerloops_m(innerloops) {
                   #  # ]
     294                 :           0 :             upper_and_lower_m  = std::move(upper_and_lower);
     295                 :           0 :             inverse_diagonal_m = std::move(inverse_diagonal);
     296                 :           0 :         }
     297                 :             : 
     298                 :           0 :         Field operator()(Field& r) override {
     299                 :           0 :             mesh_type& mesh     = r.get_mesh();
     300                 :           0 :             layout_type& layout = r.getLayout();
     301                 :           0 :             Field g(mesh, layout);
     302                 :             : 
     303         [ #  # ]:           0 :             g = 0;
     304         [ #  # ]:           0 :             for (unsigned int j = 0; j < innerloops_m; ++j) {
     305   [ #  #  #  #  :           0 :                 ULg_m = upper_and_lower_m(g);
                   #  # ]
     306   [ #  #  #  # ]:           0 :                 g     = r - ULg_m;
     307   [ #  #  #  #  :           0 :                 g     = inverse_diagonal_m(g) * g;
             #  #  #  # ]
     308                 :             :             }
     309                 :           0 :             return g;
     310                 :           0 :         }
     311                 :             : 
     312                 :           0 :         void init_fields(Field& b) override {
     313                 :           0 :             layout_type& layout = b.getLayout();
     314                 :           0 :             mesh_type& mesh     = b.get_mesh();
     315                 :             : 
     316   [ #  #  #  # ]:           0 :             ULg_m = Field(mesh, layout);
     317                 :           0 :         }
     318                 :             : 
     319                 :             :     protected:
     320                 :             :         UpperAndLowerF upper_and_lower_m;
     321                 :             :         InvDiagF inverse_diagonal_m;
     322                 :             :         unsigned innerloops_m;
     323                 :             :         Field ULg_m;
     324                 :             :     };
     325                 :             : 
     326                 :             :     /*!
     327                 :             :      * 2-step Gauss-Seidel preconditioner
     328                 :             :      */
     329                 :             :     template <typename Field, typename LowerF, typename UpperF, typename InvDiagF>
     330                 :             :     struct gs_preconditioner : public preconditioner<Field> {
     331                 :             :         constexpr static unsigned Dim = Field::dim;
     332                 :             :         using mesh_type               = typename Field::Mesh_t;
     333                 :             :         using layout_type             = typename Field::Layout_t;
     334                 :             : 
     335                 :           0 :         gs_preconditioner(LowerF&& lower, UpperF&& upper, InvDiagF&& inverse_diagonal,
     336                 :             :                           unsigned innerloops, unsigned outerloops)
     337                 :             :             : preconditioner<Field>("Gauss-Seidel")
     338                 :           0 :             , innerloops_m(innerloops)
     339   [ #  #  #  #  :           0 :             , outerloops_m(outerloops) {
             #  #  #  # ]
     340                 :           0 :             lower_m            = std::move(lower);
     341                 :           0 :             upper_m            = std::move(upper);
     342                 :           0 :             inverse_diagonal_m = std::move(inverse_diagonal);
     343                 :           0 :         }
     344                 :             : 
     345                 :           0 :         Field operator()(Field& b) override {
     346                 :           0 :             layout_type& layout = b.getLayout();
     347                 :           0 :             mesh_type& mesh     = b.get_mesh();
     348                 :             : 
     349                 :           0 :             Field x(mesh, layout);
     350                 :             : 
     351         [ #  # ]:           0 :             x = 0;  // Initial guess
     352                 :             : 
     353         [ #  # ]:           0 :             for (unsigned int k = 0; k < outerloops_m; ++k) {
     354   [ #  #  #  #  :           0 :                 UL_m = upper_m(x);
                   #  # ]
     355   [ #  #  #  # ]:           0 :                 r_m  = b - UL_m;
     356         [ #  # ]:           0 :                 for (unsigned int j = 0; j < innerloops_m; ++j) {
     357   [ #  #  #  #  :           0 :                     UL_m = lower_m(x);
                   #  # ]
     358   [ #  #  #  # ]:           0 :                     x    = r_m - UL_m;
     359   [ #  #  #  #  :           0 :                     x    = inverse_diagonal_m(x) * x;
             #  #  #  # ]
     360                 :             :                 }
     361   [ #  #  #  #  :           0 :                 UL_m = lower_m(x);
                   #  # ]
     362   [ #  #  #  # ]:           0 :                 r_m  = b - UL_m;
     363         [ #  # ]:           0 :                 for (unsigned int j = 0; j < innerloops_m; ++j) {
     364   [ #  #  #  #  :           0 :                     UL_m = upper_m(x);
                   #  # ]
     365   [ #  #  #  # ]:           0 :                     x    = r_m - UL_m;
     366   [ #  #  #  #  :           0 :                     x    = inverse_diagonal_m(x) * x;
             #  #  #  # ]
     367                 :             :                 }
     368                 :             :             }
     369                 :           0 :             return x;
     370                 :           0 :         }
     371                 :             : 
     372                 :           0 :         void init_fields(Field& b) override {
     373                 :           0 :             layout_type& layout = b.getLayout();
     374                 :           0 :             mesh_type& mesh     = b.get_mesh();
     375                 :             : 
     376   [ #  #  #  # ]:           0 :             UL_m = Field(mesh, layout);
     377   [ #  #  #  # ]:           0 :             r_m  = Field(mesh, layout);
     378                 :           0 :         }
     379                 :             : 
     380                 :             :     protected:
     381                 :             :         LowerF lower_m;
     382                 :             :         UpperF upper_m;
     383                 :             :         InvDiagF inverse_diagonal_m;
     384                 :             :         unsigned innerloops_m;
     385                 :             :         unsigned outerloops_m;
     386                 :             :         Field UL_m;
     387                 :             :         Field r_m;
     388                 :             :     };
     389                 :             : 
     390                 :             :     /*!
     391                 :             :      * Symmetric successive over-relaxation
     392                 :             :      */
     393                 :             :     template <typename Field, typename LowerF, typename UpperF, typename InvDiagF, typename DiagF>
     394                 :             :     struct ssor_preconditioner : public preconditioner<Field> {
     395                 :             :         constexpr static unsigned Dim = Field::dim;
     396                 :             :         using mesh_type               = typename Field::Mesh_t;
     397                 :             :         using layout_type             = typename Field::Layout_t;
     398                 :             : 
     399                 :           0 :         ssor_preconditioner(LowerF&& lower, UpperF&& upper, InvDiagF&& inverse_diagonal,
     400                 :             :                             DiagF&& diagonal, unsigned innerloops, unsigned outerloops,
     401                 :             :                             double omega)
     402                 :             :             : preconditioner<Field>("ssor")
     403                 :           0 :             , innerloops_m(innerloops)
     404                 :           0 :             , outerloops_m(outerloops)
     405   [ #  #  #  #  :           0 :             , omega_m(omega) {
             #  #  #  # ]
     406                 :           0 :             lower_m            = std::move(lower);
     407                 :           0 :             upper_m            = std::move(upper);
     408                 :           0 :             inverse_diagonal_m = std::move(inverse_diagonal);
     409                 :           0 :             diagonal_m         = std::move(diagonal);
     410                 :           0 :         }
     411                 :             : 
     412                 :           0 :         Field operator()(Field& b) override {
     413   [ #  #  #  #  :           0 :             static IpplTimings::TimerRef initTimer = IpplTimings::getTimer("SSOR Init");
             #  #  #  # ]
     414                 :           0 :             IpplTimings::startTimer(initTimer);
     415                 :             : 
     416                 :             :             double D;
     417                 :             : 
     418                 :           0 :             layout_type& layout = b.getLayout();
     419                 :           0 :             mesh_type& mesh     = b.get_mesh();
     420                 :             : 
     421                 :           0 :             Field x(mesh, layout);
     422                 :             : 
     423         [ #  # ]:           0 :             x = 0;  // Initial guess
     424                 :             : 
     425         [ #  # ]:           0 :             IpplTimings::stopTimer(initTimer);
     426                 :             : 
     427   [ #  #  #  #  :           0 :             static IpplTimings::TimerRef loopTimer = IpplTimings::getTimer("SSOR loop");
             #  #  #  # ]
     428         [ #  # ]:           0 :             IpplTimings::startTimer(loopTimer);
     429                 :             : 
     430         [ #  # ]:           0 :             for (unsigned int k = 0; k < outerloops_m; ++k) {
     431   [ #  #  #  #  :           0 :                 UL_m = upper_m(x);
                   #  # ]
     432   [ #  #  #  # ]:           0 :                 D    = diagonal_m(x);
     433   [ #  #  #  #  :           0 :                 r_m  = omega_m * (b - UL_m) + (1.0 - omega_m) * D * x;
          #  #  #  #  #  
                      # ]
     434                 :             : 
     435         [ #  # ]:           0 :                 for (unsigned int j = 0; j < innerloops_m; ++j) {
     436   [ #  #  #  #  :           0 :                     UL_m = lower_m(x);
                   #  # ]
     437   [ #  #  #  #  :           0 :                     x    = r_m - omega_m * UL_m;
                   #  # ]
     438   [ #  #  #  #  :           0 :                     x    = inverse_diagonal_m(x) * x;
             #  #  #  # ]
     439                 :             :                 }
     440   [ #  #  #  #  :           0 :                 UL_m = lower_m(x);
                   #  # ]
     441   [ #  #  #  # ]:           0 :                 D    = diagonal_m(x);
     442   [ #  #  #  #  :           0 :                 r_m  = omega_m * (b - UL_m) + (1.0 - omega_m) * D * x;
          #  #  #  #  #  
                      # ]
     443         [ #  # ]:           0 :                 for (unsigned int j = 0; j < innerloops_m; ++j) {
     444   [ #  #  #  #  :           0 :                     UL_m = upper_m(x);
                   #  # ]
     445   [ #  #  #  #  :           0 :                     x    = r_m - omega_m * UL_m;
                   #  # ]
     446   [ #  #  #  #  :           0 :                     x    = inverse_diagonal_m(x) * x;
             #  #  #  # ]
     447                 :             :                 }
     448                 :             :             }
     449         [ #  # ]:           0 :             IpplTimings::stopTimer(loopTimer);
     450                 :           0 :             return x;
     451                 :           0 :         }
     452                 :             : 
     453                 :           0 :         void init_fields(Field& b) override {
     454                 :           0 :             layout_type& layout = b.getLayout();
     455                 :           0 :             mesh_type& mesh     = b.get_mesh();
     456                 :             : 
     457   [ #  #  #  # ]:           0 :             UL_m = Field(mesh, layout);
     458   [ #  #  #  # ]:           0 :             r_m  = Field(mesh, layout);
     459                 :           0 :         }
     460                 :             : 
     461                 :             :     protected:
     462                 :             :         LowerF lower_m;
     463                 :             :         UpperF upper_m;
     464                 :             :         InvDiagF inverse_diagonal_m;
     465                 :             :         DiagF diagonal_m;
     466                 :             :         unsigned innerloops_m;
     467                 :             :         unsigned outerloops_m;
     468                 :             :         double omega_m;
     469                 :             :         Field UL_m;
     470                 :             :         Field r_m;
     471                 :             :     };
     472                 :             : 
     473                 :             :     /*!
     474                 :             :      * Computes the largest Eigenvalue of the Functor f
     475                 :             :      * @param f Functor
     476                 :             :      * @param x_0 initial guess
     477                 :             :      * @param max_iter maximum number of iterations
     478                 :             :      * @param tol tolerance
     479                 :             :      */
     480                 :             :     template <typename Field, typename Functor>
     481                 :             :     double powermethod(Functor&& f, Field& x_0, unsigned int max_iter = 5000, double tol = 1e-3) {
     482                 :             :         unsigned int i      = 0;
     483                 :             :         using mesh_type     = typename Field::Mesh_t;
     484                 :             :         using layout_type   = typename Field::Layout_t;
     485                 :             :         mesh_type& mesh     = x_0.get_mesh();
     486                 :             :         layout_type& layout = x_0.getLayout();
     487                 :             :         Field x_new(mesh, layout);
     488                 :             :         Field x_diff(mesh, layout);
     489                 :             :         double error  = 1.0;
     490                 :             :         double lambda = 1.0;
     491                 :             :         while (error > tol && i < max_iter) {
     492                 :             :             x_new  = f(x_0);
     493                 :             :             lambda = norm(x_new);
     494                 :             :             x_diff = x_new - lambda * x_0;
     495                 :             :             error  = norm(x_diff);
     496                 :             :             x_new  = x_new / lambda;
     497                 :             :             x_0    = x_new.deepCopy();
     498                 :             :             ++i;
     499                 :             :         }
     500                 :             :         if (i == max_iter) {
     501                 :             :             std::cerr << "Powermethod did not converge, lambda_max : " << lambda
     502                 :             :                       << ", error : " << error << std::endl;
     503                 :             :         }
     504                 :             :         return lambda;
     505                 :             :     }
     506                 :             : 
     507                 :             :     /*!
     508                 :             :      * Computes the smallest Eigenvalue of the Functor f (f must be symmetric positive definite)
     509                 :             :      * @param f Functor
     510                 :             :      * @param x_0 initial guess
     511                 :             :      * @param lambda_max largest Eigenvalue
     512                 :             :      * @param max_iter maximum number of iterations
     513                 :             :      * @param tol tolerance
     514                 :             :      */
     515                 :             :     template <typename Field, typename Functor>
     516                 :             :     double adapted_powermethod(Functor&& f, Field& x_0, double lambda_max,
     517                 :             :                                unsigned int max_iter = 5000, double tol = 1e-3) {
     518                 :             :         unsigned int i      = 0;
     519                 :             :         using mesh_type     = typename Field::Mesh_t;
     520                 :             :         using layout_type   = typename Field::Layout_t;
     521                 :             :         mesh_type& mesh     = x_0.get_mesh();
     522                 :             :         layout_type& layout = x_0.getLayout();
     523                 :             :         Field x_new(mesh, layout);
     524                 :             :         Field x_diff(mesh, layout);
     525                 :             :         double error  = 1.0;
     526                 :             :         double lambda = 1.0;
     527                 :             :         while (error > tol && i < max_iter) {
     528                 :             :             x_new  = f(x_0);
     529                 :             :             x_new  = x_new - lambda_max * x_0;
     530                 :             :             lambda = -norm(x_new);  // We know that lambda < 0;
     531                 :             :             x_diff = x_new - lambda * x_0;
     532                 :             :             error  = norm(x_diff);
     533                 :             :             x_new  = x_new / -lambda;
     534                 :             :             x_0    = x_new.deepCopy();
     535                 :             :             ++i;
     536                 :             :         }
     537                 :             :         lambda = lambda + lambda_max;
     538                 :             :         if (i == max_iter) {
     539                 :             :             std::cerr << "Powermethod did not converge, lambda_min : " << lambda
     540                 :             :                       << ", error : " << error << std::endl;
     541                 :             :         }
     542                 :             :         return lambda;
     543                 :             :     }
     544                 :             : 
     545                 :             :     /*
     546                 :             :     // Use the powermethod to compute the eigenvalues if no analytical solution is known
     547                 :             :     beta = powermethod(std::move(op_m), x_0);
     548                 :             :     // Trick for computing the smallest Eigenvalue of SPD Matrix
     549                 :             :     alpha = adapted_powermethod(std::move(op_m), x_0, beta);
     550                 :             :      */
     551                 :             : 
     552                 :             : }  // namespace ippl
     553                 :             : 
     554                 :             : #endif  // IPPL_PRECONDITIONER_H
        

Generated by: LCOV version 2.0-1