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

            Line data    Source code
       1              : /*
       2              :  * Copyright (c) 2010-2015:  G-CSC, Goethe University Frankfurt
       3              :  * Author: Andreas Vogel
       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_DISC__OPERATOR__LINEAR_SOLVER__CG__
      34              : #define __H__UG__LIB_DISC__OPERATOR__LINEAR_SOLVER__CG__
      35              : 
      36              : #include <iostream>
      37              : #include <string>
      38              : 
      39              : #include "lib_algebra/operator/interface/operator.h"
      40              : #include "lib_algebra/operator/interface/preconditioned_linear_operator_inverse.h"
      41              : #include "common/profiler/profiler.h"
      42              : #include "lib_algebra/operator/interface/pprocess.h"
      43              : #ifdef UG_PARALLEL
      44              :         #include "lib_algebra/parallelization/parallelization.h"
      45              : #endif
      46              : 
      47              : namespace ug{
      48              : 
      49              : ///     the CG method as a solver for linear operators
      50              : /**
      51              :  * This class implements the CG - method for the solution of linear operator
      52              :  * problems like A*x = b, where the solution x = A^{-1} b is computed.
      53              :  *
      54              :  * For detailed description of the algorithm, please refer to:
      55              :  *
      56              :  * - Barrett, Berry, Chan, Demmel, Donatom Dongarra, Eijkhout, Pozo, Romine,
      57              :  *       Van der Vorst, "Templates for the Solution of Linear Systems: Building
      58              :  *       Blocks for Iterative Methods", p.13, Fig, 2.5
      59              :  *
      60              :  * - Saad, "Iterative Methods For Sparse Linear Systems", p277, Alg. 9.1
      61              :  *
      62              :  * \tparam      TVector         vector type
      63              :  */
      64              : template <typename TVector>
      65              : class CG
      66              :         : public IPreconditionedLinearOperatorInverse<TVector>
      67              : {
      68              :         public:
      69              :         ///     Vector type
      70              :                 typedef TVector vector_type;
      71              : 
      72              :         ///     Base type
      73              :                 typedef IPreconditionedLinearOperatorInverse<vector_type> base_type;
      74              : 
      75              :         protected:
      76              :                 using base_type::convergence_check;
      77              :                 using base_type::linear_operator;
      78              :                 using base_type::preconditioner;
      79              :                 using base_type::write_debug;
      80              : 
      81              :         public:
      82              :         ///     constructors
      83            0 :                 CG() : base_type() {}
      84              : 
      85            0 :                 CG(SmartPtr<ILinearIterator<vector_type,vector_type> > spPrecond)
      86            0 :                         : base_type ( spPrecond )  {}
      87              : 
      88            0 :                 CG(SmartPtr<ILinearIterator<vector_type,vector_type> > spPrecond, SmartPtr<IConvergenceCheck<vector_type> > spConvCheck)
      89            0 :                         : base_type ( spPrecond, spConvCheck)  {}
      90              : 
      91              :         ///     name of solver
      92            0 :                 virtual const char* name() const {return "CG";}
      93              : 
      94              :         ///     returns if parallel solving is supported
      95            0 :                 virtual bool supports_parallel() const
      96              :                 {
      97            0 :                         if(preconditioner().valid())
      98            0 :                                 return preconditioner()->supports_parallel();
      99              :                         return true;
     100              :                 }
     101              : 
     102              :         ///     Solve J(u)*x = b, such that x = J(u)^{-1} b
     103            0 :                 virtual bool apply_return_defect(vector_type& x, vector_type& b)
     104              :                 {
     105              :                         PROFILE_BEGIN_GROUP(CG_apply_return_defect, "CG algebra");
     106              :                 //      check parallel storage types
     107              :                         #ifdef UG_PARALLEL
     108              :                         if(!b.has_storage_type(PST_ADDITIVE) || !x.has_storage_type(PST_CONSISTENT))
     109              :                                 UG_THROW("CG::apply_return_defect:"
     110              :                                                                 "Inadequate storage format of Vectors.");
     111              :                         #endif
     112              : 
     113              :                 //      rename r as b (for convenience)
     114              :                         vector_type& r = b;
     115              : 
     116              :                 //      Build defect:  r := b - J(u)*x
     117            0 :                         linear_operator()->apply_sub(r, x);
     118              : 
     119              :                 //      create help vector (h will be consistent r)
     120            0 :                         SmartPtr<vector_type> spQ = r.clone_without_values(); vector_type& q = *spQ;
     121            0 :                         SmartPtr<vector_type> spZ = x.clone_without_values(); vector_type& z = *spZ;
     122            0 :                         SmartPtr<vector_type> spP = x.clone_without_values(); vector_type& p = *spP;
     123              : 
     124            0 :                         write_debugXR(x, r, convergence_check()->step());
     125              : 
     126              :                 //      Preconditioning
     127            0 :                         if(preconditioner().valid())
     128              :                         {
     129            0 :                                 enter_precond_debug_section(convergence_check()->step());
     130              :                                 // apply z = M^-1 * s
     131            0 :                                 if(!preconditioner()->apply(z, r))
     132              :                                 {
     133              :                                         UG_LOG("ERROR in 'CG::apply_return_defect': "
     134              :                                                         "Cannot apply preconditioner. Aborting.\n");
     135            0 :                                         this->leave_vector_debug_writer_section();
     136            0 :                                         return false;
     137              :                                 }
     138            0 :                                 this->leave_vector_debug_writer_section();
     139              :                         }
     140            0 :                         else z = r;
     141              :                         
     142              :                 //      make z consistent
     143              :                         #ifdef UG_PARALLEL
     144              :                         if(!z.change_storage_type(PST_CONSISTENT))
     145              :                                 UG_THROW("CG::apply_return_defect: "
     146              :                                                                 "Cannot convert z to consistent vector.");
     147              :                         #endif
     148              : 
     149              :                 //      post-process the correction
     150            0 :                         m_corr_post_process.apply (z);
     151              : 
     152              :                 //      compute start defect
     153            0 :                         prepare_conv_check();
     154            0 :                         convergence_check()->start(r);
     155              : 
     156              :                 //      start search direction
     157            0 :                         p = z;
     158              : 
     159              :                 //      start rho
     160              :                         number rhoOld = VecProd(z, r), rho;
     161              : 
     162              :                 //      Iteration loop
     163            0 :                         while(!convergence_check()->iteration_ended())
     164              :                         {
     165              :                         //      Build q = A*p (q is additive afterwards)
     166            0 :                                 linear_operator()->apply(q, p);
     167              : 
     168              :                         //      lambda = (q,p)
     169              :                                 number lambda = VecProd(q, p);
     170              : 
     171              :                         //      check lambda
     172            0 :                                 if(lambda == 0.0)
     173              :                                 {
     174            0 :                                     if (p.size())
     175              :                                     {
     176              :                                         UG_LOG("ERROR in 'CG::apply_return_defect': lambda=" <<
     177              :                                             lambda<< " is not admitted. Aborting solver.\n");
     178              :                                         return false;
     179              :                                     }
     180              :                                     // in cases where a proc has no geometry, we do not want to fail here
     181              :                                     // so we set lambda = 1, this is not harmful
     182              :                                     else
     183              :                                         lambda = 1.0;
     184              :                                 }
     185              : 
     186              :                         //      alpha = rho / (q,p)
     187            0 :                                 const number alpha = rhoOld/lambda;
     188              : 
     189              :                         //      Update x := x + alpha*p
     190            0 :                                 VecScaleAdd(x, 1.0, x, alpha, p);
     191              : 
     192              :                         //      Update r := r - alpha*t
     193            0 :                                 VecScaleAdd(r, 1.0, r, -alpha, q);
     194              : 
     195            0 :                                 write_debugXR(x, r, convergence_check()->step());
     196              : 
     197              :                         //      Check convergence
     198            0 :                                 convergence_check()->update(r);
     199            0 :                                 if(convergence_check()->iteration_ended()) break;
     200              : 
     201              :                         //      Preconditioning
     202            0 :                                 if(preconditioner().valid())
     203              :                                 {
     204            0 :                                         enter_precond_debug_section(convergence_check()->step());
     205              :                                 //      apply z = M^-1 * r
     206            0 :                                         if(!preconditioner()->apply(z, r))
     207              :                                         {
     208              :                                                 UG_LOG("ERROR in 'CG::apply_return_defect': "
     209              :                                                                 "Cannot apply preconditioner. Aborting.\n");
     210            0 :                                                 this->leave_vector_debug_writer_section();
     211            0 :                                                 return false;
     212              :                                         }
     213            0 :                                         this->leave_vector_debug_writer_section();
     214              :                                 }
     215            0 :                                 else z = r;
     216              :                                 
     217              :                                 #ifdef UG_PARALLEL
     218              :                         //      make z consistent
     219              :                                 if(!z.change_storage_type(PST_CONSISTENT))
     220              :                                         UG_THROW("CG::apply_return_defect': "
     221              :                                                                         "Cannot convert z to consistent vector.");
     222              :                                 #endif
     223              : 
     224              :                         //      post-process the correction
     225            0 :                                 m_corr_post_process.apply (z);
     226              : 
     227              :                         //      new rho = (z,r)
     228              :                                 rho = VecProd(z, r);
     229              : 
     230              :                         //      new beta = rho / rhoOld
     231            0 :                                 const number beta = rho/rhoOld;
     232              : 
     233              :                         //      new direction p := beta * p + z
     234            0 :                                 VecScaleAdd(p, beta, p, 1.0, z);
     235              : 
     236              :                         //      remember old rho
     237              :                                 rhoOld = rho;
     238              :                         }
     239              : 
     240              :                 //      post output
     241            0 :                         return convergence_check()->post();
     242              :                 }
     243              :                 
     244              :         ///     adds a post-process for the iterates
     245            0 :                 void add_postprocess_corr (SmartPtr<IPProcessVector<vector_type> > p)
     246              :                 {
     247            0 :                         m_corr_post_process.add (p);
     248            0 :                 }
     249              : 
     250              :         ///     removes a post-process for the iterates
     251            0 :                 void remove_postprocess_corr (SmartPtr<IPProcessVector<vector_type> > p)
     252              :                 {
     253            0 :                         m_corr_post_process.remove (p);
     254            0 :                 }
     255              : 
     256              :         protected:
     257              :         ///     adjust output of convergence check
     258            0 :                 void prepare_conv_check()
     259              :                 {
     260              :                 //      set iteration symbol and name
     261            0 :                         convergence_check()->set_name(name());
     262            0 :                         convergence_check()->set_symbol('%');
     263              : 
     264              :                 //      set preconditioner string
     265              :                         std::string s;
     266            0 :                         if(preconditioner().valid())
     267            0 :                           s = std::string(" (Precond: ") + preconditioner()->name() + ")";
     268              :                         else
     269              :                                 s = " (No Preconditioner) ";
     270            0 :                         convergence_check()->set_info(s);
     271            0 :                 }
     272              : 
     273              :         /// debugger output: solution and residual
     274            0 :                 void write_debugXR(vector_type &x, vector_type &r, int loopCnt)
     275              :                 {
     276            0 :                         if(!this->vector_debug_writer_valid()) return;
     277              :                         char ext[20]; snprintf(ext, 20, "_iter%03d", loopCnt);
     278            0 :                         write_debug(r, std::string("CG_Residual") + ext + ".vec");
     279            0 :                         write_debug(x, std::string("CG_Solution") + ext + ".vec");
     280              :                 }
     281              :                 
     282              :         /// debugger section for the preconditioner
     283            0 :                 void enter_precond_debug_section(int loopCnt)
     284              :                 {
     285            0 :                         if(!this->vector_debug_writer_valid()) return;
     286              :                         char ext[20]; snprintf(ext, 20, "_iter%03d", loopCnt);
     287            0 :                         this->enter_vector_debug_writer_section(std::string("CG_Precond_") + ext);
     288              :                 }
     289              : 
     290              :         protected:
     291              :                 number VecProd(vector_type& a, vector_type& b)
     292              :                 {
     293              :                         return a.dotprod(b);
     294              :                 }
     295              :         
     296              :         protected:
     297              :         ///     postprocessor for the correction in the iterations
     298              :                 /**
     299              :                  * These postprocess operations are applied to the preconditioned
     300              :                  * defect before the orthogonalization. The goal is to prevent the
     301              :                  * useless kernel parts to prevail in the (floating point) arithmetics.
     302              :                  */
     303              :                 PProcessChain<vector_type> m_corr_post_process;
     304              : };
     305              : 
     306              : } // end namespace ug
     307              : 
     308              : #endif /* __H__UG__LIB_DISC__OPERATOR__LINEAR_SOLVER__CG__ */
        

Generated by: LCOV version 2.0-1