MechSys  1.0
Computing library for simulations in continuum and discrete mechanics
/home/dorival/mechsys/lib/mesh/paragrid3d.h
Go to the documentation of this file.
00001 /************************************************************************
00002  * MechSys - Open Library for Mechanical Systems                        *
00003  * Copyright (C) 2005 Dorival M. Pedroso, Raúl D. D. Farfan             *
00004  *                                                                      *
00005  * This program is free software: you can redistribute it and/or modify *
00006  * it under the terms of the GNU General Public License as published by *
00007  * the Free Software Foundation, either version 3 of the License, or    *
00008  * any later version.                                                   *
00009  *                                                                      *
00010  * This program is distributed in the hope that it will be useful,      *
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the         *
00013  * GNU General Public License for more details.                         *
00014  *                                                                      *
00015  * You should have received a copy of the GNU General Public License    *
00016  * along with this program. If not, see <http://www.gnu.org/licenses/>  *
00017  ************************************************************************/
00018 
00019 #ifndef MECHSYS_PARAGRID3D_H
00020 #define MECHSYS_PARAGRID3D_H
00021 
00022 // MechSys
00023 #include <mechsys/util/maps.h>
00024 #include <mechsys/linalg/matvec.h>
00025 #include <mechsys/mesh/structured.h>
00026 
00027 // enum
00028 enum CellType { Inner_t=-1, BryIn_t=-2, BryOut_t=-3, Outer_t=-4 };
00029 
00030 class ParaGrid3D
00031 {
00032 public:
00033     // enums
00034     enum MetisAlgo { Recursive_t=0, Kway_t=1, VKway_t=2 };
00035 
00036     // Constructor & Destructor
00037     ParaGrid3D (Array<int> const & N, Array<double> & L, char const * FileKey=NULL, MetisAlgo Algo=Recursive_t);
00038 
00039     // Methods
00040     int  FindCell  (Vec3_t const & X) const;                       
00041     void FindCells (Vec3_t const & X, double R, int Ids[8]) const; 
00042 
00043     // Data (read-only)
00044     Array<int>          N;             
00045     Array<double>       L;             
00046     Vec3_t              D;             
00047     Array<int>          NeighProcs;    
00048     Array<CellType>     Id2Type;       
00049     Array<int>          Id2Proc;       
00050     Array< Array<int> > Id2NeighProcs; 
00051 
00052 };
00053 
00054 
00056 
00057 
00058 inline ParaGrid3D::ParaGrid3D (Array<int> const & TheN, Array<double> & TheL, char const * FileKey, MetisAlgo Algo)
00059     : N(TheN), L(TheL)
00060 {
00061     // cell size
00062     D = (L[1]-L[0])/static_cast<double>(N[0]),
00063         (L[3]-L[2])/static_cast<double>(N[1]),
00064         (L[5]-L[4])/static_cast<double>(N[2]);
00065 
00066     // proc id and number of cells
00067     int my_id  = MPI::COMM_WORLD.Get_rank();
00068     int nprocs = MPI::COMM_WORLD.Get_size();
00069     int ncells = N[0]*N[1]*N[2];
00070 
00071     // find neighbours for METIS
00072     Array<int> Xadj(0, /*justone*/true);
00073     Array<int> Adjn;
00074     for (int k=0; k<N[2]; ++k)
00075     for (int j=0; j<N[1]; ++j)
00076     for (int i=0; i<N[0]; ++i)
00077     {
00078         int back   = (i-1) +  j   *N[0] +  k   *N[0]*N[1];
00079         int front  = (i+1) +  j   *N[0] +  k   *N[0]*N[1];
00080         int left   =  i    + (j-1)*N[0] +  k   *N[0]*N[1];
00081         int right  =  i    + (j+1)*N[0] +  k   *N[0]*N[1];
00082         int bottom =  i    +  j   *N[0] + (k-1)*N[0]*N[1];
00083         int top    =  i    +  j   *N[0] + (k+1)*N[0]*N[1];
00084         Array<int> neighs; // not including the opposite-diagonal ones (for better quality domain decomposition)
00085         if (i>0)      neighs.Push (back);
00086         if (i<N[0]-1) neighs.Push (front);
00087         if (j>0)      neighs.Push (left);
00088         if (j<N[1]-1) neighs.Push (right);
00089         if (k>0)      neighs.Push (bottom);
00090         if (k<N[2]-1) neighs.Push (top);
00091         Xadj.Push (Xadj.Last()+neighs.Size());
00092         for (size_t p=0; p<neighs.Size(); ++p) Adjn.Push (neighs[p]);
00093     }
00094 
00095     // domain decomposition
00096     Id2Proc.Resize    (ncells);
00097     Id2Proc.SetValues (0);
00098 #if defined(HAS_PARMETIS) && defined(HAS_MPI)
00099     if (nprocs>1)
00100     {
00101         int wgtflag    = 0; // No weights
00102         int numflag    = 0; // zero numbering
00103         int options[5] = {0,0,0,0,0};
00104         if (Algo==Recursive_t)
00105         {
00106             int edgecut;
00107             METIS_PartGraphRecursive (&ncells, Xadj.GetPtr(), Adjn.GetPtr(), NULL, NULL, &wgtflag, &numflag, &nprocs, options, &edgecut, Id2Proc.GetPtr());
00108             if (my_id==0) printf("METIS: Recursive: Edgecut = %d\n",edgecut);
00109         }
00110         else if (Algo==Kway_t)
00111         {
00112             int edgecut;
00113             METIS_PartGraphKway (&ncells, Xadj.GetPtr(), Adjn.GetPtr(), NULL, NULL, &wgtflag, &numflag, &nprocs, options, &edgecut, Id2Proc.GetPtr());
00114             if (my_id==0) printf("METIS: Kway: Edgecut = %d\n",edgecut);
00115         }
00116         else if (Algo==VKway_t)
00117         {
00118             int volume;
00119             METIS_PartGraphVKway (&ncells, Xadj.GetPtr(), Adjn.GetPtr(), NULL, NULL, &wgtflag, &numflag, &nprocs, options, &volume, Id2Proc.GetPtr());
00120             if (my_id==0) printf("METIS: VKway: Volume = %d\n",volume);
00121         }
00122         else throw new Fatal("ParaGrid3D::ParaGrid3D: MetisAlgo==%d is invalid",Algo);
00123 #else
00124         throw new Fatal("ParaGrid3D::ParaGrid3D: This method requires ParMETIS and MPI (if Part array is not provided)");
00125 #endif
00126     }
00127 
00128     // find types and neighbour processors of all cells
00129     Id2Type      .Resize (ncells);
00130     Id2NeighProcs.Resize (ncells);
00131     Array<int> bryouts; // boundary cells outside this processor
00132     for (int k=0; k<N[2]; ++k)
00133     for (int j=0; j<N[1]; ++j)
00134     for (int i=0; i<N[0]; ++i)
00135     {
00136         int n = i + j*N[0] + k*N[0]*N[1];
00137         Id2Type[n] = Outer_t;
00138         if (Id2Proc[n]==my_id) // cell is in this processor
00139         {
00140             Id2Type[n] = Inner_t;
00141             for (int r=i-1; r<i+2; ++r)
00142             for (int s=j-1; s<j+2; ++s)
00143             for (int t=k-1; t<k+2; ++t) // look for all 26 neighbours of cell # n
00144             {
00145                 if (!(r==i && s==j && t==k))
00146                 {
00147                     int m = r + s*N[0] + t*N[0]*N[1];
00148                     if (r>=0 && r<N[0] &&
00149                         s>=0 && s<N[1] &&
00150                         t>=0 && t<N[2]) // cell # m is inside limits
00151                     {
00152                         if (Id2Proc[m]!=my_id) // cell # m is in another processor
00153                         {
00154                             Id2Type[n] = BryIn_t;
00155                             bryouts.XPush (m);
00156                             Id2NeighProcs[n].XPush (Id2Proc[m]);
00157                         }
00158                     }
00159                 }
00160             }
00161         }
00162     }
00163     for (size_t i=0; i<bryouts.Size(); ++i)
00164     {
00165         int     m  = bryouts[i];
00166         Id2Type[m] = BryOut_t;
00167         NeighProcs.XPush (Id2Proc[m]);
00168     }
00169 
00170     // write VTU
00171     if (FileKey!=NULL)
00172     {
00173         std::ostringstream oss;
00174         size_t nn = (N[0]+1)*(N[1]+1)*(N[2]+1); // number of Nodes
00175         size_t nc = ncells;                     // number of Cells
00176 
00177         // constants
00178         size_t          nimax = 40;        // number of integers in a line
00179         size_t          nfmax =  6;        // number of floats in a line
00180         Util::NumStream nsflo = Util::_8s; // number format for floats
00181 
00182         // header
00183         oss << "<?xml version=\"1.0\"?>\n";
00184         oss << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\" byte_order=\"LittleEndian\">\n";
00185         oss << "  <UnstructuredGrid>\n";
00186         oss << "    <Piece NumberOfPoints=\"" << nn << "\" NumberOfCells=\"" << nc << "\">\n";
00187 
00188         // nodes: coordinates
00189         oss << "      <Points>\n";
00190         oss << "        <DataArray type=\"Float32\" NumberOfComponents=\"3\" format=\"ascii\">\n";
00191         size_t k = 0; oss << "        ";
00192         int nx = N[0]+1;
00193         int ny = N[1]+1;
00194         int nz = N[2]+1;
00195         for (size_t n=0; n<nn; ++n)
00196         {
00197             int K =  n / (nx*ny);
00198             int J = (n % (nx*ny)) / nx;
00199             int I = (n % (nx*ny)) % nx;
00200             oss << "  " << nsflo << L[0] + I*D[0] << " ";
00201             oss <<         nsflo << L[2] + J*D[1] << " ";
00202             oss <<         nsflo << L[4] + K*D[2];
00203             k++;
00204             VTU_NEWLINE (n,k,nn,nfmax/3-1,oss);
00205         }
00206         oss << "        </DataArray>\n";
00207         oss << "      </Points>\n";
00208 
00209         // elements: connectivity, offsets, types
00210         oss << "      <Cells>\n";
00211         oss << "        <DataArray type=\"Int32\" Name=\"connectivity\" format=\"ascii\">\n";
00212         k = 0; oss << "        ";
00213         nx = N[0];
00214         ny = N[1];
00215         nz = N[2];
00216         for (size_t n=0; n<nc; ++n)
00217         {
00218             int K =  n / (nx*ny);
00219             int J = (n % (nx*ny)) / nx;
00220             int I = (n % (nx*ny)) % nx;
00221             int C[8][3] = {{I  ,  J  ,  K},
00222                            {I+1,  J  ,  K},
00223                            {I+1,  J+1,  K},
00224                            {I  ,  J+1,  K},
00225                            {I  ,  J  ,  K+1},
00226                            {I+1,  J  ,  K+1},
00227                            {I+1,  J+1,  K+1},
00228                            {I  ,  J+1,  K+1}};
00229             oss << "  ";
00230             for (size_t j=0; j<8; ++j) oss << C[j][0] + C[j][1]*(N[0]+1) + C[j][2]*(N[0]+1)*(N[1]+1) << " ";
00231             k++;
00232             VTU_NEWLINE (n,k,nc,nimax/8,oss);
00233         }
00234         oss << "        </DataArray>\n";
00235         oss << "        <DataArray type=\"Int32\" Name=\"offsets\" format=\"ascii\">\n";
00236         k = 0; oss << "        ";
00237         size_t offset = 0;
00238         for (size_t i=0; i<nc; ++i)
00239         {
00240             offset += 8;
00241             oss << (k==0?"  ":" ") << offset;
00242             k++;
00243             VTU_NEWLINE (i,k,nc,nimax,oss);
00244         }
00245         oss << "        </DataArray>\n";
00246         oss << "        <DataArray type=\"UInt8\" Name=\"types\" format=\"ascii\">\n";
00247         k = 0; oss << "        ";
00248         for (size_t i=0; i<nc; ++i)
00249         {
00250             oss << (k==0?"  ":" ") << 12; // VTK_HEXAHEDRON
00251             k++;
00252             VTU_NEWLINE (i,k,nc,nimax,oss);
00253         }
00254         oss << "        </DataArray>\n";
00255         oss << "      </Cells>\n";
00256 
00257         // data -- elements
00258         oss << "      <CellData Scalars=\"TheScalars\">\n";
00259         oss << "        <DataArray type=\"Int32\" Name=\"" << "celltype" << "\" NumberOfComponents=\"1\" format=\"ascii\">\n";
00260         k = 0; oss << "        ";
00261         for (size_t i=0; i<nc; ++i)
00262         {
00263             oss << (k==0?"  ":" ") << Id2Type[i];
00264             k++;
00265             VTU_NEWLINE (i,k,nc,nimax,oss);
00266         }
00267         oss << "        </DataArray>\n";
00268         oss << "        <DataArray type=\"Int32\" Name=\"" << "proc" << "\" NumberOfComponents=\"1\" format=\"ascii\">\n";
00269         k = 0; oss << "        ";
00270         int max_neigh_procs = 0;
00271         for (size_t i=0; i<nc; ++i)
00272         {
00273             if (Id2NeighProcs[i].Size()>(size_t)max_neigh_procs) max_neigh_procs = Id2NeighProcs[i].Size();
00274             oss << (k==0?"  ":" ") << Id2Proc[i];
00275             k++;
00276             VTU_NEWLINE (i,k,nc,nimax,oss);
00277         }
00278         oss << "        </DataArray>\n";
00279         if (max_neigh_procs>0)
00280         {
00281             oss << "        <DataArray type=\"Int32\" Name=\"" << "neighproc" << "\" NumberOfComponents=\""<<max_neigh_procs<<"\" format=\"ascii\">\n";
00282             k = 0; oss << "        ";
00283             for (size_t i=0; i<nc; ++i)
00284             {
00285                 oss << (k==0?"  ":" ");
00286                 for (int j=0; j<max_neigh_procs; ++j)
00287                 {
00288                     if (j>static_cast<int>(Id2NeighProcs[i].Size()-1)) oss << -1 << " ";
00289                     else oss << Id2NeighProcs[i][j] << " ";
00290                 }
00291                 k++;
00292                 VTU_NEWLINE (i,k,nc,nimax,oss);
00293             }
00294             oss << "        </DataArray>\n";
00295         }
00296         oss << "      </CellData>\n";
00297 
00298         // Bottom
00299         oss << "    </Piece>\n";
00300         oss << "  </UnstructuredGrid>\n";
00301         oss << "</VTKFile>" << std::endl;
00302 
00303         // Write to file
00304         String fn(FileKey); fn.append(".vtu");
00305         std::ofstream of(fn.CStr(), std::ios::out);
00306         of << oss.str();
00307         of.close();
00308     }
00309 }
00310 
00311 inline int ParaGrid3D::FindCell (Vec3_t const & X) const
00312 {
00313     // cell
00314     int I = static_cast<int>((X(0)-L[0])/D(0));
00315     int J = static_cast<int>((X(1)-L[2])/D(1));
00316     int K = static_cast<int>((X(2)-L[4])/D(2));
00317     int n = I + J*N[0] + K*N[0]*N[1];
00318 
00319     // check
00320     if (n<0) throw new Fatal("ParaGrid3D::FindCellId:: Point X=(%g,%g,%g) is outside grid: N=(%d,%d,%d), L=[x:(%g,%g) y:(%g,%g) z:(%g,%g)]", X(0),X(1),X(2), N[0],N[1],N[2], L[0],L[1],L[2],L[3],L[4],L[5]);
00321     return n;
00322 }
00323 
00324 inline void ParaGrid3D::FindCells (Vec3_t const & X, double R, int Ids[8]) const
00325 {
00326     // coordinates of corners
00327     double xa=X(0)-R;   double xb=X(0)+R;
00328     double ya=X(1)-R;   double yb=X(1)+R;
00329     double za=X(2)-R;   double zb=X(2)+R;
00330 
00331     // check
00332     if (xa<L[0] || xb>L[1] ||
00333         ya<L[2] || yb>L[3] ||
00334         za<L[4] || zb>L[5]) throw new Fatal("ParaGrid3D::FindCellsIds: Corner of cube centered at (%g,%g,%g) with inner radius=%g is outside limits of domain (N=(%d,%d,%d), L=[x:(%g,%g) y:(%g,%g) z:(%g,%g)])", X(0),X(1),X(2),R, N[0],N[1],N[2], L[0],L[1],L[2],L[3],L[4],L[5]);
00335 
00336     // corners
00337     double C[8][3] = {{xa,  ya,  za},
00338                       {xb,  ya,  za},
00339                       {xa,  yb,  za},
00340                       {xb,  yb,  za},
00341                       {xa,  ya,  zb},
00342                       {xb,  ya,  zb},
00343                       {xa,  yb,  zb},
00344                       {xb,  yb,  zb}};
00345 
00346     // find cells ids
00347     for (size_t i=0; i<8; ++i)
00348     {
00349         // cell touched by corner
00350         int I = static_cast<int>((C[i][0]-L[0])/D(0));
00351         int J = static_cast<int>((C[i][1]-L[2])/D(1));
00352         int K = static_cast<int>((C[i][2]-L[4])/D(2));
00353         Ids[i] = I + J*N[0] + K*N[0]*N[1];
00354 
00355         // check
00356         if (Ids[i]<0) throw new Fatal("ParaGrid3D::FindCellsIds:: __internal_error: cell id (%d) cannot be negative",Ids[i]);
00357     }
00358 }
00359 
00360 #endif // MECHSYS_PARAGRID3D_H
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines