LCOV - code coverage report
Current view: top level - ugbase/lib_algebra/operator/eigensolver - power_method.h (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 110 0
Test Date: 2025-09-21 23:31:46 Functions: 0.0 % 54 0

            Line data    Source code
       1              : /*
       2              :  * Copyright (c) 2018:  G-CSC, Goethe University Frankfurt
       3              :  * Author: Martin Stepniewski
       4              :  * 
       5              :  * This file is part of UG4.
       6              :  * 
       7              :  * UG4 is free software: you can redistribute it and/or modify it under the
       8              :  * terms of the GNU Lesser General Public License version 3 (as published by the
       9              :  * Free Software Foundation) with the following additional attribution
      10              :  * requirements (according to LGPL/GPL v3 §7):
      11              :  * 
      12              :  * (1) The following notice must be displayed in the Appropriate Legal Notices
      13              :  * of covered and combined works: "Based on UG4 (www.ug4.org/license)".
      14              :  * 
      15              :  * (2) The following notice must be displayed at a prominent place in the
      16              :  * terminal output of covered works: "Based on UG4 (www.ug4.org/license)".
      17              :  * 
      18              :  * (3) The following bibliography is recommended for citation and must be
      19              :  * preserved in all covered files:
      20              :  * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively
      21              :  *   parallel geometric multigrid solver on hierarchically distributed grids.
      22              :  *   Computing and visualization in science 16, 4 (2013), 151-164"
      23              :  * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel
      24              :  *   flexible software system for simulating pde based models on high performance
      25              :  *   computers. Computing and visualization in science 16, 4 (2013), 165-179"
      26              :  * 
      27              :  * This program is distributed in the hope that it will be useful,
      28              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      29              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      30              :  * GNU Lesser General Public License for more details.
      31              :  */
      32              : 
      33              : #ifndef __H__UG__LIB_ALGEBRA__POWER_METHOD_H__
      34              : #define __H__UG__LIB_ALGEBRA__POWER_METHOD_H__
      35              : 
      36              : #include <vector>
      37              : #include <string>
      38              : #include "additional_math.h"
      39              : 
      40              : #include "lib_algebra/operator/interface/linear_operator.h"
      41              : #include "lib_algebra/operator/interface/linear_operator_inverse.h"
      42              : #include "lib_algebra/operator/interface/preconditioner.h"
      43              : #include "lib_algebra/operator/interface/matrix_operator.h"
      44              : 
      45              : #include "lib_algebra/algebra_common/vector_util.h"
      46              : #include  "common/profiler/profiler.h"
      47              : 
      48              : 
      49              : namespace ug{
      50              : 
      51              : 
      52              : /**
      53              :  * Power Method Eigensolver
      54              :  *
      55              :  * The Power Method solves generalized eigenvalue problems of the form A v = lambda B v
      56              :  * calculating the largest/smallest (in terms of abs(lambda)) eigenvalues of the problem
      57              :  * for sparse matrices A and B which e.g. emerge from FE or FV discretizations.
      58              :  */
      59              : template<typename TAlgebra>
      60              : class PowerMethod
      61              : {
      62              :         public:
      63              :         //      Algebra type
      64              :                 typedef TAlgebra algebra_type;
      65              : 
      66              :         //      Vector type
      67              :                 typedef typename TAlgebra::vector_type vector_type;
      68              :                 typedef typename TAlgebra::matrix_type matrix_type;
      69              :                 typedef typename vector_type::value_type vector_value_type;
      70              : 
      71              :         private:
      72              :         //      Stiffness matrix
      73              :                 SmartPtr<ILinearOperator<vector_type> > m_spLinOpA;
      74              : 
      75              :         //      Mass matrix
      76              :                 typedef typename IPreconditioner<TAlgebra>::matrix_operator_type matrix_operator_type;
      77              :                 SmartPtr<ILinearOperator<vector_type> > m_spLinOpB;
      78              :                 SmartPtr<matrix_operator_type> m_spMatOpA;
      79              :                 SmartPtr<matrix_operator_type> m_spMatOpB;
      80              :                 //matrix_operator_type *m_pB;
      81              : 
      82              :         //      Eigenvector and -value
      83              :                 SmartPtr<vector_type> m_spEigenvector;
      84              :                 SmartPtr<vector_type> m_spEigenvectorOld;
      85              :                 double m_dMaxEigenvalue;
      86              :                 double m_dMinEigenvalue;
      87              : 
      88              :         //      Solver
      89              :                 SmartPtr<ILinearOperatorInverse<vector_type> > m_spSolver;
      90              : 
      91              :         //      Precision
      92              :                 size_t m_maxIterations;
      93              :                 double m_dPrecision;
      94              : 
      95              :         //      Residual
      96              :                 SmartPtr<vector_type> m_spResidual;
      97              : 
      98              :         //      Dirichlet node indexing
      99              :                 std::vector<bool> m_vbDirichlet;
     100              :                 int m_numDirichletRows;
     101              : 
     102              :         public:
     103              :         //      Number of iterations
     104              :                 size_t m_iteration;
     105              : 
     106            0 :                 PowerMethod()
     107              :                 {
     108              :                         UG_LOG("Initializing PowerMethod." << std::endl);
     109            0 :                         m_spLinOpA = SPNULL;
     110            0 :                         m_spLinOpB = SPNULL;
     111            0 :                         m_spMatOpA = SPNULL;
     112            0 :                         m_spMatOpB = SPNULL;
     113            0 :                         m_maxIterations = 1000;
     114            0 :                         m_dPrecision = 1e-8;
     115            0 :                         m_iteration = 0;
     116            0 :                         m_dMaxEigenvalue = 0.0;
     117            0 :                         m_dMinEigenvalue = 0.0;
     118            0 :                         m_numDirichletRows = 0;
     119            0 :                 }
     120              : 
     121            0 :                 void set_solver(SmartPtr<ILinearOperatorInverse<vector_type> > solver)
     122              :                 {
     123            0 :                         m_spSolver = solver;
     124            0 :                 }
     125              : 
     126            0 :                 void set_linear_operator_A(SmartPtr<ILinearOperator<vector_type> > loA)
     127              :                 {
     128            0 :                         m_spLinOpA = loA;
     129              : 
     130              :                 //      get dirichlet nodes
     131            0 :                         m_spMatOpA = m_spLinOpA.template cast_dynamic<MatrixOperator<matrix_type, vector_type> >();
     132            0 :                         matrix_type& A = m_spMatOpA->get_matrix();
     133            0 :                         m_vbDirichlet.resize(A.num_rows());
     134              : 
     135            0 :                         for(size_t i=0; i<A.num_rows(); i++)
     136              :                         {
     137            0 :                                 m_vbDirichlet[i] = A.is_isolated(i);
     138              : 
     139            0 :                                 if(A.is_isolated(i) == 0)
     140            0 :                                         m_numDirichletRows++;
     141              :                         }
     142            0 :                 }
     143              : 
     144            0 :                 void set_linear_operator_B(SmartPtr<ILinearOperator<vector_type> > loB)
     145              :                 {
     146            0 :                         m_spLinOpB = loB;
     147            0 :                         m_spMatOpB = m_spLinOpB.template cast_dynamic<MatrixOperator<matrix_type, vector_type> >();
     148            0 :                 }
     149              : 
     150            0 :                 void set_start_vector(SmartPtr<vector_type> vec)
     151              :                 {
     152            0 :                         m_spEigenvector = vec;
     153            0 :                 }
     154              : 
     155            0 :                 void set_max_iterations(size_t maxIterations)
     156              :                 {
     157            0 :                         m_maxIterations = maxIterations;
     158            0 :                 }
     159              : 
     160            0 :                 void set_precision(double precision)
     161              :                 {
     162            0 :                         m_dPrecision = precision;
     163            0 :                 }
     164              : 
     165            0 :                 int calculate_max_eigenvalue()
     166              :                 {
     167              :                         PROFILE_FUNC_GROUP("PowerMethod");
     168              : 
     169            0 :                         UG_COND_THROW(m_spSolver == SPNULL && m_spLinOpB != SPNULL, "PowerMethod::calculate_max_eigenvalue(): Solver not set, please specify.");
     170            0 :                         if(m_spLinOpB != SPNULL)
     171            0 :                                 m_spSolver->init(m_spLinOpB);
     172              : 
     173            0 :                         m_spResidual = create_approximation_vector();
     174              : 
     175            0 :                         for(m_iteration = 0; m_iteration < m_maxIterations; ++m_iteration)
     176              :                         {
     177            0 :                                 m_spEigenvectorOld = m_spEigenvector->clone();
     178              : 
     179              :                         //      residual = A v
     180            0 :                                 UG_COND_THROW(m_spLinOpA == SPNULL, "PowerMethod::calculate_max_eigenvalue(): Linear operator A not set, please specify.");
     181            0 :                                 m_spLinOpA->apply(*m_spResidual, *m_spEigenvector);
     182              : 
     183              :                         //      v = B^-1 A v
     184            0 :                                 if(m_spLinOpB != SPNULL)
     185            0 :                                         m_spSolver->apply(*m_spEigenvector, *m_spResidual);
     186              :                         //      in case B is not set: v = A v
     187              :                                 else
     188            0 :                                         m_spEigenvector = m_spResidual->clone();
     189              : 
     190              :                         //      reset Dirichlet rows to 0
     191            0 :                                 for(size_t i = 0; i < m_spEigenvector->size(); i++)
     192              :                                 {
     193            0 :                                         if(m_vbDirichlet[i])
     194              :                                         {
     195            0 :                                                 (*m_spEigenvector)[i] = 0.0;
     196              :                                         }
     197              :                                 }
     198              : 
     199              :                         //      v = v / ||v||_B
     200            0 :                                 normalize_approximations();
     201              : 
     202              :                         //      in case B is not set, restore storage type of m_spEigenvector to PST_CONSISTENT
     203              :                         //      changed by norm calculation in normalize_approximations()
     204              :                                 if(m_spLinOpB == SPNULL)
     205              :                                 {
     206              :                                         #ifdef UG_PARALLEL
     207              :                                                         m_spEigenvector->change_storage_type(PST_CONSISTENT);
     208              :                                         #endif
     209              :                                 }
     210              : 
     211              :                         //      residual = v - v_old
     212            0 :                                 VecScaleAdd(*m_spResidual, 1.0, *m_spEigenvectorOld, -1.0, *m_spEigenvector);
     213              : 
     214            0 :                                 if(m_spResidual->norm() <= m_dPrecision)
     215              :                                 {
     216            0 :                                         UG_LOG("PowerMethod::calculate_max_eigenvalue() converged after " << m_iteration << " iterations." << std::endl);
     217              :                                         break;
     218              :                                 }
     219              : 
     220            0 :                                 if(m_iteration == m_maxIterations-1)
     221            0 :                                         UG_LOG("PowerMethod::calculate_max_eigenvalue() reached precision of " << m_spResidual->norm() << " after " << m_maxIterations << " iterations." << std::endl);
     222              :                         }
     223              : 
     224              :                 //      lambda = <v,Av>
     225            0 :                         m_spLinOpA->apply(*m_spResidual, *m_spEigenvector);
     226            0 :                         m_dMaxEigenvalue = m_spEigenvector->dotprod(*m_spResidual);
     227              : 
     228            0 :                         return true;
     229              :                 }
     230              : 
     231            0 :                 int calculate_min_eigenvalue()
     232              :                 {
     233              :                         PROFILE_FUNC_GROUP("PowerMethod");
     234              : 
     235            0 :                         UG_COND_THROW(m_spLinOpA == SPNULL, "PowerMethod::calculate_min_eigenvalue(): Linear operator A not set, please specify.");
     236            0 :                         UG_COND_THROW(m_spSolver == SPNULL, "PowerMethod::calculate_min_eigenvalue(): Solver not set, please specify.");
     237              : 
     238            0 :                         m_spResidual = create_approximation_vector();
     239              : 
     240            0 :                         m_spSolver->init(m_spLinOpA);
     241              : 
     242            0 :                         for(m_iteration = 0; m_iteration < m_maxIterations; ++m_iteration)
     243              :                         {
     244            0 :                                 m_spEigenvectorOld = m_spEigenvector->clone();
     245              : 
     246              :                         //      residual = B v
     247            0 :                                 if(m_spLinOpB != SPNULL)
     248            0 :                                         m_spLinOpB->apply(*m_spResidual, *m_spEigenvector);
     249              :                         //      in case B is not set
     250              :                                 else
     251              :                                 {
     252            0 :                                         m_spResidual = m_spEigenvector->clone();
     253              : 
     254              :                                         #ifdef UG_PARALLEL
     255              :                                                 m_spResidual->change_storage_type(PST_ADDITIVE);
     256              :                                         #endif
     257              :                                 }
     258              : 
     259              :                         //      v = A^-1 B v or v = A^-1 v
     260            0 :                                 m_spSolver->apply(*m_spEigenvector, *m_spResidual);
     261              : 
     262              :                         //      reset Dirichlet rows to 0
     263            0 :                                 for(size_t i = 0; i < m_spEigenvector->size(); i++)
     264              :                                 {
     265            0 :                                         if(m_vbDirichlet[i])
     266              :                                         {
     267            0 :                                                 (*m_spEigenvector)[i] = 0.0;
     268              :                                         }
     269              :                                 }
     270              : 
     271              :                         //      v = v / ||v||_B
     272            0 :                                 normalize_approximations();
     273              : 
     274              :                         //      in case B is not set, restore storage type of m_spEigenvector to PST_CONSISTENT
     275              :                         //      changed by norm calculation in normalize_approximations()
     276              :                                 if(m_spLinOpB == SPNULL)
     277              :                                 {
     278              :                                         #ifdef UG_PARALLEL
     279              :                                                         m_spEigenvector->change_storage_type(PST_CONSISTENT);
     280              :                                         #endif
     281              :                                 }
     282              : 
     283              :                         //      residual = v - v_old
     284            0 :                                 VecScaleAdd(*m_spResidual, 1.0, *m_spEigenvectorOld, -1.0, *m_spEigenvector);
     285              : 
     286            0 :                                 if(m_spResidual->norm() <= m_dPrecision)
     287              :                                 {
     288            0 :                                         UG_LOG("PowerMethod::calculate_min_eigenvalue() converged after " << m_iteration << " iterations." << std::endl);
     289              :                                         break;
     290              :                                 }
     291              : 
     292            0 :                                 if(m_iteration == m_maxIterations-1)
     293            0 :                                         UG_LOG("PowerMethod::calculate_min_eigenvalue() reached precision of " << m_spResidual->norm() << " after " << m_maxIterations << " iterations." << std::endl);
     294              :                         }
     295              : 
     296              :                 //      lambda = <v,Av>
     297            0 :                         m_spLinOpA->apply(*m_spResidual, *m_spEigenvector);
     298            0 :                         m_dMinEigenvalue = m_spEigenvector->dotprod(*m_spResidual);
     299              : 
     300            0 :                         return true;
     301              :                 }
     302              : 
     303            0 :                 double get_max_eigenvalue()
     304              :                 {
     305            0 :                         return m_dMaxEigenvalue;
     306              :                 }
     307              : 
     308            0 :                 double get_min_eigenvalue()
     309              :                 {
     310            0 :                         return m_dMinEigenvalue;
     311              :                 }
     312              : 
     313            0 :                 size_t get_iterations()
     314              :                 {
     315            0 :                         return m_iteration;
     316              :                 }
     317              : 
     318            0 :                 void print_matrix_A()
     319              :                 {
     320            0 :                         PrintMatrix(m_spMatOpA->get_matrix(), "A");
     321            0 :                 }
     322              : 
     323            0 :                 void print_matrix_B()
     324              :                 {
     325            0 :                         PrintMatrix(m_spMatOpB->get_matrix(), "B");
     326            0 :                 }
     327              : 
     328            0 :                 void print_eigenvector()
     329              :                 {
     330            0 :                         m_spEigenvector->print();
     331            0 :                 }
     332              : 
     333              :         private:
     334              : 
     335            0 :                 SmartPtr<vector_type> create_approximation_vector()
     336              :                 {
     337            0 :                         SmartPtr<vector_type> t = m_spEigenvector->clone_without_values();
     338              :                         t->set(0.0);
     339            0 :                         return t;
     340              :                 }
     341              : 
     342            0 :                 double B_norm(vector_type &x)
     343              :                 {
     344            0 :                         if(m_spMatOpB != SPNULL)
     345            0 :                                 return EnergyNorm(x, *m_spMatOpB);
     346              :                         else
     347            0 :                                 return x.norm();
     348              :                 }
     349              : 
     350            0 :                 void normalize_approximations()
     351              :                 {
     352            0 :                         *m_spEigenvector *= 1/ B_norm(*m_spEigenvector);
     353            0 :                 }
     354              : };
     355              : 
     356              : } // namespace ug
     357              : 
     358              : 
     359              : #endif // __H__UG__LIB_ALGEBRA__POWER_METHOD_H__
        

Generated by: LCOV version 2.0-1