![]() |
MechSys
1.0
Computing library for simulations in continuum and discrete mechanics
|
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