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_BTDLINEARSOLVER_H
00026 #define SOFA_COMPONENT_LINEARSOLVER_BTDLINEARSOLVER_H
00027
00028 #include <sofa/core/componentmodel/behavior/LinearSolver.h>
00029 #include <sofa/simulation/common/MatrixLinearSolver.h>
00030 #include <sofa/component/linearsolver/SparseMatrix.h>
00031 #include <sofa/component/linearsolver/FullMatrix.h>
00032 #include <math.h>
00033
00034 namespace sofa
00035 {
00036
00037 namespace component
00038 {
00039
00040 namespace linearsolver
00041 {
00042
00050 template<class Matrix, class Vector>
00051 class BTDLinearSolver : public sofa::simulation::MatrixLinearSolver<Matrix,Vector>, public virtual sofa::core::objectmodel::BaseObject
00052 {
00053 public:
00054 Data<bool> f_verbose;
00055 Data<bool> problem;
00056
00057 typedef typename Matrix::SubMatrixType SubMatrix;
00058
00059
00060 helper::vector<SubMatrix> alpha_inv;
00061 helper::vector<SubMatrix> lambda;
00062 helper::vector<SubMatrix> B;
00063 typename Matrix::InvMatrixType Minv;
00064 helper::vector<int> nBlockComputedMinv;
00065 Vector Y;
00066
00067 Data<int> f_blockSize;
00068
00069 BTDLinearSolver()
00070 : f_verbose( initData(&f_verbose,false,"verbose","Dump system state at each iteration") )
00071 , problem(initData(&problem, false,"showProblem", "Suppress the computation of all elements of the inverse") )
00072 , f_blockSize( initData(&f_blockSize,6,"blockSize","dimension of the blocks in the matrix") )
00073 {
00074 }
00075
00115 template<class T>
00116 void invert(SubMatrix& Inv, const T& m)
00117 {
00118 SubMatrix M;
00119 M = m;
00120
00121 unsigned int i0 = 0;
00122 const unsigned int n = M.Nrows();
00123 Inv.resize(n,n);
00124 while (i0 < n)
00125 {
00126 unsigned int j0 = i0+1;
00127 double eps = M.element(i0,i0)*1.0e-10;
00128 while (j0 < n)
00129 if (fabs(M.element(i0,j0)) > eps) break;
00130 else ++j0;
00131 if (j0 == n)
00132 {
00133 Inv.set(i0,i0,1.0/M.element(i0,i0));
00134 ++i0;
00135 }
00136 else break;
00137 }
00138 if (i0 == 0)
00139 Inv = M.i();
00140 else if (i0 < n)
00141 Inv.sub(i0,i0,n-i0,n-i0) = M.sub(i0,i0,n-i0,n-i0).i();
00142
00143
00144 }
00145 void invert(Matrix& M)
00146 {
00147 const bool verbose = f_verbose.getValue() || f_printLog.getValue();
00148
00149 if( verbose )
00150 {
00151 std::cerr<<"BTDLinearSolver, M = "<< M <<std::endl;
00152 }
00153
00154 const int bsize = f_blockSize.getValue();
00155 const int nb = M.rowSize() / bsize;
00156 if (nb == 0) return;
00157
00158 alpha_inv.resize(nb);
00159 lambda.resize(nb-1);
00160 B.resize(nb);
00161
00162 SubMatrix A, C;
00163
00164 M.getSubMatrix(0*bsize,0*bsize,bsize,bsize,A);
00165
00166 M.getSubMatrix(0*bsize,1*bsize,bsize,bsize,C);
00167
00168
00169 invert(alpha_inv[0],A);
00170 if (verbose) std::cout << "alpha_inv[0] = " << alpha_inv[0] << std::endl;
00171 lambda[0] = alpha_inv[0]*C;
00172 if (verbose) std::cout << "lambda[0] = " << lambda[0] << std::endl;
00173
00174 for (int i=1;i<nb;++i)
00175 {
00176 M.getSubMatrix((i )*bsize,(i )*bsize,bsize,bsize,A);
00177
00178 M.getSubMatrix((i )*bsize,(i-1)*bsize,bsize,bsize,B[i]);
00179
00180
00181 invert(alpha_inv[i], (A - B[i]*lambda[i-1]));
00182 if (verbose) std::cout << "alpha_inv["<<i<<"] = " << alpha_inv[i] << std::endl;
00183
00184 if (i<nb-1)
00185 {
00186 M.getSubMatrix((i )*bsize,(i+1)*bsize,bsize,bsize,C);
00187
00188 lambda[i] = alpha_inv[i]*C;
00189 if (verbose) std::cout << "lambda["<<i<<"] = " << lambda[i] << std::endl;
00190
00191 }
00192 }
00193 nBlockComputedMinv.resize(nb);
00194 for (int i=0;i<nb;++i)
00195 nBlockComputedMinv[i] = 0;
00196 Minv.resize(nb*bsize,nb*bsize);
00197 Minv.setSubMatrix((nb-1)*bsize,(nb-1)*bsize,bsize,bsize,alpha_inv[nb-1]);
00198 nBlockComputedMinv[nb-1] = 1;
00199
00200 }
00201
00208
00209 void computeMinvBlock(int i, int j)
00210 {
00211 const int bsize = f_blockSize.getValue();
00212 if (i < j)
00213 {
00214 int t = i; i = j; j = t;
00215 }
00216 if (nBlockComputedMinv[i] > i-j) return;
00217 int i0 = i;
00218 while (nBlockComputedMinv[i0]==0)
00219 ++i0;
00220 while (i0 > i)
00221 {
00222 if (nBlockComputedMinv[i0] == 1)
00223 {
00224
00225 Minv.sub((i0 )*bsize,(i0-1)*bsize,bsize,bsize) = Minv.sub((i0 )*bsize,(i0 )*bsize,bsize,bsize)*(-lambda[i0-1].t());
00226 ++nBlockComputedMinv[i0];
00227 }
00228
00229 Minv.sub((i0-1)*bsize,(i0-1)*bsize,bsize,bsize) = alpha_inv[i0-1] - lambda[i0-1]*Minv.sub((i0 )*bsize,(i0-1)*bsize,bsize,bsize);
00230 ++nBlockComputedMinv[i0-1];
00231 --i0;
00232 }
00233 int j0 = i-nBlockComputedMinv[i];
00234 while (j0 >= j)
00235 {
00236
00237 Minv.sub((i0 )*bsize,(j0 )*bsize,bsize,bsize) = Minv.sub((i0 )*bsize,(j0+1)*bsize,bsize,bsize)*(-lambda[j0].t());
00238 ++nBlockComputedMinv[i0];
00239 --j0;
00240 }
00241 }
00242
00243 double getMinvElement(int i, int j)
00244 {
00245 const int bsize = f_blockSize.getValue();
00246 if (i < j)
00247 {
00248 int t = i; i = j; j = t;
00249 }
00250 computeMinvBlock(i/bsize, j/bsize);
00251 return Minv.element(i,j);
00252 }
00253
00255 void solve (Matrix& , Vector& x, Vector& b)
00256 {
00257 const bool verbose = f_verbose.getValue() || f_printLog.getValue();
00258
00259 if( verbose )
00260 {
00261 std::cerr<<"BTDLinearSolver, b = "<< b <<std::endl;
00262 }
00263
00264
00265
00266 const int bsize = f_blockSize.getValue();
00267 const int nb = b.size() / bsize;
00268 if (nb == 0) return;
00269
00270
00271 x.sub(0,bsize) = alpha_inv[0] * b.sub(0,bsize);
00272
00273 for (int i=1;i<nb;++i)
00274 {
00275
00276 x.sub(i*bsize,bsize) = alpha_inv[i]*(b.sub(i*bsize,bsize) - B[i]*x.sub((i-1)*bsize,bsize));
00277
00278 }
00279
00280
00281 for (int i=nb-2;i>=0;--i)
00282 {
00283 x.sub(i*bsize,bsize) -= lambda[i]*x.sub((i+1)*bsize,bsize);
00284
00285 }
00286
00287
00288 if( verbose )
00289 {
00290 std::cerr<<"BTDLinearSolver::solve, solution = "<<x<<std::endl;
00291 }
00292 }
00293
00294 template<class RMatrix, class JMatrix>
00295 bool addJMInvJt(RMatrix& result, JMatrix& J, double fact)
00296 {
00297
00298 const int Jcols = J.colSize();
00299 if (Jcols != Minv.rowSize())
00300 {
00301 std::cerr << "BTDLinearSolver::addJMInvJt ERROR: incompatible J matrix size." << std::endl;
00302 return false;
00303 }
00304
00305
00306 #if 0
00307
00308
00309
00310
00311 if (!problem.getValue()){
00312 for (int mr=0; mr<Minv.rowSize(); mr++)
00313 {
00314 for (int mc=0; mc<Minv.colSize(); mc++)
00315 {
00316 getMinvElement(mr,mc);
00317 }
00318 }
00319 }
00321 #endif
00322 if (f_verbose.getValue()){
00323
00324 std::cout<< "C = ["<<std::endl;
00325 for (int mr=0; mr<Minv.rowSize(); mr++)
00326 {
00327 std::cout<<" "<<std::endl;
00328 for (int mc=0; mc<Minv.colSize(); mc++)
00329 {
00330 std::cout<<" "<< getMinvElement(mr,mc);
00331 }
00332 }
00333 std::cout<< "];"<<std::endl;
00334
00335
00336 std::cout<< "J = ["<<std::endl;
00337 for (int jr=0; jr<J.rowSize(); jr++)
00338 {
00339 std::cout<<" "<<std::endl;
00340 for (int jc=0; jc<J.colSize(); jc++)
00341 {
00342 std::cout<<" "<< J.element(jr, jc) ;
00343 }
00344 }
00345 std::cout<< "];"<<std::endl;
00346 }
00347
00348
00349 const typename JMatrix::LineConstIterator jitend = J.end();
00350 for (typename JMatrix::LineConstIterator jit1 = J.begin(); jit1 != jitend; ++jit1)
00351 {
00352 int row1 = jit1->first;
00353 for (typename JMatrix::LineConstIterator jit2 = jit1; jit2 != jitend; ++jit2)
00354 {
00355 int row2 = jit2->first;
00356 double acc = 0.0;
00357 for (typename JMatrix::LElementConstIterator i1 = jit1->second.begin(), i1end = jit1->second.end(); i1 != i1end; ++i1)
00358 {
00359 int col1 = i1->first;
00360 double val1 = i1->second;
00361 for (typename JMatrix::LElementConstIterator i2 = jit2->second.begin(), i2end = jit2->second.end(); i2 != i2end; ++i2)
00362 {
00363 int col2 = i2->first;
00364 double val2 = i2->second;
00365 acc += val1 * getMinvElement(col1,col2) * val2;
00366 }
00367 }
00368
00369 acc *= fact;
00370 result.add(row1,row2,acc);
00371 if (row1!=row2)
00372 result.add(row2,row1,acc);
00373 }
00374 }
00375 return true;
00376 }
00377
00383 bool addJMInvJt(defaulttype::BaseMatrix* result, defaulttype::BaseMatrix* J, double fact)
00384 {
00385 if (FullMatrix<double>* r = dynamic_cast<FullMatrix<double>*>(result))
00386 {
00387 if (SparseMatrix<double>* j = dynamic_cast<SparseMatrix<double>*>(J))
00388 {
00389 return addJMInvJt(*r,*j,fact);
00390 }
00391 else if (SparseMatrix<float>* j = dynamic_cast<SparseMatrix<float>*>(J))
00392 {
00393 return addJMInvJt(*r,*j,fact);
00394 }
00395 }
00396 else if (FullMatrix<double>* r = dynamic_cast<FullMatrix<double>*>(result))
00397 {
00398 if (SparseMatrix<double>* j = dynamic_cast<SparseMatrix<double>*>(J))
00399 {
00400 return addJMInvJt(*r,*j,fact);
00401 }
00402 else if (SparseMatrix<float>* j = dynamic_cast<SparseMatrix<float>*>(J))
00403 {
00404 return addJMInvJt(*r,*j,fact);
00405 }
00406 }
00407 else if (defaulttype::BaseMatrix* r = result)
00408 {
00409 if (SparseMatrix<double>* j = dynamic_cast<SparseMatrix<double>*>(J))
00410 {
00411 return addJMInvJt(*r,*j,fact);
00412 }
00413 else if (SparseMatrix<float>* j = dynamic_cast<SparseMatrix<float>*>(J))
00414 {
00415 return addJMInvJt(*r,*j,fact);
00416 }
00417 }
00418 return false;
00419 }
00420
00421 };
00422
00423 }
00424
00425 }
00426
00427 }
00428
00429 #endif