computation/interfaces/direct/Mumps.cxx

00001 // Copyright (C) 2003-2009 Marc Duruflé
00002 //
00003 // This file is part of the linear-algebra library Seldon,
00004 // http://seldon.sourceforge.net/.
00005 //
00006 // Seldon is free software; you can redistribute it and/or modify it under the
00007 // terms of the GNU Lesser General Public License as published by the Free
00008 // Software Foundation; either version 2.1 of the License, or (at your option)
00009 // any later version.
00010 //
00011 // Seldon is distributed in the hope that it will be useful, but WITHOUT ANY
00012 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00013 // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
00014 // more details.
00015 //
00016 // You should have received a copy of the GNU Lesser General Public License
00017 // along with Seldon. If not, see http://www.gnu.org/licenses/.
00018 
00019 
00020 #ifndef SELDON_FILE_MUMPS_CXX
00021 
00022 #include "Mumps.hxx"
00023 
00024 namespace Seldon
00025 {
00026 
00028   template<>
00029   inline void MatrixMumps<double>::CallMumps()
00030   {
00031     dmumps_c(&struct_mumps);
00032   }
00033 
00034 
00036   template<>
00037   inline void MatrixMumps<complex<double> >::CallMumps()
00038   {
00039     zmumps_c(&struct_mumps);
00040   }
00041 
00042 
00044   template<class T>
00045   inline MatrixMumps<T>::MatrixMumps()
00046   {
00047     // struct_mumps.comm_fortran = MPI_Comm_c2f(MPI_COMM_WORLD);
00048     struct_mumps.comm_fortran = -987654;
00049 
00050     // parameters for mumps
00051     struct_mumps.job = -1;
00052     struct_mumps.par = 1;
00053     struct_mumps.sym = 0; // 0 -> unsymmetric matrix
00054 
00055     // mumps is called
00056     CallMumps();
00057 
00058     // other parameters
00059     struct_mumps.n = 0;
00060     type_ordering = 7; // default : we let Mumps choose the ordering
00061     print_level = -1;
00062     out_of_core = false;
00063     new_communicator = false;
00064   }
00065 
00066 
00068   template<class T> template<class MatrixSparse>
00069   inline void MatrixMumps<T>
00070   ::InitMatrix(const MatrixSparse& A, bool distributed)
00071   {
00072     // we clear previous factorization
00073     Clear();
00074 
00075 #ifdef SELDON_WITH_MPI
00076     // MPI initialization for parallel version
00077     if (distributed)
00078       {
00079         // for distributed matrix, every processor is assumed to be involved
00080         struct_mumps.comm_fortran = -987654;
00081       }
00082     else
00083       {
00084         // centralized matrix => a linear system per processor
00085         MPI_Comm_rank(MPI_COMM_WORLD, &rank);
00086         MPI_Comm_group(MPI_COMM_WORLD, &single_group);
00087         MPI_Group_incl(single_group, 1, &rank, &single_group);
00088         MPI_Comm_create(MPI_COMM_WORLD, single_group, &single_comm);
00089         struct_mumps.comm_fortran = MPI_Comm_c2f(single_comm);
00090         new_communicator = true;
00091       }
00092 #endif
00093 
00094     // symmetry is specified during the initialization stage
00095     struct_mumps.job = -1;
00096     if (IsSymmetricMatrix(A))
00097       struct_mumps.sym = 2; // general symmetric matrix
00098     else
00099       struct_mumps.sym = 0; // unsymmetric matrix
00100 
00101     // mumps is called
00102     CallMumps();
00103 
00104     struct_mumps.icntl[13] = 20;
00105     struct_mumps.icntl[6] = type_ordering;
00106     // setting out of core parameters
00107     if (out_of_core)
00108       struct_mumps.icntl[21] = 1;
00109     else
00110       struct_mumps.icntl[21] = 0;
00111 
00112     struct_mumps.icntl[17] = 0;
00113 
00114     // the print level is set in mumps
00115     if (print_level >= 0)
00116       {
00117         struct_mumps.icntl[0] = 6;
00118         struct_mumps.icntl[1] = 0;
00119         struct_mumps.icntl[2] = 6;
00120         struct_mumps.icntl[3] = 2;
00121       }
00122     else
00123       {
00124         struct_mumps.icntl[0] = -1;
00125         struct_mumps.icntl[1] = -1;
00126         struct_mumps.icntl[2] = -1;
00127         struct_mumps.icntl[3] = 0;
00128       }
00129   }
00130 
00131 
00133   template<class T>
00134   inline void MatrixMumps<T>::SelectOrdering(int num_ordering)
00135   {
00136     type_ordering = num_ordering;
00137   }
00138 
00139 
00141   template<class T>
00142   MatrixMumps<T>::~MatrixMumps()
00143   {
00144     Clear();
00145   }
00146 
00147 
00149   template<class T>
00150   inline void MatrixMumps<T>::Clear()
00151   {
00152     if (struct_mumps.n > 0)
00153       {
00154         struct_mumps.job = -2;
00155         CallMumps(); /* Terminate instance */
00156 
00157         num_row_glob.Clear(); num_col_glob.Clear();
00158         struct_mumps.n = 0;
00159 
00160       }
00161 
00162 #ifdef SELDON_WITH_MPI
00163     if (new_communicator)
00164       {
00165         MPI_Comm_free(&single_comm);
00166         new_communicator = false;
00167       }
00168 #endif
00169 
00170   }
00171 
00172 
00174   template<class T>
00175   inline void MatrixMumps<T>::HideMessages()
00176   {
00177     print_level = -1;
00178 
00179     struct_mumps.icntl[0] = -1;
00180     struct_mumps.icntl[1] = -1;
00181     struct_mumps.icntl[2] = -1;
00182     struct_mumps.icntl[3] = 0;
00183 
00184   }
00185 
00186 
00188   template<class T>
00189   inline void MatrixMumps<T>::ShowMessages()
00190   {
00191     print_level = 0;
00192 
00193     struct_mumps.icntl[0] = 6;
00194     struct_mumps.icntl[1] = 0;
00195     struct_mumps.icntl[2] = 6;
00196     struct_mumps.icntl[3] = 2;
00197 
00198   }
00199 
00200 
00201   template<class T>
00202   inline void MatrixMumps<T>::EnableOutOfCore()
00203   {
00204     out_of_core = true;
00205   }
00206 
00207 
00208   template<class T>
00209   inline void MatrixMumps<T>::DisableOutOfCore()
00210   {
00211     out_of_core = false;
00212   }
00213 
00214 
00216 
00221   template<class T> template<class Prop,class Storage,class Allocator>
00222   void MatrixMumps<T>::FindOrdering(Matrix<T, Prop, Storage, Allocator> & mat,
00223                                     IVect& numbers, bool keep_matrix)
00224   {
00225     InitMatrix(mat);
00226 
00227     int n = mat.GetM(), nnz = mat.GetNonZeros();
00228     // conversion in coordinate format
00229     IVect num_row, num_col; Vector<T, VectFull, Allocator> values;
00230     ConvertMatrix_to_Coordinates(mat, num_row, num_col, values, 1);
00231     // no values needed to renumber
00232     values.Clear();
00233     if (!keep_matrix)
00234       mat.Clear();
00235 
00236     struct_mumps.n = n; struct_mumps.nz = nnz;
00237     struct_mumps.irn = num_row.GetData();
00238     struct_mumps.jcn = num_col.GetData();
00239 
00240     /* Call the MUMPS package. */
00241     struct_mumps.job = 1; // we analyse the system
00242     CallMumps();
00243 
00244     numbers.Reallocate(n);
00245     for (int i = 0; i < n; i++)
00246       numbers(i) = struct_mumps.sym_perm[i]-1;
00247   }
00248 
00249 
00251 
00255   template<class T> template<class Prop, class Storage, class Allocator>
00256   void MatrixMumps<T>::FactorizeMatrix(Matrix<T,Prop,Storage,Allocator> & mat,
00257                                        bool keep_matrix)
00258   {
00259     InitMatrix(mat);
00260 
00261     int n = mat.GetM(), nnz = mat.GetNonZeros();
00262     // conversion in coordinate format with fortran convention (1-index)
00263     IVect num_row, num_col; Vector<T, VectFull, Allocator> values;
00264     ConvertMatrix_to_Coordinates(mat, num_row, num_col, values, 1);
00265     if (!keep_matrix)
00266       mat.Clear();
00267 
00268     struct_mumps.n = n; struct_mumps.nz = nnz;
00269     struct_mumps.irn = num_row.GetData();
00270     struct_mumps.jcn = num_col.GetData();
00271     struct_mumps.a = reinterpret_cast<pointer>(values.GetData());
00272 
00273     /* Call the MUMPS package. */
00274     struct_mumps.job = 4; // we analyse and factorize the system
00275     CallMumps();
00276   }
00277 
00278 
00280   template<class T> template<class Prop, class Storage, class Allocator>
00281   void MatrixMumps<T>
00282   ::PerformAnalysis(Matrix<T, Prop, Storage, Allocator> & mat)
00283   {
00284     InitMatrix(mat);
00285 
00286     int n = mat.GetM(), nnz = mat.GetNonZeros();
00287     // conversion in coordinate format with fortran convention (1-index)
00288     Vector<T, VectFull, Allocator> values;
00289     ConvertMatrix_to_Coordinates(mat, num_row_glob, num_col_glob, values, 1);
00290 
00291     struct_mumps.n = n; struct_mumps.nz = nnz;
00292     struct_mumps.irn = num_row_glob.GetData();
00293     struct_mumps.jcn = num_col_glob.GetData();
00294     struct_mumps.a = reinterpret_cast<pointer>(values.GetData());
00295 
00296     /* Call the MUMPS package. */
00297     struct_mumps.job = 1; // we analyse the system
00298     CallMumps();
00299   }
00300 
00301 
00303 
00309   template<class T> template<class Prop, class Storage, class Allocator>
00310   void MatrixMumps<T>
00311   ::PerformFactorization(Matrix<T, Prop, Storage, Allocator> & mat)
00312   {
00313     // we consider that the values are corresponding
00314     // to the row/column numbers given for the analysis
00315     struct_mumps.a = reinterpret_cast<pointer>(mat.GetData());
00316 
00317     /* Call the MUMPS package. */
00318     struct_mumps.job = 2; // we factorize the system
00319     CallMumps();
00320   }
00321 
00322 
00324   template<class T>
00325   int MatrixMumps<T>::GetInfoFactorization() const
00326   {
00327     return struct_mumps.info[0];
00328   }
00329 
00330 
00332 
00338   template<class T> template<class Prop1, class Storage1, class Allocator,
00339                              class Prop2, class Storage2, class Allocator2>
00340   void MatrixMumps<T>::
00341   GetSchurMatrix(Matrix<T, Prop1, Storage1, Allocator>& mat, const IVect& num,
00342                  Matrix<T, Prop2, Storage2, Allocator2> & mat_schur,
00343                  bool keep_matrix)
00344   {
00345     InitMatrix(mat);
00346 
00347     int n_schur = num.GetM(), n = mat.GetM();
00348     // Subscripts are changed to respect fortran convention
00349     IVect index_schur(n_schur);
00350     for (int i = 0; i < n_schur; i++)
00351       index_schur(i) = num(i)+1;
00352 
00353     // array that will contain values of Schur matrix
00354     Vector<T, VectFull, Allocator2> vec_schur(n_schur*n_schur);
00355 
00356     struct_mumps.icntl[18] = n_schur;
00357     struct_mumps.size_schur = n_schur;
00358     struct_mumps.listvar_schur = index_schur.GetData();
00359     struct_mumps.schur = reinterpret_cast<pointer>(vec_schur.GetData());
00360 
00361     // factorization of the matrix
00362     FactorizeMatrix(mat, keep_matrix);
00363 
00364     // resetting parameters related to Schur complement
00365     struct_mumps.icntl[18] = 0;
00366     struct_mumps.size_schur = 0;
00367     struct_mumps.listvar_schur = NULL;
00368     struct_mumps.schur = NULL;
00369 
00370     // schur complement stored by rows
00371     int nb = 0;
00372     mat_schur.Reallocate(n,n);
00373     for (int i = 0; i < n; i++)
00374       for (int j = 0; j < n ;j++)
00375         mat_schur(i,j) = vec_schur(nb++);
00376 
00377     vec_schur.Clear(); index_schur.Clear();
00378   }
00379 
00380 
00382 
00386   template<class T> template<class Allocator2, class Transpose_status>
00387   void MatrixMumps<T>::Solve(const Transpose_status& TransA,
00388                              Vector<T, VectFull, Allocator2>& x)
00389   {
00390 #ifdef SELDON_CHECK_DIMENSIONS
00391     if (x.GetM() != struct_mumps.n)
00392       throw WrongDim("Mumps::Solve(TransA, c)",
00393                      string("The length of x is equal to ")
00394                      + to_str(x.GetM())
00395                      + " while the size of the matrix is equal to "
00396                      + to_str(struct_mumps.n) + ".");
00397 #endif
00398 
00399     if (TransA.Trans())
00400       struct_mumps.icntl[8] = 0;
00401     else
00402       struct_mumps.icntl[8] = 1;
00403 
00404     struct_mumps.rhs = reinterpret_cast<pointer>(x.GetData());
00405     struct_mumps.job = 3; // we solve system
00406     CallMumps();
00407   }
00408 
00409 
00410 
00411   template<class T> template<class Allocator2>
00412   void MatrixMumps<T>::Solve(Vector<T, VectFull, Allocator2>& x)
00413   {
00414     Solve(SeldonNoTrans, x);
00415   }
00416 
00417 
00419 
00423   template<class T>
00424   template<class Allocator2, class Transpose_status, class Prop>
00425   void MatrixMumps<T>::Solve(const Transpose_status& TransA,
00426                              Matrix<T, Prop, ColMajor, Allocator2>& x)
00427   {
00428 
00429 #ifdef SELDON_CHECK_BOUNDS
00430     if (x.GetM() != struct_mumps.n)
00431       throw WrongDim("Mumps::Solve", string("Row size of x is equal to ")
00432                      + to_str(x.GetM()) + " while size of matrix is equal to "
00433                      + to_str(struct_mumps.n));
00434 #endif
00435 
00436     if (TransA.Trans())
00437       struct_mumps.icntl[8] = 0;
00438     else
00439       struct_mumps.icntl[8] = 1;
00440 
00441     struct_mumps.nrhs = x.GetN();
00442     struct_mumps.lrhs = x.GetM();
00443     struct_mumps.rhs = reinterpret_cast<pointer>(x.GetData());
00444     struct_mumps.job = 3; // we solve system
00445     CallMumps();
00446   }
00447 
00448 
00449 #ifdef SELDON_WITH_MPI
00450 
00451 
00457   template<class T> template<class Prop, class Allocator>
00458   void MatrixMumps<T>::
00459   FactorizeDistributedMatrix(Matrix<T, General, ColSparse, Allocator> & mat,
00460                              const Prop& sym, const IVect& glob_number,
00461                              bool keep_matrix)
00462   {
00463     // initialization depending on symmetric of the matrix
00464     Matrix<T, Prop, RowSparse, Allocator> Atest;
00465     InitMatrix(Atest, true);
00466 
00467     // distributed matrix
00468     struct_mumps.icntl[17] = 3;
00469 
00470     // global number of rows : mat.GetM()
00471     int N = mat.GetM();
00472     int nnz = mat.GetNonZeros();
00473     // conversion in coordinate format with C-convention (0-index)
00474     IVect num_row, num_col; Vector<T, VectFull, Allocator> values;
00475     ConvertMatrix_to_Coordinates(mat, num_row,
00476                                  num_col, values, 0);
00477 
00478     // we replace num_col with global numbers
00479     for (int i = 0; i < num_row.GetM(); i++)
00480       {
00481         num_row(i)++;
00482         num_col(i) = glob_number(num_col(i)) + 1;
00483       }
00484 
00485     if (!keep_matrix)
00486       mat.Clear();
00487 
00488     /* Define the problem on the host */
00489     struct_mumps.n = N; struct_mumps.nz_loc = nnz;
00490     struct_mumps.irn_loc = num_row.GetData();
00491     struct_mumps.jcn_loc = num_col.GetData();
00492     struct_mumps.a_loc = reinterpret_cast<pointer>(values.GetData());
00493 
00494     /* Call the MUMPS package. */
00495     struct_mumps.job = 4; // we analyse and factorize the system
00496     CallMumps();
00497     cout<<"Factorization completed"<<endl;
00498   }
00499 
00500 
00502   template<class Alloc1, class Alloc2, class Alloc3, class Tint>
00503   void FactorizeDistributedMatrix(Vector<int, VectFull, Alloc1>&,
00504                                   Vector<int, VectFull, Alloc2>&,
00505                                   Vector<T, VectFull, Alloc3>&,
00506                                   const Vector<Tint>& glob_number,
00507                                   bool sym, bool keep_matrix)
00508   {
00509     throw Undefined("FactorizeDistributedMatrix(Vector<int>&, Vector<int>&, "
00510                     "Vector<T>&, Vector<Tint>, bool, bool)");
00511   }
00512 
00513 
00515 
00520   template<class T> template<class Allocator2, class Transpose_status>
00521   void MatrixMumps<T>::SolveDistributed(const Transpose_status& TransA,
00522                                         Vector<T, VectFull, Allocator2>& x,
00523                                         const IVect& glob_num)
00524   {
00525     Vector<T, VectFull, Allocator2> rhs;
00526     int cplx = sizeof(T)/8;
00527     // allocating the global right hand side
00528     rhs.Reallocate(struct_mumps.n); rhs.Zero();
00529 
00530     if (rank == 0)
00531       {
00532         // on the host, we retrieve datas of all the other processors
00533         int nb_procs; MPI_Status status;
00534         MPI_Comm_size(MPI_COMM_WORLD, &nb_procs);
00535         if (nb_procs > 1)
00536           {
00537             // assembling the right hand side
00538             Vector<T, VectFull, Allocator2> xp;
00539             IVect nump;
00540             for (int i = 0; i < nb_procs; i++)
00541               {
00542 
00543                 if (i != 0)
00544                   {
00545                     int nb_dof;
00546                     MPI_Recv(&nb_dof, 1, MPI_INT, i, 34,
00547                              MPI_COMM_WORLD, &status);
00548                     xp.Reallocate(nb_dof);
00549                     nump.Reallocate(nb_dof);
00550                     MPI_Recv(xp.GetDataVoid(), cplx*nb_dof,
00551                              MPI_DOUBLE, i, 35, MPI_COMM_WORLD, &status);
00552                     MPI_Recv(nump.GetData(), nb_dof, MPI_INT, i, 36,
00553                              MPI_COMM_WORLD, &status);
00554                   }
00555                 else
00556                   {
00557                     xp = x; nump = glob_num;
00558                   }
00559 
00560                 for (int j = 0; j < nump.GetM(); j++)
00561                   rhs(nump(j)) = xp(j);
00562               }
00563           }
00564         else
00565           Copy(x, rhs);
00566 
00567         struct_mumps.rhs = reinterpret_cast<pointer>(rhs.GetData());
00568       }
00569     else
00570       {
00571         // on other processors, we send solution
00572         int nb = x.GetM();
00573         MPI_Send(&nb, 1, MPI_INT, 0, 34, MPI_COMM_WORLD);
00574         MPI_Send(x.GetDataVoid(), cplx*nb, MPI_DOUBLE, 0, 35, MPI_COMM_WORLD);
00575         MPI_Send(glob_num.GetData(), nb, MPI_INT, 0, 36, MPI_COMM_WORLD);
00576       }
00577 
00578     // we solve system
00579     if (TransA.Trans())
00580       struct_mumps.icntl[8] = 0;
00581     else
00582       struct_mumps.icntl[8] = 1;
00583 
00584     struct_mumps.job = 3;
00585     CallMumps();
00586 
00587     // we distribute solution on all the processors
00588     MPI_Bcast(rhs.GetDataVoid(), cplx*rhs.GetM(),
00589               MPI_DOUBLE, 0, MPI_COMM_WORLD);
00590 
00591     // and we extract the solution on provided numbers
00592     for (int i = 0; i < x.GetM(); i++)
00593       x(i) = rhs(glob_num(i));
00594   }
00595 
00596 
00597   template<class T> template<class Allocator2>
00598   void MatrixMumps<T>::SolveDistributed(Vector<T, VectFull, Allocator2>& x,
00599                                         const IVect& glob_num)
00600   {
00601     SolveDistributed(SeldonNoTrans, x, glob_num);
00602   }
00603 #endif
00604 
00605 
00606   template<class T, class Storage, class Allocator>
00607   void GetLU(Matrix<T,Symmetric,Storage,Allocator>& A, MatrixMumps<T>& mat_lu,
00608              bool keep_matrix = false)
00609   {
00610     mat_lu.FactorizeMatrix(A, keep_matrix);
00611   }
00612 
00613 
00614   template<class T, class Storage, class Allocator>
00615   void GetLU(Matrix<T,General,Storage,Allocator>& A, MatrixMumps<T>& mat_lu,
00616              bool keep_matrix = false)
00617   {
00618     mat_lu.FactorizeMatrix(A, keep_matrix);
00619   }
00620 
00621 
00622   template<class T, class Storage, class Allocator, class MatrixFull>
00623   void GetSchurMatrix(Matrix<T, Symmetric, Storage, Allocator>& A,
00624                       MatrixMumps<T>& mat_lu, const IVect& num,
00625                       MatrixFull& schur_matrix, bool keep_matrix = false)
00626   {
00627     mat_lu.GetSchurMatrix(A, num, schur_matrix, keep_matrix);
00628   }
00629 
00630 
00631   template<class T, class Storage, class Allocator, class MatrixFull>
00632   void GetSchurMatrix(Matrix<T, General, Storage, Allocator>& A,
00633                       MatrixMumps<T>& mat_lu, const IVect& num,
00634                       MatrixFull& schur_matrix, bool keep_matrix = false)
00635   {
00636     mat_lu.GetSchurMatrix(A, num, schur_matrix, keep_matrix);
00637   }
00638 
00639 
00640   template<class T, class Allocator>
00641   void SolveLU(MatrixMumps<T>& mat_lu, Vector<T, VectFull, Allocator>& x)
00642   {
00643     mat_lu.Solve(x);
00644   }
00645 
00646 
00647   template<class T, class Allocator, class Transpose_status>
00648   void SolveLU(const Transpose_status& TransA,
00649                MatrixMumps<T>& mat_lu, Vector<T, VectFull, Allocator>& x)
00650   {
00651     mat_lu.Solve(TransA, x);
00652   }
00653 
00654 
00655   template<class T, class Prop, class Allocator>
00656   void SolveLU(MatrixMumps<T>& mat_lu,
00657                Matrix<T, Prop, ColMajor, Allocator>& x)
00658   {
00659     mat_lu.Solve(SeldonNoTrans, x);
00660   }
00661 
00662 
00663   template<class T, class Allocator, class Transpose_status>
00664   void SolveLU(const Transpose_status& TransA,
00665                MatrixMumps<T>& mat_lu, Matrix<T, ColMajor, Allocator>& x)
00666   {
00667     mat_lu.Solve(TransA, x);
00668   }
00669 
00670 }
00671 
00672 #define SELDON_FILE_MUMPS_CXX
00673 #endif