00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifndef SOFA_COMPONENT_LINEARSOLVER_CGLINEARSOLVER_H
00026 #define SOFA_COMPONENT_LINEARSOLVER_CGLINEARSOLVER_H
00027
00028 #include <sofa/core/componentmodel/behavior/LinearSolver.h>
00029 #include <sofa/simulation/common/MatrixLinearSolver.h>
00030 #include <sofa/simulation/common/MechanicalVisitor.h>
00031 #include <math.h>
00032
00033 namespace sofa
00034 {
00035
00036 namespace component
00037 {
00038
00039 namespace linearsolver
00040 {
00041
00043 template<class TMatrix, class TVector>
00044 class CGLinearSolver : public sofa::simulation::MatrixLinearSolver<TMatrix,TVector>, public virtual sofa::core::objectmodel::BaseObject
00045 {
00046 public:
00047 typedef TMatrix Matrix;
00048 typedef TVector Vector;
00049 Data<unsigned> f_maxIter;
00050 Data<double> f_tolerance;
00051 Data<double> f_smallDenominatorThreshold;
00052 Data<bool> f_verbose;
00053
00054 CGLinearSolver()
00055 : f_maxIter( initData(&f_maxIter,(unsigned)25,"iterations","maximum number of iterations of the Conjugate Gradient solution") )
00056 , f_tolerance( initData(&f_tolerance,1e-5,"tolerance","desired precision of the Conjugate Gradient Solution (ratio of current residual norm over initial residual norm)") )
00057 , f_smallDenominatorThreshold( initData(&f_smallDenominatorThreshold,1e-5,"threshold","minimum value of the denominator in the conjugate Gradient solution") )
00058 , f_verbose( initData(&f_verbose,false,"verbose","Dump system state at each iteration") )
00059 {
00060 }
00061 protected:
00064 inline void cgstep_beta(Vector& p, Vector& r, double beta);
00067 inline void cgstep_alpha(Vector& x, Vector& r, Vector& p, Vector& q, double alpha);
00068
00069 public:
00071 void solve (Matrix& M, Vector& x, Vector& b)
00072 {
00073 using std::cerr;
00074 using std::endl;
00075
00076 Vector& p = *this->createVector();
00077 Vector& q = *this->createVector();
00078 Vector& r = *this->createVector();
00079
00080 const bool printLog = f_printLog.getValue();
00081 const bool verbose = f_verbose.getValue();
00082
00083
00084 double rho, rho_1=0, alpha, beta;
00085
00086 if( verbose )
00087 cerr<<"CGLinearSolver, b = "<< b <<endl;
00088
00089 x.clear();
00090 r = b;
00091
00092 double normb2 = b.dot(b);
00093 double normb = sqrt(normb2);
00094
00095 unsigned nb_iter;
00096 const char* endcond = "iterations";
00097 for( nb_iter=1; nb_iter<=f_maxIter.getValue(); nb_iter++ )
00098 {
00099
00100
00101
00102
00103
00104 rho = (nb_iter==1) ? normb2 : r.dot(r);
00105
00106 if (nb_iter>1)
00107 {
00108 double normr = sqrt(rho);
00109 if (normr/normb <= f_tolerance.getValue())
00110 {
00111 endcond = "tolerance";
00112 break;
00113 }
00114 }
00115
00116 if( nb_iter==1 )
00117 p = r;
00118 else
00119 {
00120 beta = rho / rho_1;
00121
00122 cgstep_beta(p,r,beta);
00123 }
00124
00125 if( verbose )
00126 {
00127 cerr<<"p : "<<p<<endl;
00128 }
00129
00130
00131 q = M*p;
00132
00133 if( verbose )
00134 {
00135 cerr<<"q = M p : "<<q<<endl;
00136 }
00137
00138 double den = p.dot(q);
00139
00140
00141 if( fabs(den)<f_smallDenominatorThreshold.getValue() )
00142 {
00143 endcond = "threshold";
00144 if( verbose )
00145 {
00146 cerr<<"CGLinearSolver, den = "<<den<<", smallDenominatorThreshold = "<<f_smallDenominatorThreshold.getValue()<<endl;
00147 }
00148 break;
00149 }
00150 alpha = rho/den;
00151
00152
00153 cgstep_alpha(x,r,p,q,alpha);
00154 if( verbose ){
00155 cerr<<"den = "<<den<<", alpha = "<<alpha<<endl;
00156 cerr<<"x : "<<x<<endl;
00157 cerr<<"r : "<<r<<endl;
00158 }
00159
00160 rho_1 = rho;
00161 }
00162
00163 if( printLog )
00164 {
00165 cerr<<"CGLinearSolver::solve, nbiter = "<<nb_iter<<" stop because of "<<endcond<<endl;
00166 }
00167 if( verbose )
00168 {
00169 cerr<<"CGLinearSolver::solve, solution = "<<x<<endl;
00170 }
00171 this->deleteVector(&p);
00172 this->deleteVector(&q);
00173 this->deleteVector(&r);
00174 }
00175 };
00176
00177 template<class TMatrix, class TVector>
00178 inline void CGLinearSolver<TMatrix,TVector>::cgstep_beta(Vector& p, Vector& r, double beta)
00179 {
00180 p *= beta;
00181 p += r;
00182 }
00183
00184 template<class TMatrix, class TVector>
00185 inline void CGLinearSolver<TMatrix,TVector>::cgstep_alpha(Vector& x, Vector& r, Vector& p, Vector& q, double alpha)
00186 {
00187 x.peq(p,alpha);
00188 r.peq(q,-alpha);
00189 }
00190
00191 template<>
00192 inline void CGLinearSolver<simulation::GraphScatteredMatrix,simulation::GraphScatteredVector>::cgstep_beta(Vector& p, Vector& r, double beta)
00193 {
00194 this->v_op(p,r,p,beta);
00195 }
00196
00197 template<>
00198 inline void CGLinearSolver<simulation::GraphScatteredMatrix,simulation::GraphScatteredVector>::cgstep_alpha(Vector& x, Vector& r, Vector& p, Vector& q, double alpha)
00199 {
00200 #if 1 //SOFA_NO_VMULTIOP // unoptimized version
00201 x.peq(p,alpha);
00202 r.peq(q,-alpha);
00203 #else // single-operation optimization
00204 simulation::tree::MechanicalVMultiOpVisitor vmop;
00205 vmop.ops.resize(2);
00206 vmop.ops[0].first = (VecId)x;
00207 vmop.ops[0].second.push_back(std::make_pair((VecId)x,1.0));
00208 vmop.ops[0].second.push_back(std::make_pair((VecId)p,alpha));
00209 vmop.ops[1].first = (VecId)r;
00210 vmop.ops[1].second.push_back(std::make_pair((VecId)r,1.0));
00211 vmop.ops[1].second.push_back(std::make_pair((VecId)q,-alpha));
00212 vmop.execute(this->getContext());
00213 #endif
00214 }
00215
00216 }
00217
00218 }
00219
00220 }
00221
00222 #endif