tscalapack.cpp

00001 /*************************************************************************************
00002  * MechSys - A C++ library to simulate (Continuum) Mechanical Systems                *
00003  * Copyright (C) 2005 Dorival de Moraes Pedroso <dorival.pedroso at gmail.com>       *
00004  * Copyright (C) 2005 Raul Dario Durand Farfan  <raul.durand at gmail.com>           *
00005  *                                                                                   *
00006  * This file is part of MechSys.                                                     *
00007  *                                                                                   *
00008  * MechSys is free software; you can redistribute it and/or modify it under the      *
00009  * terms of the GNU General Public License as published by the Free Software         *
00010  * Foundation; either version 2 of the License, or (at your option) any later        *
00011  * version.                                                                          *
00012  *                                                                                   *
00013  * MechSys is distributed in the hope that it will be useful, but WITHOUT ANY        *
00014  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A   *
00015  * PARTICULAR PURPOSE. See the GNU General Public License for more details.          *
00016  *                                                                                   *
00017  * You should have received a copy of the GNU General Public License along with      *
00018  * MechSys; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, *
00019  * Fifth Floor, Boston, MA 02110-1301, USA                                           *
00020  *************************************************************************************/
00021 
00022 // STL
00023 #include <iostream>
00024 
00025 // MPI (must be before #define REAL)
00026 #include "mpi.h"
00027 
00028 using std::cout;
00029 using std::endl;
00030 
00031 extern "C" // {{{
00032 {
00033     void   Cblacs_pinfo    (int* mypnum, int* nprocs);
00034     void   Cblacs_get      (int context, int request, int* value);
00035     int    Cblacs_gridinit (int* context, char * order, int np_row, int np_col);
00036     void   Cblacs_gridinfo (int context, int*  np_row, int* np_col, int*  my_row, int*  my_col);
00037     void   Cblacs_gridexit (int context);
00038     void   Cblacs_exit     (int error_code);
00039     int    numroc_         (int *n, int *nb, int *iproc, int *isrcproc, int *nprocs);
00040     void   descinit_       (int *desc, int *m, int *n, int *mb, int *nb, int *irsrc, int *icsrc, int *ictxt, int *lld, int *info);
00041     double pdlamch_        (int *ictxt , char *cmach);
00042     double pdlange_        (char *norm, int *m, int *n, double *A, int *ia, int *ja, int *desca, double *work);
00043     void   pdlacpy_        (char *uplo, int *m, int *n, double *a, int *ia, int *ja, int *desca, double *b, int *ib, int *jb, int *descb);
00044     void   pdgesv_         (int *n, int *nrhs, double *A, int *ia, int *ja, int *desca, int* ipiv, double *B, int *ib, int *jb, int *descb, int *info);
00045     void   pdgemm_         (char *TRANSA, char *TRANSB, int * M, int * N, int * K, double * ALPHA,
00046                             double * A, int * IA, int * JA, int * DESCA, double * B, int * IB, int * JB, int * DESCB,
00047                             double * BETA, double * C, int * IC, int * JC, int * DESCC );
00048     int    indxg2p_        (int *indxglob, int *nb, int *iproc, int *isrcproc, int *nprocs);
00049 } // }}}
00050 
00051 int main(int argc, char **argv)
00052 {
00053     // Initialize
00054     MPI::Init(argc, argv);
00055     int rank = MPI::COMM_WORLD.Get_rank();
00056     int size = MPI::COMM_WORLD.Get_size();
00057 
00058     // Info
00059     cout << "Process #" << rank << " of " << size << " processes just started ...\n";
00060     cout << "" << endl;
00061 
00062     // Data
00063     int n     = 500; // nrows=ncols of a squared matrix
00064     int nrhs  = 1;   // number of Right-Hand-Side columns
00065     int nprow = 2;   // grid size
00066     int npcol = 2;   // grid size
00067     int nb    = 64;  // number of blocks
00068 
00069     // Check
00070     if (nb>n) nb=n;
00071     if (nprow*npcol>size)
00072     {
00073         if (rank==0)
00074         {
00075             cout << "ERROR: There is not enough processes (" << size << "<" << nprow*npcol << ") to make a p-by-q process grid" << endl;
00076             MPI::Finalize();
00077             return 1;
00078         }
00079     }
00080 
00081     // Initialize BLACS grid
00082     int iam,   nprocs, ictxt;
00083     int myrow, mycol;
00084     Cblacs_pinfo    (&iam, &nprocs);
00085     Cblacs_get      (-1, 0, &ictxt);
00086     Cblacs_gridinit (&ictxt, /*order*/"Col", nprow, npcol);
00087     Cblacs_gridinfo (ictxt, &nprow, &npcol, &myrow, &mycol);
00088 
00089     // Work only the process in the process grid
00090     if ((myrow>-1)&&(mycol>-1)&&(myrow<nprow)&&(mycol<npcol))
00091     {
00092         // Compute the size of the local matrices
00093         int izero = 0;
00094         int np    = numroc_(&n   , &nb, &myrow, &izero, &nprow);
00095         int nq    = numroc_(&n   , &nb, &mycol, &izero, &npcol);
00096         int nqrhs = numroc_(&nrhs, &nb, &mycol, &izero, &npcol);
00097 
00098         // Allocate and fill the matrices A and B
00099         double * A     = new double [np*nq];
00100         double * Acpy  = new double [np*nq];
00101         double * B     = new double [np*nqrhs];
00102         double * X     = new double [np*nqrhs];
00103         double * R     = new double [np*nqrhs];
00104         int    * ippiv = new int    [np+nb];
00105 
00106         // Generate random A matrix 
00107         int k=0;
00108         for (int i=0; i<np; i++)
00109         for (int j=0; j<nq; j++)
00110         {
00111             A[k] = ((double) rand()) / ((double) RAND_MAX) - 0.5;
00112             k++;   
00113         }
00114 
00115         // Generate random B vector
00116         k=0;
00117         for (int i=0; i<np;    i++)
00118         for (int j=0; j<nqrhs; j++)
00119         {
00120             B[k] = ((double) rand()) / ((double) RAND_MAX) - 0.5;
00121             k++;   
00122         }
00123 
00124         // Initialize the array descriptor for the matrix A and B
00125         int itemp = (np<1 ? 1 : np);
00126         int descA[9];
00127         int descB[9];
00128         int info;
00129         descinit_(descA, &n, &n   , &nb, &nb, &izero, &izero, &ictxt, &itemp, &info);
00130         descinit_(descB, &n, &nrhs, &nb, &nb, &izero, &izero, &ictxt, &itemp, &info);
00131 
00132         // Make a copy of A and the rhs for checking purposes
00133         int ione = 1;
00134         pdlacpy_("All", &n, &n   , A, &ione, &ione, descA, Acpy, &ione, &ione, descA);
00135         pdlacpy_("All", &n, &nrhs, B, &ione, &ione, descB, X   , &ione, &ione, descB);
00136 
00137         // Call ScaLAPACK PDGESV routine
00138         double MPIt1 = MPI::Wtime();
00139         pdgesv_(&n, &nrhs, A, &ione, &ione, descA, ippiv, X, &ione, &ione, descB, &info);
00140         double MPIt2 = MPI::Wtime();
00141         double MPIelapsed = MPIt2-MPIt1;
00142 
00143         // Froebenius norm = ||A * X  - B|| / ( ||X|| * ||A|| * eps * N )
00144         double mone=-1.0;
00145         double pone= 1.0;
00146         pdlacpy_("All", &n, &nrhs, B, &ione, &ione, descB, R, &ione, &ione, descB);
00147         pdgemm_ ("N", "N", &n, &nrhs, &n, &pone, Acpy, &ione, &ione, descA, X, &ione, &ione, descB, &mone, R, &ione, &ione, descB);
00148         double work   = 0.0;
00149         double eps    = pdlamch_(&ictxt, "Epsilon");
00150         double AnormF = pdlange_("F", &n, &n   , A, &ione, &ione, descA, &work);
00151         double XnormF = pdlange_("F", &n, &nrhs, X, &ione, &ione, descB, &work);
00152         double RnormF = pdlange_("F", &n, &nrhs, R, &ione, &ione, descB, &work);
00153         double residF = RnormF/(AnormF*XnormF*eps*static_cast<double>(n));
00154 
00155         // Information
00156         if (iam==0)
00157         {
00158             cout << endl;
00159             cout << "***********************************************" << endl;
00160             cout << "  Example of ScaLAPACK routine call: (PDGESV)  " << endl;
00161             cout << "***********************************************" << endl;
00162             cout << endl;
00163             cout << "  n      = " << n                      << endl;
00164             cout << "  nrhs   = " << nrhs                   << endl;
00165             cout << "  grid   = " << nprow << ", " << npcol << endl;
00166             cout << "  blocks = " << nb << "x" << nb        << endl;
00167             cout << "  np     = " << np                     << endl;
00168             cout << "  nq     = " << nq                     << endl;
00169             cout << "  nqrhs  = " << nqrhs                  << endl;
00170             cout << endl;
00171             cout << "MPI elapsed time during (pdgesv) = " << MPIelapsed << endl;
00172             cout << "Info returned by (pdgesv)        = " << info       << endl;
00173             cout << endl;
00174             cout << "Froebenius norm (residual) = " << residF << endl;
00175             cout << endl;
00176         }
00177 
00178         // Clean up
00179         delete [] A;
00180         delete [] Acpy;
00181         delete [] B;
00182         delete [] X;
00183         delete [] R;
00184         delete [] ippiv;
00185 
00186         // Grid exit
00187         Cblacs_gridexit(0);
00188     }
00189 
00190     // Information
00191     if(iam==0)
00192     {
00193         cout << "***********************************************\n";
00194         cout << "                      END                      \n";
00195         cout << "***********************************************\n";
00196     }
00197 
00198     // Finalize
00199     MPI::Finalize();
00200 
00201     return 0;
00202 }
00203 
00204 // vim:fdm=marker

Generated on Wed Jan 24 15:56:26 2007 for MechSys by  doxygen 1.4.7