![]() |
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, Raul Durand * 00004 * Copyright (C) 2009 Sergio Galindo * 00005 * * 00006 * This program is free software: you can redistribute it and/or modify * 00007 * it under the terms of the GNU General Public License as published by * 00008 * the Free Software Foundation, either version 3 of the License, or * 00009 * any later version. * 00010 * * 00011 * This program is distributed in the hope that it will be useful, * 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00014 * GNU General Public License for more details. * 00015 * * 00016 * You should have received a copy of the GNU General Public License * 00017 * along with this program. If not, see <http://www.gnu.org/licenses/> * 00018 ************************************************************************/ 00019 00020 #ifndef MECHSYS_MESH_H 00021 #define MECHSYS_MESH_H 00022 00023 // STL 00024 #include <iostream> 00025 #include <fstream> 00026 #include <sstream> 00027 #include <cfloat> // for DBL_EPSILON 00028 #include <cstdarg> // for va_list, va_start, va_end 00029 #include <cstdlib> // for atoi 00030 #include <map> 00031 00032 // Boost 00033 #include <boost/tuple/tuple_io.hpp> 00034 #include <boost/tuple/tuple_comparison.hpp> 00035 00036 // ParMETIS 00037 #if defined(HAS_PARMETIS) && defined(HAS_MPI) 00038 #include <mpi.h> 00039 extern "C" { 00040 #include <metis.h> 00041 } 00042 #endif 00043 00044 // MechSys 00045 #include <mechsys/util/array.h> 00046 #include <mechsys/util/fatal.h> 00047 #include <mechsys/util/util.h> 00048 #include <mechsys/util/numstreams.h> 00049 #include <mechsys/linalg/matvec.h> 00050 #include <mechsys/vtkcelltype.h> 00051 00052 namespace Mesh 00053 { 00054 00055 #ifndef VTU_NEWLINE_DEFINED 00056 #define VTU_NEWLINE_DEFINED 00057 #define VTU_NEWLINE(I,K,N,KMAX,OF) if (K>KMAX) { OF<<(I<N-1?"\n ":"\n"); K=0; } else if (I==N-1) { OF<<"\n"; } 00058 #endif 00059 00060 #define NOEDGE {-1,-1,-1} 00061 #define NOFACE {-1,-1,-1,-1} 00062 #define NOEDGES {NOEDGE,NOEDGE,NOEDGE,NOEDGE} 00063 #define NOEDGES3D {NOEDGE,NOEDGE,NOEDGE,NOEDGE,NOEDGE,NOEDGE,NOEDGE,NOEDGE,NOEDGE,NOEDGE,NOEDGE,NOEDGE} 00064 #define NOFACES {NOFACE,NOFACE,NOFACE,NOFACE,NOFACE,NOFACE} 00065 00066 size_t MaxNVerts2D = 8; 00067 size_t NVertsToNEdges2D[] = {0,0,0,3,4,0,3,0,4}; 00068 size_t NVertsToNVertsPerEdge2D[] = {0,0,0,2,2,0,3,0,3}; 00069 int NVertsToEdge2D[][4/*edges at most*/][3/*verts per edge at most*/]= 00070 { 00071 NOEDGES,NOEDGES,NOEDGES, // 0,1,2 verts 00072 {{0,1,-1},{1,2,-1},{2,0,-1},NOEDGE}, // 3 verts => TRIANGLE 00073 {{0,1,-1},{1,2,-1},{2,3,-1},{3,0,-1}}, // 4 verts => QUAD 00074 NOEDGES, // 5 verts 00075 {{0,1,3},{1,2,4},{2,0,5},NOEDGE}, // 6 verts => O2 TRIANGLE 00076 NOEDGES, // 7 verts 00077 {{0,1,4},{1,2,5},{2,3,6},{3,0,7}} // 8 verts => O2 QUAD 00078 }; 00079 00080 size_t MaxNVerts3D = 20; 00081 size_t NVertsToNFaces3D[] = {0,0,0,0, 4, 0,0,0, 6, 0, 4, 0,0,0,0,0,0,0,0,0, 6}; 00082 size_t NVertsToNVertsPerFace3D[] = {0,0,0,0, 3, 0,0,0, 4, 0, 3, 0,0,0,0,0,0,0,0,0, 4}; // disregarding O2 nodes 00083 int NVertsToFace3D[][6/*faces at most*/][4/*verts per face at most*/]= 00084 { 00085 NOFACES,NOFACES,NOFACES,NOFACES, // 0,1,2,3 verts 00086 {{0,3,2,-1},{0,1,3,-1},{0,2,1,-1},{1,2,3,-1},NOFACE,NOFACE}, // 4 verts => TETRA 00087 NOFACES,NOFACES,NOFACES, // 5,6,7 verts 00088 {{0,4,7,3},{1,2,6,5},{0,1,5,4},{2,3,7,6},{0,3,2,1},{4,5,6,7}}, // 8 verts => HEX 00089 NOFACES, // 9 verts 00090 {{0,3,2,-1},{0,1,3,-1},{0,2,1,-1},{1,2,3,-1},NOFACE,NOFACE}, // 10 verts => O2 TETRA 00091 NOFACES,NOFACES,NOFACES,NOFACES,NOFACES,NOFACES,NOFACES,NOFACES,NOFACES, // 11,12,13,14,15,16,17,18,19 verts 00092 {{0,4,7,3},{1,2,6,5},{0,1,5,4},{2,3,7,6},{0,3,2,1},{4,5,6,7}} // 20 verts => O2 HEX 00093 }; 00094 00095 size_t NVertsToNEdges3D[] = {0,0,0,0, 6, 0,0,0, 12, 0, 6, 0,0,0,0,0,0,0,0,0, 12}; 00096 int NVertsToEdge3D[][12/*edges at most*/][3/*verts per edge at most*/]= 00097 { 00098 NOEDGES3D,NOEDGES3D,NOEDGES3D,NOEDGES3D, // 0,1,2,3 verts 00099 {{0,1,-1},{1,2,-1},{2,0,-1},{0,3,-1},{1,3,-1},{2,3,-1},NOEDGE,NOEDGE,NOEDGE,NOEDGE,NOEDGE,NOEDGE}, // 4 verts => TETRA 00100 NOEDGES3D,NOEDGES3D,NOEDGES3D, // 5,6,7 verts 00101 {{0,1,-1},{1,2,-1},{2,3,-1},{3,0,-1},{4,5,-1},{5,6,-1},{6,7,-1},{7,4,-1},{0,4,-1},{1,5,-1},{2,6,-1},{3,7,-1}}, // 8 verts => HEX 00102 NOEDGES3D, // 9 verts 00103 {{0,1,4},{1,2,5},{2,0,6},{0,3,7},{1,3,8},{2,3,9},NOEDGE,NOEDGE,NOEDGE,NOEDGE,NOEDGE,NOEDGE}, // 10 verts => O2 TETRA 00104 NOEDGES3D,NOEDGES3D,NOEDGES3D,NOEDGES3D,NOEDGES3D,NOEDGES3D,NOEDGES3D,NOEDGES3D,NOEDGES3D, // 11,12,13,14,15,16,17,18,19 verts 00105 {{0,1,8},{1,2,9},{2,3,10},{3,0,11},{4,5,12},{5,6,13},{6,7,14},{7,4,15},{0,4,16},{1,5,17},{2,6,18},{3,7,19}} // 20 verts => O2 HEX 00106 }; 00107 00108 size_t NVertsToGeoNVerts2D[] = {-1, // 0 verts 00109 -1, // 1 vert 00110 2, // 2 verts 00111 3, // 3 00112 4, // 4 00113 -1, // 5 00114 3, // 6 00115 -1, // 7 00116 4, // 8 00117 -1,-1,-1,-1,-1,-1, // 9,10,11,12,13,14 00118 3}; // 15 00119 00120 size_t NVertsToGeoNVerts3D[] = {-1, // 0 verts 00121 -1, // 1 vert 00122 2, // 2 verts 00123 -1, // 3 00124 4, // 4 00125 -1, // 5 00126 -1, // 6 00127 -1, // 7 00128 8, // 8 00129 -1, // 9 00130 4, // 10 00131 -1,-1,-1,-1,-1,-1,-1,-1,-1, // 11,12,13,14,15,16,17,18,19 00132 8}; // 20 00133 00134 #define BRYKEY(num_verts,idx_cell,idx_bry) \ 00135 int vert_a, vert_b, vert_c=-1, vert_d=-1; \ 00136 if (NDim==2) \ 00137 { \ 00138 vert_a = Cells[idx_cell]->V[NVertsToEdge2D[num_verts][idx_bry][0]]->ID; \ 00139 vert_b = Cells[idx_cell]->V[NVertsToEdge2D[num_verts][idx_bry][1]]->ID; \ 00140 Util::Sort (vert_a,vert_b); \ 00141 } \ 00142 else \ 00143 { \ 00144 vert_a = Cells[idx_cell]->V[NVertsToFace3D[num_verts][idx_bry][0]]->ID; \ 00145 vert_b = Cells[idx_cell]->V[NVertsToFace3D[num_verts][idx_bry][1]]->ID; \ 00146 vert_c = Cells[idx_cell]->V[NVertsToFace3D[num_verts][idx_bry][2]]->ID; \ 00147 if (NVertsToNVertsPerFace3D[num_verts]>3) \ 00148 vert_d = Cells[idx_cell]->V[NVertsToFace3D[num_verts][idx_bry][3]]->ID; \ 00149 Util::Sort (vert_a,vert_b,vert_c,vert_d); \ 00150 } \ 00151 BryKey_t brykey(vert_a,vert_b,vert_c,vert_d); 00152 00153 #undef NOEDGE 00154 #undef NOFACE 00155 #undef NOEDGES 00156 #undef NOFACES 00157 00158 struct Cell; 00159 00160 struct Share 00161 { 00162 Cell * C; 00163 size_t N; 00164 }; 00165 00166 struct Vertex 00167 { 00168 size_t ID; 00169 int Tag; 00170 Vec3_t C; 00171 Array<Share> Shares; 00172 Array<int> PartIDs; 00173 }; 00174 00175 typedef std::map<int,int> BryTag_t; 00176 typedef boost::tuple<int,int,int,int> BryKey_t; 00177 typedef std::pair<int,Cell*> NeighDat_t; 00178 typedef std::map<BryKey_t, NeighDat_t> Neighs_t; 00179 typedef std::map<BryKey_t, Array<NeighDat_t> > BryCell_t; 00180 typedef std::map<Vertex*,Array<Vertex*> > Pin_t; 00181 00182 struct Cell 00183 { 00184 size_t ID; 00185 int Tag; 00186 Array<Vertex*> V; 00187 BryTag_t BryTags; 00188 Neighs_t Neighs; 00189 int PartID; 00190 }; 00191 00192 inline int CellGetBryTag(int iSide, Cell const *c) 00193 { 00194 BryTag_t::const_iterator p = c->BryTags.find(iSide); 00195 if (p==c->BryTags.end()) return 0; 00196 else return p->second; 00197 } 00198 00199 inline int CellGetNeigh(int iSide, Cell const *c) 00200 { 00201 for (Neighs_t::const_iterator p=c->Neighs.begin(); p!=c->Neighs.end(); ++p) 00202 { 00203 if (iSide==p->second.first) return p->second.second->ID; 00204 } 00205 return -1; // no neighbour 00206 } 00207 00208 class Generic 00209 { 00210 public: 00211 // Constructor 00212 Generic (int TheNDim) : NDim(TheNDim), IsShell(false), WithInfo(true) {} 00213 00214 // Destructor 00215 virtual ~Generic () { Erase(); } 00216 00217 // Set methods 00218 void ReadMesh (char const * FileKey, bool IsShell=false); 00219 void SetSize (size_t NumVerts, size_t NumCells); 00220 void SetVert (int iVert, int Tag, double X, double Y, double Z=0); 00221 void SetCell (int iCell, int Tag, Array<int> const & Con); 00222 void SetBryTag (int iCell, int iEdgeFace, int Tag); 00223 void FindNeigh (); 00224 void GenO2Verts (); 00225 void Erase (); 00226 00227 // Tag methods (can be called after the mesh is created) 00228 void TagVertex (int Tag, int Idx); 00229 int TagVertex (int Tag, double x, double y, double z=0.0, double Tol=1.0e-5); 00230 void TagVertsLine (int Tag, double x0, double y0, double AlpDeg, double Tol=1.0e-5); 00231 void TagSegsLine (int Tag, double x0, double y0, double AlpDeg, double Tol=1.0e-5); 00232 void TagHorzSegs (int Tag, double y, double xMin, double xMax, double Tol=1.0e-5); 00233 void GroundTags (int LTag=-10, int RTag=-10, int BTag=-20, double Tol=1.0e-5); 00234 00235 // Push methods 00236 int PushVert (int Tag, double X, double Y, double Z=0); 00237 int PushCell (int Tag, Array<int> const & Con); 00238 00239 // Method to extend mesh 00240 void AddLinCells (Array<int> const & IDsOrTags); 00241 void AddPin (int VertexIdOrTag); 00242 00243 // Methods 00244 void Check (double Tol=1.0e-3) const; 00245 void WriteVTU (char const * FileKey, int VolSurfOrBoth=0) const; 00246 void WriteMPY (char const * FileKey, bool WithTags=true, bool WithIDs=true, bool WithShares=false, 00247 char const * Extra=NULL) const; 00248 void WriteJSON(char const * FileKey) const; 00249 00250 // Auxiliar methods 00251 int FindVert (int Tag) const; 00252 void BoundingBox (Vec3_t & Min, Vec3_t & Max) const; 00253 void ThrowError (std::istringstream & iss, char const * Message) const; 00254 void Adjacency (Array<int> & Xadj, Array<int> & Adjncy, bool Full=false); 00255 void PartDomain (int NParts, bool Full=false, int * Part=NULL); 00256 00257 // Other methods 00258 void GenGroundSG (Array<double> const & X, Array<double> const & Y, double FootingLx=-1); 00259 void GenGroundSG (size_t Nx, size_t Ny, double Dx=1.0, double Dy=1.0); 00260 void GenSector (size_t Nr, size_t Nth, double r, double R, double ThetaRad); 00261 void Quad4ToTri3 (bool BackDiagonal=true); 00262 void Quad8ToTri6 (bool BackDiagonal=true); 00263 void Tri6ToTri15 (); 00264 void Tri3ToTri6 (); 00265 void Refine (); 00266 void Tri6Shape (double r, double s, Vec_t & N) const; 00267 00268 // Data 00269 int NDim; 00270 bool IsShell; 00271 Array<Vertex*> Verts; 00272 Array<Cell*> Cells; 00273 Array<Vertex*> TgdVerts; 00274 Array<Cell*> TgdCells; 00275 BryCell_t Bry2Cells; 00276 Pin_t Pins; 00277 bool WithInfo; 00278 00279 #ifdef USE_BOOST_PYTHON 00280 void PySetCell (int iCell, int Tag, BPy::list const Con) { SetCell (iCell, Tag, Array<int>(Con)); } 00281 void PyAddLinCells (BPy::list const & IDsOrTags) { AddLinCells (Array<int>(IDsOrTags)); } 00282 void PyGetVertsEdges (BPy::list & V, BPy::list & E) const; 00283 #endif 00284 }; 00285 00286 00288 00289 00290 std::ostream & operator<< (std::ostream & os, BryKey_t const & BK) 00291 { 00292 os << "(" << boost::get<0>(BK) << "," << boost::get<1>(BK) << "," << boost::get<2>(BK) << "," << boost::get<3>(BK) << ")"; 00293 return os; 00294 } 00295 00296 std::ostream & operator<< (std::ostream & os, Generic const & M) 00297 { 00298 // verts 00299 os << "V=["; 00300 for (size_t i=0; i<M.Verts.Size(); ++i) 00301 { 00302 if (M.Verts[i]==NULL) throw new Fatal("Mesh::operator<<: Vertex %d was not defined",i); 00303 os << "[" << Util::_4 << M.Verts[i]->ID; 00304 os << "," << Util::_4 << M.Verts[i]->Tag; 00305 os << "," << Util::_8s << M.Verts[i]->C(0); 00306 os << "," << Util::_8s << M.Verts[i]->C(1); if (M.NDim==3) 00307 os << "," << Util::_8s << M.Verts[i]->C(2); 00308 if (i==M.Verts.Size()-1) os << "]]\n"; 00309 else os << "],\n "; 00310 } 00311 00312 // cells 00313 os << "\nC=["; 00314 for (size_t i=0; i<M.Cells.Size(); ++i) 00315 { 00316 if (M.Cells[i]==NULL) throw new Fatal("Mesh::operator<<: Cell %d was not defined",i); 00317 os << "[" << Util::_4 << M.Cells[i]->ID; 00318 os << "," << Util::_4 << M.Cells[i]->Tag; 00319 os << ", ["; 00320 for (size_t j=0; j<M.Cells[i]->V.Size(); ++j) 00321 { 00322 os << M.Cells[i]->V[j]->ID; 00323 if (j!=M.Cells[i]->V.Size()-1) os << ","; 00324 } 00325 os << "], {"; 00326 size_t k = 0; 00327 for (BryTag_t::const_iterator p=M.Cells[i]->BryTags.begin(); p!=M.Cells[i]->BryTags.end(); ++p) 00328 { 00329 os << p->first << ":" << p->second; 00330 if (k!=M.Cells[i]->BryTags.size()-1) os << ","; 00331 k++; 00332 } 00333 os << "}"; 00334 os << ", {"; 00335 for (Neighs_t::const_iterator p=M.Cells[i]->Neighs.begin(); p!=M.Cells[i]->Neighs.end(); ++p) 00336 { 00337 if (p!=M.Cells[i]->Neighs.begin()) os << ","; 00338 os << "(" << boost::get<0>(p->first); 00339 os << "," << boost::get<1>(p->first); 00340 os << "," << boost::get<2>(p->first); 00341 os << "," << boost::get<3>(p->first); 00342 os << "):"; 00343 os << "[" << p->second.first << "," << p->second.second->ID << "]"; 00344 } 00345 os << "}"; 00346 if (i==M.Cells.Size()-1) os << "]]\n"; 00347 else os << "],\n "; 00348 } 00349 return os; 00350 } 00351 00352 inline int Generic::FindVert (int Tag) const 00353 { 00354 for (size_t i=0; i<TgdVerts.Size(); ++i) 00355 { 00356 if (TgdVerts[i]->Tag==Tag) return TgdVerts[i]->ID; 00357 } 00358 return -1; 00359 } 00360 00361 inline void Generic::BoundingBox (Vec3_t & Min, Vec3_t & Max) const 00362 { 00363 Min = Verts[0]->C(0), Verts[0]->C(1), Verts[0]->C(2); 00364 Max = Verts[0]->C(0), Verts[0]->C(1), Verts[0]->C(2); 00365 for (size_t i=1; i<Verts.Size(); ++i) 00366 { 00367 if (Verts[i]->C(0)<Min(0)) Min(0) = Verts[i]->C(0); 00368 if (Verts[i]->C(1)<Min(1)) Min(1) = Verts[i]->C(1); 00369 if (Verts[i]->C(2)<Min(2)) Min(2) = Verts[i]->C(2); 00370 if (Verts[i]->C(0)>Max(0)) Max(0) = Verts[i]->C(0); 00371 if (Verts[i]->C(1)>Max(1)) Max(1) = Verts[i]->C(1); 00372 if (Verts[i]->C(2)>Max(2)) Max(2) = Verts[i]->C(2); 00373 } 00374 } 00375 00376 inline void Generic::ThrowError (std::istringstream & iss, char const * Message) const 00377 { 00378 size_t num = 1+iss.tellg(); 00379 String str(iss.str()); 00380 str.resize (num); 00381 size_t pos = str.find(" "); 00382 while (pos!=String::npos) 00383 { 00384 str.replace (pos,1,""); 00385 pos = str.find(" ",pos+1); 00386 } 00387 throw new Fatal("Generic::ReadMesh: Mesh file format invalid\n %s\n %s",Message,str.CStr()); 00388 } 00389 00390 inline void Generic::Adjacency (Array<int> & Xadj, Array<int> & Adjncy, bool Full) 00391 { 00392 Xadj.Push (0); 00393 if (Full) 00394 { 00395 for (size_t i=0; i<Cells.Size(); ++i) 00396 { 00397 size_t nv = (NDim==2 ? NVertsToGeoNVerts2D[Cells[i]->V.Size()] : NVertsToGeoNVerts3D[Cells[i]->V.Size()]); 00398 Array<Cell*> neigh; 00399 for (size_t j=0; j<nv; ++j) 00400 { 00401 Array<Share> const & sha = Cells[i]->V[j]->Shares; 00402 for (size_t k=0; k<sha.Size(); ++k) 00403 { 00404 if (sha[k].C!=Cells[i]) 00405 { 00406 if (neigh.Find(sha[k].C)<0) 00407 { 00408 neigh .Push (sha[k].C); 00409 Adjncy.Push (sha[k].C->ID); 00410 } 00411 } 00412 } 00413 } 00414 Xadj.Push (Xadj.Last()+neigh.Size()); 00415 } 00416 } 00417 else 00418 { 00419 FindNeigh (); 00420 for (size_t i=0; i<Cells.Size(); ++i) 00421 { 00422 for (Neighs_t::const_iterator p=Cells[i]->Neighs.begin(); p!=Cells[i]->Neighs.end(); ++p) 00423 { 00424 Adjncy.Push (p->second.second->ID); 00425 } 00426 Xadj.Push (Xadj.Last()+Cells[i]->Neighs.size()); 00427 } 00428 } 00429 } 00430 00431 inline void Generic::PartDomain (int NParts, bool Full, int * Part) 00432 { 00433 // allocate/set array with partition ids 00434 int n = Cells.Size(); 00435 bool del_part = false; 00436 int * part; 00437 if (Part==NULL) 00438 { 00439 part = new int [n]; 00440 del_part = true; 00441 if (NParts==1) for (int i=0; i<n; ++i) part[i] = 0; 00442 } 00443 else part = Part; 00444 00445 // partition domain 00446 if (Part==NULL && NParts>1) 00447 { 00448 #if defined(HAS_PARMETIS) && defined(HAS_MPI) 00449 Array<int> Xadj, Adjncy; 00450 Adjacency (Xadj, Adjncy, Full); 00451 int wgtflag = 0; // No weights 00452 int numflag = 0; // zero numbering 00453 int options[5] = {0,0,0,0,0}; 00454 int edgecut; 00455 if (NParts<8) METIS_PartGraphRecursive (&n, Xadj.GetPtr(), Adjncy.GetPtr(), NULL, NULL, &wgtflag, &numflag, &NParts, options, &edgecut, part); 00456 else METIS_PartGraphKway (&n, Xadj.GetPtr(), Adjncy.GetPtr(), NULL, NULL, &wgtflag, &numflag, &NParts, options, &edgecut, part); 00457 #else 00458 throw new Fatal("Generic::PartDomain: This method requires ParMETIS and MPI (if Part array is not provided)"); 00459 #endif 00460 } 00461 00462 // find domains of elements 00463 for (int i=0; i<n; ++i) Cells[i]->PartID = part[i]; 00464 if (del_part) delete [] part; 00465 00466 // find domais of nodes 00467 for (size_t i=0; i<Verts.Size(); ++i) 00468 { 00469 Array<Share> const & sha = Verts[i]->Shares; 00470 for (size_t k=0; k<sha.Size(); ++k) 00471 { 00472 if (Verts[i]->PartIDs.Find(sha[k].C->PartID)<0) Verts[i]->PartIDs.Push (sha[k].C->PartID); 00473 } 00474 } 00475 } 00476 00477 inline void Generic::ReadMesh (char const * FileKey, bool Shell) 00478 { 00479 // shell mesh ? 00480 IsShell = Shell; 00481 00482 // open file 00483 String fn(FileKey); fn.append(".mesh"); 00484 std::fstream fil(fn.CStr(), std::ios::in); 00485 if (!fil.is_open()) throw new Fatal("Generic::ReadMesh: Could not open file < %s >",fn.CStr()); 00486 00487 String line, str, comma, colon, buf; 00488 size_t vid, cid, bid; // vertex id, cell id, boundary id 00489 int vtag, ctag, btag; // vertex tag, cell tag, boundary tag 00490 double x,y,z=0.0; 00491 bool reading_verts = false; 00492 bool reading_cells = false; 00493 bool verts_read = false; 00494 while (!fil.eof()) 00495 { 00496 // read line 00497 std::getline (fil,line); 00498 00499 // add spaces around: = [ ] , 00500 size_t pos; 00501 pos=line.find("="); while (pos!=String::npos) { line.replace(pos,1," = "); pos=line.find("=",pos+3); } 00502 pos=line.find("["); while (pos!=String::npos) { line.replace(pos,1," [ "); pos=line.find("[",pos+3); } 00503 pos=line.find("]"); while (pos!=String::npos) { line.replace(pos,1," ] "); pos=line.find("]",pos+3); } 00504 pos=line.find(","); while (pos!=String::npos) { line.replace(pos,1," , "); pos=line.find(",",pos+3); } 00505 pos=line.find("{"); while (pos!=String::npos) { line.replace(pos,1," { "); pos=line.find("{",pos+3); } 00506 pos=line.find("}"); while (pos!=String::npos) { line.replace(pos,1," } "); pos=line.find("}",pos+3); } 00507 pos=line.find(":"); while (pos!=String::npos) { line.replace(pos,1," : "); pos=line.find(":",pos+3); } 00508 00509 // parse 00510 std::istringstream iss(line); 00511 while (iss>>str) 00512 { 00513 if (str=="V") 00514 { 00515 iss>>str>>str>>str; // = [ [ 00516 reading_cells = false; 00517 reading_verts = true; 00518 } 00519 else if (str=="C") 00520 { 00521 iss>>str>>str>>str; // = [ [ 00522 reading_verts = false; 00523 reading_cells = true; 00524 } 00525 if (reading_verts) 00526 { 00527 if (str!="[") ThrowError (iss, "Verts: opening bracket '[' lacking"); 00528 while (iss>>vid) 00529 { 00530 // read vertex data 00531 iss >> comma >> vtag >> comma >> x >> comma >> y; 00532 if (NDim==3) iss >> comma >> z; 00533 iss >> str; 00534 if (str!="]") ThrowError (iss, "Verts: closing brackets ']' lacking"); 00535 iss >> str; 00536 if (str=="]") { reading_verts = false; verts_read = true; } 00537 else if (str!=",") ThrowError (iss, "Verts: last vertex: ',' or ']' lacking"); 00538 00539 // allocate vertex 00540 int new_vid = PushVert (vtag, x, y, z); 00541 if (new_vid!=(int)vid) throw new Fatal("Generic::ReadMesh: Verts IDs must be sequential. Vertex ID (%d) must be equal to (%d)",vid,new_vid); 00542 00543 break; 00544 } 00545 } 00546 if (reading_cells) 00547 { 00548 if (!verts_read) throw new Fatal("Generic::ReadMesh: List with vertices data must come before list with cells data"); 00549 if (str!="[") ThrowError (iss, "Cells: opening brackets '[' lacking"); 00550 while (iss>>cid) 00551 { 00552 // read cell data 00553 iss >> comma >> ctag >> comma >> str; 00554 if (str!="[") ThrowError (iss, "Cells: opening brackets of connectivity '[' lacking"); 00555 00556 // read connectivity 00557 Array<int> con; 00558 while (iss>>vid) 00559 { 00560 con.Push (Verts[vid]->ID); 00561 iss >> str; 00562 if (str=="]") break; 00563 else if (str!=",") ThrowError (iss, "Cells: closing brackets of connectivity: ',' or ']' lacking"); 00564 } 00565 00566 // allocate cell 00567 int new_cid = PushCell (ctag, con); 00568 if (new_cid!=(int)cid) throw new Fatal("Generic::ReadMesh: Cells IDs must be sequential. Cell ID (%d) must be equal to (%d)",cid,new_cid); 00569 00570 iss >> comma; 00571 iss >> str; 00572 if (str!="{") ThrowError (iss, "Cells: opening braces of bry tags '{' lacking"); 00573 00574 // read boundary tags 00575 while (iss>>str) 00576 { 00577 if (str=="}") break; 00578 else bid = atoi(str.CStr()); 00579 iss >> colon >> btag >> str; 00580 Cells[cid]->BryTags[bid] = btag; 00581 if (TgdCells.Find(Cells[cid])<0) TgdCells.Push (Cells[cid]); 00582 if (str=="}") break; 00583 else if (str!=",") ThrowError (iss, "Cells: closing braces of bry tags: ',' or '}' lacking"); 00584 } 00585 iss >> str; 00586 if (str!="]") ThrowError (iss, "Cells: closing brackets ']' lacking"); 00587 iss >> str; 00588 if (str=="]") reading_cells = false; 00589 else if (str!=",") ThrowError (iss, "Cells: last cell: ',' or ']' lacking"); 00590 00591 break; 00592 } 00593 } 00594 } 00595 } 00596 } 00597 00598 inline void Generic::SetSize (size_t NumVerts, size_t NumCells) 00599 { 00600 // erase previous mesh 00601 Erase (); 00602 00603 // nodes 00604 Verts.Resize (NumVerts); 00605 Verts.SetValues (NULL); 00606 TgdVerts.Resize (0); 00607 00608 // elements 00609 Cells.Resize (NumCells); 00610 Cells.SetValues (NULL); 00611 TgdCells.Resize (0); 00612 } 00613 00614 inline int Generic::PushVert (int Tag, double X, double Y, double Z) 00615 { 00616 Verts.Push (NULL); 00617 int i = static_cast<int>(Verts.Size())-1; 00618 SetVert (i, Tag, X, Y, Z); 00619 return i; 00620 } 00621 00622 inline void Generic::SetVert (int i, int Tag, double X, double Y, double Z) 00623 { 00624 // set Verts 00625 if (Verts[i]==NULL) Verts[i] = new Vertex; 00626 Verts[i]->ID = i; 00627 Verts[i]->Tag = Tag; 00628 Verts[i]->C = X, Y, Z; 00629 00630 // set TgdVerts 00631 if (Tag<0) TgdVerts.Push (Verts[i]); 00632 } 00633 00634 inline int Generic::PushCell (int Tag, Array<int> const & Con) 00635 { 00636 Cells.Push (NULL); 00637 int i = static_cast<int>(Cells.Size())-1; 00638 SetCell (i, Tag, Con); 00639 return i; 00640 } 00641 00642 inline void Generic::SetCell (int i, int Tag, Array<int> const & Con) 00643 { 00644 // number of vertices 00645 size_t NVerts = Con.Size(); 00646 00647 // check 00648 if (NDim==2) { if (NVertsToVTKCell2D[NVerts]<0) throw new Fatal("Generic::SetCell: In two-dimensions (NDim=2), Cell=%d with Tag=%d has invalid NVerts=%d",i,Tag,NVerts); } 00649 else { if (NVertsToVTKCell3D[NVerts]<0) throw new Fatal("Generic::SetCell: In three-dimensions (NDim=3), Cell=%d with Tag=%d has invalid NVerts=%d",i,Tag,NVerts); } 00650 00651 // set elems 00652 if (Cells[i]==NULL) Cells[i] = new Cell; 00653 Cells[i]->ID = i; 00654 Cells[i]->Tag = Tag; 00655 Cells[i]->V.Resize (NVerts); 00656 00657 // set connectivity 00658 double sum_z = 0.0; 00659 for (size_t j=0; j<NVerts; ++j) 00660 { 00661 int ivert = Con[j]; 00662 if (Verts[ivert]==NULL) throw new Fatal("Generic::SetCell: Vert=%d of Cell %d, %d could not be found. Vertices must be set (with SetVert) before calling this method",ivert,i,Tag); 00663 Cells[i]->V[j] = Verts[ivert]; 00664 Share sha = {Cells[i],j}; 00665 Verts[ivert]->Shares.Push (sha); 00666 if (NDim==3) sum_z += Verts[ivert]->C(2); 00667 } 00668 00669 // check connectivity (2D) 00670 if (NDim==2 && Cells[i]->V.Size()>2) 00671 { 00672 Vec3_t p0, p1, p2; 00673 for (size_t j=1; j<Cells[i]->V.Size()-1; ++j) 00674 { 00675 p0 = Cells[i]->V[j-1]->C - Cells[i]->V[j]->C; 00676 p1 = Cells[i]->V[j+1]->C - Cells[i]->V[j]->C; 00677 p2 = blitz::cross (p1,p0); 00678 if (p2(2)<0.0) throw new Fatal("Generic::SetCell: Order of vertices is incorrect (it must be counter-clockwise)"); 00679 if (fabs(p2(0))>1.0e-10 || fabs(p2(1)>1.0e-10)) throw new Fatal("Generic::SetCell: In 2D, all vertices of cells must lie on the x-y plane"); 00680 } 00681 } 00682 00683 // check 00684 if (NDim==3 and fabs(sum_z)<1.0e-10) throw new Fatal("Generic::SetCell: In 3D, the sum of all z coordinates of a Cell (%d, %d) must not be zero",i,Tag); 00685 } 00686 00687 inline void Generic::AddLinCells (Array<int> const & IDsOrTags) 00688 { 00689 if (NDim==3) throw new Fatal("Generic::AddLinCells: Method not available for 3D yet"); 00690 00691 bool with_tags = (IDsOrTags[0]<0 ? true : false); 00692 size_t nitems = (with_tags ? IDsOrTags.Size() : IDsOrTags.Size()/3); 00693 00694 size_t idx = 0; 00695 for (size_t i=0; i<nitems; ++i) 00696 { 00697 if (with_tags) // tag given 00698 { 00699 int etag = IDsOrTags[idx]; 00700 bool found = false; 00701 for (size_t j=0; j<TgdCells.Size(); ++j) 00702 { 00703 BryTag_t & eftags = TgdCells[j]->BryTags; 00704 for (BryTag_t::iterator p=eftags.begin(); p!=eftags.end(); ++p) 00705 { 00706 if (etag==p->second) 00707 { 00708 int eid = p->first; 00709 size_t nv = TgdCells[j]->V.Size(); 00710 int ivert0 = TgdCells[j]->V[NVertsToEdge2D[nv][eid][0]]->ID; 00711 int ivert1 = TgdCells[j]->V[NVertsToEdge2D[nv][eid][1]]->ID; 00712 int ivert2 = -1; 00713 if (NVertsToNVertsPerEdge2D[nv]>2) ivert2 = TgdCells[j]->V[NVertsToEdge2D[nv][eid][2]]->ID; 00714 if (ivert2<0) 00715 { 00716 Cells.Push (NULL); 00717 SetCell (Cells.Size()-1, etag, Array<int>(ivert0,ivert1)); 00718 } 00719 else 00720 { 00721 Cells.Push (NULL); SetCell (Cells.Size()-1, etag, Array<int>(ivert0,ivert2)); 00722 Cells.Push (NULL); SetCell (Cells.Size()-1, etag, Array<int>(ivert2,ivert1)); 00723 } 00724 found = true; 00725 TgdCells[j]->BryTags.erase(p); // delete edge tag from element 00726 break; 00727 } 00728 } 00729 } 00730 if (!found) throw new Fatal("Generic::SetLinCells: Could not find cell with edge with tag = %d",etag); 00731 idx++; 00732 } 00733 else // vertices IDs given 00734 { 00735 int ivert0 = IDsOrTags[idx]; idx++; 00736 int ivert1 = IDsOrTags[idx]; idx++; 00737 int tag = IDsOrTags[idx]; idx++; 00738 Cells.Push (NULL); 00739 SetCell (Cells.Size()-1, tag, Array<int>(ivert0,ivert1)); 00740 } 00741 } 00742 } 00743 00744 inline void Generic::AddPin (int VertIdOrTag) 00745 { 00746 // find vertex 00747 Vertex * vert = NULL; 00748 if (VertIdOrTag<0) // vertex tag given 00749 { 00750 bool found = false; 00751 for (size_t i=0; i<TgdVerts.Size(); ++i) 00752 { 00753 if (VertIdOrTag==TgdVerts[i]->Tag) 00754 { 00755 vert = Verts[TgdVerts[i]->ID]; 00756 found = true; 00757 break; 00758 } 00759 } 00760 if (!found) throw new Fatal("Mesh::AddPin: Could not find vertex with tag = %d", VertIdOrTag); 00761 } 00762 else vert = Verts[VertIdOrTag]; 00763 00764 // break linear elements connected to this vert 00765 Array<size_t> lins_to_disconnect; 00766 size_t idx_lin = 0; 00767 for (size_t i=0; i<vert->Shares.Size(); ++i) 00768 { 00769 Cell * cell = vert->Shares[i].C; 00770 if (cell->V.Size()==2) // cell sharing this vertex is a lin2 (linear cell with 2 vertices) 00771 { 00772 if (idx_lin>0) // do this for the second lin2 sharing this vertex on 00773 { 00774 // add new vertex 00775 Verts.Push (NULL); 00776 //SetVert (Verts.Size()-1, vert->Tag, vert->C(0)-idx_lin*0.5, vert->C(1)-idx_lin*0.5, vert->C(2)); 00777 SetVert (Verts.Size()-1, vert->Tag, vert->C(0), vert->C(1), vert->C(2)); 00778 00779 // set map of pins 00780 Pins[vert].Push (Verts[Verts.Size()-1]); 00781 00782 // set connectivity of lin2 00783 int idx = vert->Shares[i].N; // local vertex ID 00784 cell->V[idx] = Verts[Verts.Size()-1]; 00785 Share sha = {cell,idx}; 00786 Verts[Verts.Size()-1]->Shares.Push (sha); 00787 00788 // set this lin2 to be disconnected from vert 00789 lins_to_disconnect.Push (i); 00790 } 00791 idx_lin++; 00792 } 00793 } 00794 if (idx_lin<2) throw new Fatal("Mesh::AddPin: Vertex %d (%d) must be connected to at least two linear elements",vert->ID,vert->Tag); 00795 00796 // disconnect lins from vert 00797 Array<Share> old_shares(vert->Shares); 00798 vert->Shares.Resize (vert->Shares.Size()-lins_to_disconnect.Size()); 00799 size_t k = 0; 00800 for (size_t i=0; i<old_shares.Size(); ++i) 00801 { 00802 if (lins_to_disconnect.Find(i)<0) 00803 { 00804 vert->Shares[k].C = old_shares[i].C; 00805 vert->Shares[k].N = old_shares[i].N; 00806 k++; 00807 } 00808 } 00809 } 00810 00811 inline void Generic::SetBryTag (int i, int iEdgeFace, int Tag) 00812 { 00813 if (Tag<0) 00814 { 00815 if (Cells[i]==NULL) throw new Fatal("Generic::SetBryTag: This method must be called after SetCell which allocates Cells"); 00816 Cells[i]->BryTags[iEdgeFace] = Tag; 00817 TgdCells.XPush (Cells[i]); 00818 } 00819 } 00820 00821 inline void Generic::FindNeigh () 00822 { 00823 // build Bry2Cells map 00824 Bry2Cells.clear(); 00825 for (size_t i=0; i<Cells.Size(); ++i) 00826 { 00827 size_t nverts = Cells[i]->V.Size(); 00828 size_t nbrys = (NDim==2 ? NVertsToNEdges2D[nverts] : NVertsToNFaces3D[nverts]); 00829 for (size_t j=0; j<nbrys; ++j) 00830 { 00831 BRYKEY(nverts,i,j) 00832 NeighDat_t neigh_dat(j,Cells[i]); 00833 Bry2Cells[brykey].Push (neigh_dat); 00834 } 00835 } 00836 00837 // set neighbours information in cells 00838 for (size_t i=0; i<Cells.Size(); ++i) 00839 { 00840 Cells[i]->Neighs.clear(); 00841 size_t nverts = Cells[i]->V.Size(); 00842 size_t nbrys = (NDim==2 ? NVertsToNEdges2D[nverts] : NVertsToNFaces3D[nverts]); 00843 for (size_t j=0; j<nbrys; ++j) 00844 { 00845 BRYKEY(nverts,i,j) 00846 Array<NeighDat_t> const & neigh_dat = Bry2Cells[brykey]; 00847 for (size_t k=0; k<neigh_dat.Size(); ++k) 00848 { 00849 if (neigh_dat[k].second!=Cells[i]) 00850 { 00851 NeighDat_t dat(j, neigh_dat[k].second); 00852 Cells[i]->Neighs[brykey] = dat; 00853 //std::cout << Cells[i]->ID << " " << neigh_dat[k].second->ID << " " << brykey << "\n"; 00854 } 00855 } 00856 } 00857 //std::cout << "\n"; 00858 } 00859 } 00860 00861 inline void Generic::GenO2Verts () 00862 { 00863 if (IsShell) throw new Fatal("Generic::GenO2Verts: This mehtod is not ready for Shell meshes yet"); 00864 00865 // generate neighbours map 00866 if (Bry2Cells.empty()) FindNeigh (); 00867 00868 //for (BryCell_t::const_iterator p=Bry2Cells.begin(); p!=Bry2Cells.end(); ++p) std::cout << p->first << std::endl; 00869 00870 // create vertices 00871 if (NDim==2) 00872 { 00873 for (BryCell_t::const_iterator p=Bry2Cells.begin(); p!=Bry2Cells.end(); ++p) // loop over edges 00874 { 00875 // add vertex 00876 Vec3_t mid; 00877 mid = 0.5*(Verts[boost::get<0>(p->first)]->C + Verts[boost::get<1>(p->first)]->C); 00878 //std::cout << boost::get<0>(p->first) << ", " << boost::get<1>(p->first) << " : " << mid << " "; 00879 Verts.Push (new Vertex); 00880 Verts[Verts.Size()-1]->ID = Verts.Size()-1; 00881 Verts[Verts.Size()-1]->Tag = 0; 00882 Verts[Verts.Size()-1]->C = mid; 00883 00884 // set connectivity in cells 00885 for (size_t i=0; i<p->second.Size(); ++i) // loop over cells sharing this edge 00886 { 00887 int idx_edge = p->second[i].first; 00888 Cell * cell = p->second[i].second; 00889 size_t nv = cell->V.Size(); 00890 int idx_vert = -1; 00891 if (NVertsToVTKCell2D[nv]==VTK_TRIANGLE || NVertsToVTKCell2D[nv]==VTK_QUAD) 00892 { 00893 // allocate space for nv vertices 00894 cell->V.PushN (NULL,nv); 00895 idx_vert = NVertsToEdge2D[2*nv][idx_edge][2]; 00896 } 00897 else if (NVertsToVTKCell2D[nv]==VTK_QUADRATIC_TRIANGLE || NVertsToVTKCell2D[nv]==VTK_QUADRATIC_QUAD) 00898 { 00899 // OK. Space already allocated 00900 idx_vert = NVertsToEdge2D[nv][idx_edge][2]; 00901 } 00902 else throw new Fatal("GenO2Verts::GenO2Verts: NDim==2D. Cell must be of type VTK_TRIANGLE (tri3) or VTK_QUAD (quad4) in order to generate O2 vertices. Number of vertices = %d is invalid",nv); 00903 00904 // set pointer to vertex 00905 cell->V[idx_vert] = Verts[Verts.Size()-1]; 00906 00907 // set shares information 00908 Share sha = {cell,idx_vert}; 00909 Verts[Verts.Size()-1]->Shares.Push (sha); 00910 } 00911 } 00912 } 00913 else throw new Fatal("Generic::GenO2Verts: Method not available for 3D yet"); 00914 } 00915 00916 inline void Generic::Erase () 00917 { 00918 for (size_t i=0; i<Verts.Size(); ++i) if (Verts[i]!=NULL) delete Verts[i]; // it is only necessary to delete nodes in Verts array 00919 for (size_t i=0; i<Cells.Size(); ++i) if (Cells[i]!=NULL) delete Cells[i]; // it is only necessary to delete elems in Cells array 00920 if (Verts .Size()>0) Verts .Resize(0); 00921 if (Cells .Size()>0) Cells .Resize(0); 00922 if (TgdVerts.Size()>0) TgdVerts.Resize(0); 00923 if (TgdCells.Size()>0) TgdCells.Resize(0); 00924 } 00925 00926 inline void Generic::TagVertex (int Tag, int Idx) 00927 { 00928 Verts[Idx]->Tag = Tag; 00929 TgdVerts.XPush (Verts[Idx]); 00930 } 00931 00932 inline int Generic::TagVertex (int Tag, double x, double y, double z, double Tol) 00933 { 00934 int idx = -1; 00935 for (size_t i=0; i<Verts.Size(); ++i) 00936 { 00937 double d = sqrt(pow(Verts[i]->C(0)-x, 2.0) + 00938 pow(Verts[i]->C(1)-y, 2.0) + 00939 (NDim==3 ? pow(Verts[i]->C(2)-z, 2.0) : 0.0)); 00940 if (d<Tol) { idx=i; break; } 00941 } 00942 if (idx<0) throw new Fatal("Generic::TagVertex: Could not find Vertex at (%g,%g,%g)",x,y,z); 00943 Verts[idx]->Tag = Tag; 00944 TgdVerts.XPush (Verts[idx]); 00945 return idx; 00946 } 00947 00948 inline void Generic::TagVertsLine (int Tag, double x0, double y0, double AlpDeg, double Tol) 00949 { 00950 bool found = false; 00951 if (NDim==3) throw new Fatal("Generic::TagVertsLine: This method is only available for 2D meshes"); 00952 if ((AlpDeg > -90.0) && (AlpDeg < 90.0)) 00953 { 00954 double m = tan(AlpDeg*Util::PI/180.0); 00955 for (size_t i=0; i<Verts.Size(); ++i) 00956 { 00957 double x = Verts[i]->C(0); 00958 double y = Verts[i]->C(1); 00959 double err = y - (y0 + m*(x-x0)); 00960 if (fabs(err)<Tol) 00961 { 00962 Verts[i]->Tag = Tag; 00963 TgdVerts.XPush (Verts[i]); 00964 found = true; 00965 } 00966 } 00967 } 00968 else 00969 { 00970 for (size_t i=0; i<Verts.Size(); ++i) 00971 { 00972 double x = Verts[i]->C(0); 00973 double err = x - x0; 00974 if (fabs(err)<Tol) 00975 { 00976 Verts[i]->Tag = Tag; 00977 TgdVerts.XPush (Verts[i]); 00978 found = true; 00979 } 00980 } 00981 } 00982 if (!found) throw new Fatal("Generic::TagVertsLine: Could not find any vertex along line passing through (%g,%g)",x0,y0); 00983 } 00984 00985 inline void Generic::TagSegsLine (int Tag, double x0, double y0, double AlpDeg, double Tol) 00986 { 00987 bool found = false; 00988 if (NDim==3) throw new Fatal("Generic::TagSegsLine: This method is only available for 2D meshes"); 00989 if ((AlpDeg > -90.0) && (AlpDeg < 90.0)) 00990 { 00991 double m = tan(AlpDeg*Util::PI/180.0); 00992 for (size_t i=0; i<Cells.Size(); ++i) 00993 { 00994 size_t nverts = Cells[i]->V.Size(); 00995 size_t nbrys = NVertsToNEdges2D[nverts]; 00996 for (size_t j=0; j<nbrys; ++j) 00997 { 00998 BRYKEY(nverts,i,j) 00999 double xa = Verts[vert_a]->C(0); 01000 double ya = Verts[vert_a]->C(1); 01001 double xb = Verts[vert_b]->C(0); 01002 double yb = Verts[vert_b]->C(1); 01003 double err_a = ya - (y0 + m*(xa-x0)); 01004 double err_b = yb - (y0 + m*(xb-x0)); 01005 if ((fabs(err_a)<Tol) && (fabs(err_b)<Tol)) 01006 { 01007 SetBryTag (i, j, Tag); 01008 found = true; 01009 } 01010 } 01011 } 01012 } 01013 else 01014 { 01015 for (size_t i=0; i<Cells.Size(); ++i) 01016 { 01017 size_t nverts = Cells[i]->V.Size(); 01018 size_t nbrys = NVertsToNEdges2D[nverts]; 01019 for (size_t j=0; j<nbrys; ++j) 01020 { 01021 BRYKEY(nverts,i,j) 01022 double xa = Verts[vert_a]->C(0); 01023 double xb = Verts[vert_b]->C(0); 01024 double err_a = xa-x0; 01025 double err_b = xb-x0; 01026 if ((fabs(err_a)<Tol) && (fabs(err_b)<Tol)) 01027 { 01028 SetBryTag (i, j, Tag); 01029 found = true; 01030 } 01031 } 01032 } 01033 } 01034 if (!found) throw new Fatal("Generic::TagSegsLine: Could not find any edge on line passing through (%g,%g)",x0,y0); 01035 } 01036 01037 inline void Generic::TagHorzSegs (int Tag, double y, double xMin, double xMax, double Tol) 01038 { 01039 if (NDim==3) throw new Fatal("Generic::TagHSeg: This method is only available for 2D meshes"); 01040 for (size_t i=0; i<Cells.Size(); ++i) 01041 { 01042 size_t nverts = Cells[i]->V.Size(); 01043 size_t nbrys = NVertsToNEdges2D[nverts]; 01044 for (size_t j=0; j<nbrys; ++j) 01045 { 01046 BRYKEY(nverts,i,j) 01047 double xa = Verts[vert_a]->C(0); 01048 double ya = Verts[vert_a]->C(1); 01049 double xb = Verts[vert_b]->C(0); 01050 double yb = Verts[vert_b]->C(1); 01051 if ((fabs(ya-y)<Tol) && (fabs(yb-y)<Tol)) 01052 { 01053 if ((xa>=xMin) && (xa<=xMax) && (xb>=xMin) && (xb<=xMax)) 01054 { 01055 SetBryTag (i, j, Tag); 01056 } 01057 } 01058 } 01059 } 01060 } 01061 01062 inline void Generic::GroundTags (int LTag, int RTag, int BTag, double Tol) 01063 { 01064 if (NDim==3) throw new Fatal("Generic::GroundTags: This method is only available for 2D meshes"); 01065 Vec3_t min, max; 01066 BoundingBox (min, max); 01067 double left_vert_x = min(0); // left vertical line 01068 double right_vert_x = max(0); // right vertical line 01069 double bottom_horz_y = min(1); // bottom horizontal line 01070 for (size_t i=0; i<Cells.Size(); ++i) 01071 { 01072 size_t nverts = Cells[i]->V.Size(); 01073 size_t nbrys = NVertsToNEdges2D[nverts]; 01074 for (size_t j=0; j<nbrys; ++j) 01075 { 01076 BRYKEY(nverts,i,j) 01077 double xa = Verts[vert_a]->C(0); 01078 double ya = Verts[vert_a]->C(1); 01079 double xb = Verts[vert_b]->C(0); 01080 double yb = Verts[vert_b]->C(1); 01081 01082 // left vertical line 01083 if ((fabs(xa-left_vert_x)<Tol) && (fabs(xb-left_vert_x)<Tol)) 01084 { 01085 SetBryTag (i, j, LTag); 01086 } 01087 01088 // right vertical line 01089 if ((fabs(xa-right_vert_x)<Tol) && (fabs(xb-right_vert_x)<Tol)) 01090 { 01091 SetBryTag (i, j, RTag); 01092 } 01093 01094 // bottom horizontal line 01095 if ((fabs(ya-bottom_horz_y)<Tol) && (fabs(yb-bottom_horz_y)<Tol)) 01096 { 01097 SetBryTag (i, j, BTag); 01098 } 01099 } 01100 } 01101 } 01102 01103 inline void Generic::Check (double Tol) const 01104 { 01105 for (size_t i=0; i<Verts.Size(); ++i) 01106 { 01107 for (size_t j=i+1; j<Verts.Size(); ++j) 01108 { 01109 double dist = Norm(Verts[i]->C - Verts[j]->C); 01110 if (dist<Tol) throw new Fatal("Generic::Check: Found two vertices (%d and %d) with distance=%g smaller than %g",Verts[i]->ID,Verts[j]->ID,dist,Tol); 01111 } 01112 } 01113 } 01114 01115 inline void Generic::WriteVTU (char const * FileKey, int VolSurfOrBoth) const 01116 { 01117 if (IsShell) throw new Fatal("Generic::WriteVTU: This method is not ready for Shell meshes yet"); 01118 01119 // Vol=0, Surf=1, Both=2 01120 01121 // boundary cells (for plotting bry tags) 01122 Array<Cell*> bcells; 01123 if (VolSurfOrBoth>0) 01124 for (size_t i=0; i<Cells.Size(); ++i) 01125 { 01126 int nverts = Cells[i]->V.Size(); 01127 for (BryTag_t::const_iterator p=Cells[i]->BryTags.begin(); p!=Cells[i]->BryTags.end(); ++p) 01128 { 01129 int ibry = p->first; 01130 int btag = p->second; 01131 if (btag<0) 01132 { 01133 int ibcell = bcells.Size(); 01134 int nbverts = (NDim==3 ? NVertsToNVertsPerFace3D[nverts] : 2); 01135 bcells.Push (new Cell); 01136 bcells[ibcell]->ID = Cells.Size()+ibcell; 01137 bcells[ibcell]->Tag = btag; 01138 for (int j=0; j<nbverts; ++j) 01139 { 01140 bcells[ibcell]->V.Push (new Vertex); 01141 bcells[ibcell]->V[j]->ID = (NDim==3 ? Cells[i]->V[NVertsToFace3D[nverts][ibry][j]]->ID : Cells[i]->V[NVertsToEdge2D[nverts][ibry][j]]->ID); 01142 } 01143 } 01144 } 01145 } 01146 01147 // shares data 01148 size_t max_nshares = 0; 01149 size_t max_nparts = 0; 01150 for (size_t i=0; i<Verts.Size(); ++i) 01151 { 01152 if (Verts[i]->Shares .Size()>max_nshares) max_nshares = Verts[i]->Shares .Size(); 01153 if (Verts[i]->PartIDs.Size()>max_nparts ) max_nparts = Verts[i]->PartIDs.Size(); 01154 } 01155 if (max_nshares<1) throw new Fatal("Mesh::WriteVTU: Max number of shares (%d) is wrong", max_nshares); 01156 01157 // data 01158 String fn(FileKey); fn.append(".vtu"); 01159 std::ostringstream oss; 01160 size_t nn = Verts.Size(); // number of Nodes 01161 size_t nc = (VolSurfOrBoth!=1 ? Cells.Size() : 0); // number of Cells 01162 size_t nb = bcells.Size(); // number of boundaries (faces or edges) 01163 01164 // constants 01165 size_t nimax = 40; // number of integers in a line 01166 size_t nfmax = 6; // number of floats in a line 01167 Util::NumStream nsflo = Util::_8s; // number format for floats 01168 01169 // header 01170 oss << "<?xml version=\"1.0\"?>\n"; 01171 oss << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\" byte_order=\"LittleEndian\">\n"; 01172 oss << " <UnstructuredGrid>\n"; 01173 oss << " <Piece NumberOfPoints=\"" << nn << "\" NumberOfCells=\"" << nc+nb << "\">\n"; 01174 01175 // nodes: coordinates 01176 oss << " <Points>\n"; 01177 oss << " <DataArray type=\"Float64\" NumberOfComponents=\"3\" format=\"ascii\">\n"; 01178 size_t k = 0; oss << " "; 01179 for (size_t i=0; i<nn; ++i) 01180 { 01181 oss << " " << nsflo << Verts[i]->C(0) << " "; 01182 oss << nsflo << Verts[i]->C(1) << " "; 01183 oss << nsflo << (NDim==3?Verts[i]->C(2):0.0); 01184 k++; 01185 VTU_NEWLINE (i,k,nn,nfmax/3-1,oss); 01186 } 01187 oss << " </DataArray>\n"; 01188 oss << " </Points>\n"; 01189 01190 // elements: connectivity, offsets, types 01191 oss << " <Cells>\n"; 01192 oss << " <DataArray type=\"Int32\" Name=\"connectivity\" format=\"ascii\">\n"; 01193 k = 0; oss << " "; 01194 if (VolSurfOrBoth!=1) 01195 for (size_t i=0; i<nc; ++i) 01196 { 01197 oss << " "; 01198 for (size_t j=0; j<Cells[i]->V.Size(); ++j) oss << Cells[i]->V[j]->ID << " "; 01199 k++; 01200 VTU_NEWLINE (i,k,nc,nimax/Cells[i]->V.Size(),oss); 01201 } 01202 if (VolSurfOrBoth>0) 01203 for (size_t i=0; i<nb; ++i) 01204 { 01205 oss << " "; 01206 for (size_t j=0; j<bcells[i]->V.Size(); ++j) oss << bcells[i]->V[j]->ID << " "; 01207 k++; 01208 VTU_NEWLINE (i,k,nb,nimax/bcells[i]->V.Size(),oss); 01209 } 01210 oss << " </DataArray>\n"; 01211 oss << " <DataArray type=\"Int32\" Name=\"offsets\" format=\"ascii\">\n"; 01212 k = 0; oss << " "; 01213 size_t offset = 0; 01214 if (VolSurfOrBoth!=1) 01215 for (size_t i=0; i<nc; ++i) 01216 { 01217 offset += Cells[i]->V.Size(); 01218 oss << (k==0?" ":" ") << offset; 01219 k++; 01220 VTU_NEWLINE (i,k,nc,nimax,oss); 01221 } 01222 if (VolSurfOrBoth>0) 01223 for (size_t i=0; i<nb; ++i) 01224 { 01225 offset += bcells[i]->V.Size(); 01226 oss << (k==0?" ":" ") << offset; 01227 k++; 01228 VTU_NEWLINE (i,k,nb,nimax,oss); 01229 } 01230 oss << " </DataArray>\n"; 01231 oss << " <DataArray type=\"UInt8\" Name=\"types\" format=\"ascii\">\n"; 01232 k = 0; oss << " "; 01233 if (VolSurfOrBoth!=1) 01234 for (size_t i=0; i<nc; ++i) 01235 { 01236 if (NDim==2) oss << (k==0?" ":" ") << NVertsToVTKCell2D[Cells[i]->V.Size()]; 01237 else oss << (k==0?" ":" ") << NVertsToVTKCell3D[Cells[i]->V.Size()]; 01238 k++; 01239 VTU_NEWLINE (i,k,nc,nimax,oss); 01240 } 01241 if (VolSurfOrBoth>0) 01242 for (size_t i=0; i<nb; ++i) 01243 { 01244 oss << (k==0?" ":" ") << NVertsToVTKCell2D[bcells[i]->V.Size()]; 01245 k++; 01246 VTU_NEWLINE (i,k,nb,nimax,oss); 01247 } 01248 oss << " </DataArray>\n"; 01249 oss << " </Cells>\n"; 01250 01251 // data -- nodes 01252 oss << " <PointData Scalars=\"TheScalars\">\n"; 01253 oss << " <DataArray type=\"Int32\" Name=\"" << "tag" << "\" NumberOfComponents=\"1\" format=\"ascii\">\n"; 01254 k = 0; oss << " "; 01255 for (size_t i=0; i<nn; ++i) 01256 { 01257 oss << (k==0?" ":" ") << Verts[i]->Tag; 01258 k++; 01259 VTU_NEWLINE (i,k,nn,nimax,oss); 01260 } 01261 oss << " </DataArray>\n"; 01262 oss << " <DataArray type=\"Int32\" Name=\"" << "shares" << "\" NumberOfComponents=\""<< max_nshares <<"\" format=\"ascii\">\n"; 01263 k = 0; oss << " "; 01264 for (size_t i=0; i<nn; ++i) 01265 { 01266 oss << " "; 01267 for (size_t j=0; j<max_nshares; ++j) 01268 { 01269 if (j<Verts[i]->Shares.Size()) oss << Verts[i]->Shares[j].C->ID << " "; 01270 else oss << -1 << " "; 01271 } 01272 k++; 01273 VTU_NEWLINE (i,k,nn,nimax/max_nshares-1,oss); 01274 } 01275 oss << " </DataArray>\n"; 01276 if (max_nparts>0) 01277 { 01278 oss << " <DataArray type=\"Int32\" Name=\"" << "part" << "\" NumberOfComponents=\""<< max_nparts <<"\" format=\"ascii\">\n"; 01279 k = 0; oss << " "; 01280 for (size_t i=0; i<nn; ++i) 01281 { 01282 oss << " "; 01283 for (size_t j=0; j<max_nparts; ++j) 01284 { 01285 if (j<Verts[i]->PartIDs.Size()) oss << Verts[i]->PartIDs[j] << " "; 01286 else oss << -1 << " "; 01287 } 01288 k++; 01289 VTU_NEWLINE (i,k,nn,nimax/max_nparts-1,oss); 01290 } 01291 oss << " </DataArray>\n"; 01292 } 01293 oss << " </PointData>\n"; 01294 01295 // data -- elements 01296 oss << " <CellData Scalars=\"TheScalars\">\n"; 01297 oss << " <DataArray type=\"Int32\" Name=\"" << "tag" << "\" NumberOfComponents=\"1\" format=\"ascii\">\n"; 01298 k = 0; oss << " "; 01299 if (VolSurfOrBoth!=1) 01300 for (size_t i=0; i<nc; ++i) 01301 { 01302 oss << (k==0?" ":" ") << Cells[i]->Tag; 01303 k++; 01304 VTU_NEWLINE (i,k,nc,nimax,oss); 01305 } 01306 if (VolSurfOrBoth>0) 01307 for (size_t i=0; i<nb; ++i) 01308 { 01309 oss << (k==0?" ":" ") << bcells[i]->Tag; 01310 k++; 01311 VTU_NEWLINE (i,k,nb,nimax,oss); 01312 } 01313 oss << " </DataArray>\n"; 01314 if (max_nparts>0) 01315 { 01316 oss << " <DataArray type=\"Int32\" Name=\"" << "part" << "\" NumberOfComponents=\"1\" format=\"ascii\">\n"; 01317 k = 0; oss << " "; 01318 if (VolSurfOrBoth!=1) 01319 for (size_t i=0; i<nc; ++i) 01320 { 01321 oss << (k==0?" ":" ") << Cells[i]->PartID; 01322 k++; 01323 VTU_NEWLINE (i,k,nc,nimax,oss); 01324 } 01325 oss << " </DataArray>\n"; 01326 } 01327 oss << " </CellData>\n"; 01328 01329 // Bottom 01330 oss << " </Piece>\n"; 01331 oss << " </UnstructuredGrid>\n"; 01332 oss << "</VTKFile>" << std::endl; 01333 01334 // Write to file 01335 std::ofstream of(fn.CStr(), std::ios::out); 01336 of << oss.str(); 01337 of.close(); 01338 } 01339 01340 inline void Generic::WriteMPY (char const * FileKey, bool WithTags, bool WithIDs, bool WithShares, char const * Extra) const 01341 { 01342 if (IsShell) throw new Fatal("Generic::WriteMPY: This mehtod is not ready for Shell meshes yet"); 01343 01344 // header 01345 String fn(FileKey); fn.append(".mpy"); 01346 std::ostringstream oss; 01347 oss << "from msys_drawmesh import *\n\n"; 01348 oss << (*this) << "\n"; 01349 01350 // pins 01351 oss << "pins = {"; 01352 size_t npins = Pins.size(); 01353 size_t k = 0; 01354 for (Pin_t::const_iterator p=Pins.begin(); p!=Pins.end(); ++p) 01355 { 01356 oss << p->first->ID << ":["; 01357 for (size_t i=0; i<p->second.Size(); ++i) 01358 { 01359 if (i==p->second.Size()-1) oss << p->second[i]->ID << "]"; 01360 else oss << p->second[i]->ID << ","; 01361 } 01362 if (k!=npins-1) oss << ",\n "; 01363 k++; 01364 } 01365 oss << "}\n\n"; 01366 01367 // shares 01368 oss << "shares = {"; 01369 for (size_t i=0; i<Verts.Size(); ++i) 01370 { 01371 oss << Verts[i]->ID << ":["; 01372 for (size_t j=0; j<Verts[i]->Shares.Size(); ++j) 01373 { 01374 if (j==Verts[i]->Shares.Size()-1) oss << Verts[i]->Shares[j].C->ID << "]"; 01375 else oss << Verts[i]->Shares[j].C->ID << ","; 01376 } 01377 if (Verts[i]->Shares.Size()>0) 01378 { 01379 if (i!=Verts.Size()-1) oss << ",\n "; 01380 } 01381 else 01382 { 01383 if (i!=Verts.Size()-1) oss << "],\n "; 01384 else oss << "]"; 01385 } 01386 } 01387 oss << "}\n\n"; 01388 01389 // drawing 01390 oss << "d = DrawMesh(V,C,pins,shares)\n"; 01391 String prms; 01392 if (WithTags) prms.append("True,"); else prms.append("False,"); 01393 if (WithIDs) prms.append("True,"); else prms.append("False,"); 01394 if (WithShares) prms.append("True,"); else prms.append("False"); 01395 oss << "d.draw(" << prms << ")\n"; 01396 if (Extra!=NULL) oss << Extra; 01397 oss << "d.show()\n"; 01398 std::ofstream of(fn.CStr(), std::ios::out); 01399 of << oss.str(); 01400 of.close(); 01401 std::cout << "File <" << TERM_CLR_BLUE_H << fn << TERM_RST << "> written\n"; 01402 } 01403 01404 inline void Generic::WriteJSON (char const * FileKey) const 01405 { 01406 // open stream 01407 String fn(FileKey); fn.append(".msh"); 01408 std::ostringstream oss; 01409 oss << "{\n"; 01410 01411 // verts 01412 oss << " \"verts\" : [\n"; 01413 for (size_t i=0; i<Verts.Size(); ++i) 01414 { 01415 if (Verts[i]==NULL) throw new Fatal("Generic::WriteJSON: Vertex %d is not defined",i); 01416 oss << " { "; 01417 oss << "\"id\":" << Verts[i]->ID << ", "; 01418 oss << "\"tag\":" << Verts[i]->Tag << ", "; 01419 oss << "\"c\":["; 01420 if (NDim==3) 01421 { 01422 oss << Verts[i]->C(0) << ", "; 01423 oss << Verts[i]->C(1) << ", "; 01424 oss << Verts[i]->C(2); 01425 } 01426 else 01427 { 01428 oss << Verts[i]->C(0) << ", "; 01429 oss << Verts[i]->C(1); 01430 } 01431 oss << "], \"shares\":["; 01432 for (size_t j=0; j<Verts[i]->Shares.Size(); ++j) 01433 { 01434 oss << Verts[i]->Shares[j].C->ID; 01435 if (j!=Verts[i]->Shares.Size()-1) oss << ", "; 01436 } 01437 oss << "], \"parts\":["; 01438 for (size_t j=0; j<Verts[i]->PartIDs.Size(); ++j) 01439 { 01440 oss << Verts[i]->PartIDs[j]; 01441 if (j!=Verts[i]->PartIDs.Size()-1) oss << ", "; 01442 } 01443 if (i==Verts.Size()-1) oss << "] }\n"; 01444 else oss << "] },\n"; 01445 } 01446 oss << " ],\n"; 01447 01448 // cells 01449 oss << " \"cells\" : [\n"; 01450 for (size_t i=0; i<Cells.Size(); ++i) 01451 { 01452 if (Cells[i]==NULL) throw new Fatal("Generic::WriteJSON: Cell %d is not defined",i); 01453 oss << " { "; 01454 oss << "\"id\":" << Cells[i]->ID << ", "; 01455 oss << "\"tag\":" << Cells[i]->Tag << ", "; 01456 oss << "\"part\":" << Cells[i]->PartID << ", "; 01457 oss << "\"verts\":["; 01458 for (size_t j=0; j<Cells[i]->V.Size(); ++j) 01459 { 01460 oss << Cells[i]->V[j]->ID; 01461 if (j!=Cells[i]->V.Size()-1) oss << ", "; 01462 } 01463 oss << "], \"ftags\":["; 01464 size_t nbrys = (NDim==2 ? NVertsToNEdges2D[Cells[i]->V.Size()] : NVertsToNFaces3D[Cells[i]->V.Size()]); 01465 for (size_t j=0; j<nbrys; ++j) 01466 { 01467 oss << CellGetBryTag(j, Cells[i]); 01468 if (j!=nbrys-1) oss << ", "; 01469 } 01470 oss << "], \"neigh\":["; 01471 for (size_t j=0; j<nbrys; ++j) 01472 { 01473 oss << CellGetNeigh(j, Cells[i]); 01474 if (j!=nbrys-1) oss << ", "; 01475 } 01476 if (i==Cells.Size()-1) oss << "] }\n"; 01477 else oss << "] },\n"; 01478 } 01479 oss << " ]\n"; 01480 01481 // write file 01482 oss << "}\n"; 01483 std::ofstream of(fn.CStr(), std::ios::out); 01484 of << oss.str(); 01485 of.close(); 01486 std::cout << "File <" << TERM_CLR_BLUE_H << fn << TERM_RST << "> written\n"; 01487 } 01488 01489 inline void Generic::GenGroundSG (Array<double> const & X, Array<double> const & Y, double FootingLx) 01490 { 01491 // constants 01492 size_t nx = X.Size(); // number of columns 01493 size_t ny = Y.Size(); // number of rows 01494 size_t nc = (nx-1)*(ny-1); // number of cells 01495 size_t nv = nx*ny + nx*(ny-1) + (nx-1)*ny; // number of vertices 01496 01497 // check 01498 if (NDim!=2) throw new Fatal("Mesh::Generic::GenGroundSG: This method is only available for 2D yet"); 01499 for (size_t j=1; j<nx; ++j) if (X[j]<X[j-1]) throw new Fatal("Mesh::Generic::GenGroundSG: x-coordinates must be increasing"); 01500 for (size_t j=1; j<ny; ++j) if (Y[j]>Y[j-1]) throw new Fatal("Mesh::Generic::GenGroundSG: y-coordinates must be decreasing"); 01501 01502 // set size 01503 SetSize (nv, nc); 01504 01505 // generate mesh 01506 size_t idx_vert = 0; 01507 size_t idx_cell = 0; 01508 for (size_t i=0; i<nx-1; ++i) 01509 { 01510 // vertices: first column 01511 if (i==0) 01512 { 01513 for (size_t j=0; j<ny; ++j) 01514 { 01515 SetVert (idx_vert, 0, X[i], Y[j]); 01516 idx_vert++; 01517 if (j!=ny-1) // intermediate nodes 01518 { 01519 double dy = Y[j+1] - Y[j]; 01520 SetVert (idx_vert, 0, X[i], Y[j]+dy/2.0); 01521 idx_vert++; 01522 } 01523 } 01524 } 01525 01526 // vertices: second column 01527 double dx = X[i+1] - X[i]; 01528 for (size_t j=0; j<ny; ++j) 01529 { 01530 SetVert (idx_vert, 0, X[i]+dx/2.0, Y[j]); 01531 idx_vert++; 01532 } 01533 01534 // vertices: third column 01535 for (size_t j=0; j<ny; ++j) 01536 { 01537 SetVert (idx_vert, 0, X[i]+dx, Y[j]); 01538 idx_vert++; 01539 if (j!=ny-1) 01540 { 01541 double dy = Y[j+1] - Y[j]; 01542 SetVert (idx_vert, 0, X[i]+dx, Y[j]+dy/2.0); 01543 idx_vert++; 01544 } 01545 } 01546 01547 // set cells 01548 for (size_t j=0; j<ny-1; ++j) 01549 { 01550 int a = (3*ny-1)*i + 2*j; 01551 int b = (3*ny-1)*i + (2*ny-1) + j; 01552 int c = a + 3*ny - 1; 01553 SetCell (idx_cell, -1, Array<int>(a+2, c+2, c, a, b+1, c+1, b, a+1)); 01554 if (i==0) SetBryTag (idx_cell, 3, -10); 01555 if (i==nx-2) SetBryTag (idx_cell, 1, -20); 01556 if (j==ny-2) SetBryTag (idx_cell, 0, -30); 01557 if (j==0) // footing 01558 { 01559 if (X[i]+0.95*dx<=FootingLx) 01560 SetBryTag (idx_cell, 2, -40); 01561 } 01562 idx_cell++; 01563 } 01564 } 01565 } 01566 01567 inline void Generic::GenGroundSG (size_t Nx, size_t Ny, double Dx, double Dy) 01568 { 01569 if (Nx<2) throw new Fatal("Generic::GenGroundSG: Number of columns along x must be at least two. Nx=%d is invalid",Nx); 01570 if (Ny<2) throw new Fatal("Generic::GenGroundSG: Number of columns along y must be at least two. Ny=%d is invalid",Ny); 01571 Array<double> X(Nx); 01572 Array<double> Y(Ny); 01573 for (size_t i=0; i<Nx; ++i) X[i] = static_cast<double>(i)*Dx; 01574 for (size_t i=0; i<Ny; ++i) Y[i] = -static_cast<double>(i)*Dy; 01575 Y[0] = 0.0; 01576 GenGroundSG (X, Y); 01577 } 01578 01579 inline void Generic::GenSector (size_t Nr, size_t Nth, double r, double R, double Theta) 01580 { 01581 // check 01582 if (Nr<2) throw new Fatal("Mesh::Generic::GenSector: Nr (number of lines/columns for each radii) must be greater than or equal to 2"); 01583 if (Nth<2) throw new Fatal("Mesh::Generic::GenSector: Nth (number of lines/rows for each theta) must be greater than or equal to 2"); 01584 if (NDim!=2) throw new Fatal("Mesh::Generic::GenSector: This method is only available for 2D yet"); 01585 01586 // constants 01587 size_t nc = (Nr-1)*(Nth-1); // number of cells 01588 size_t nv = Nr*Nth + Nr*(Nth-1) + (Nr-1)*Nth; // number of vertices 01589 double dr = (R-r)/(Nr-1); // delta radius 01590 double dth = Theta/(Nth-1); // delta theta 01591 01592 // set size 01593 SetSize (nv, nc); 01594 01595 // generate mesh 01596 size_t idx_vert = 0; 01597 size_t idx_cell = 0; 01598 for (size_t i=0; i<Nr-1; ++i) 01599 { 01600 double radius = r+i*dr; 01601 01602 // vertices: first column 01603 if (i==0) 01604 { 01605 for (size_t j=0; j<Nth; ++j) 01606 { 01607 double th = Theta-j*dth; 01608 double x = radius*cos(th); 01609 double y = radius*sin(th); 01610 SetVert (idx_vert, (j==0 ? -100 : (j==Nth-1 ? -200 : 0)), x, y); 01611 idx_vert++; 01612 if (j!=Nth-1) // intermediate nodes 01613 { 01614 th -= dth/2.0; 01615 x = radius*cos(th); 01616 y = radius*sin(th); 01617 SetVert (idx_vert, 0, x, y); 01618 idx_vert++; 01619 } 01620 } 01621 } 01622 01623 // vertices: middle column 01624 radius += dr/2.0; 01625 for (size_t j=0; j<Nth; ++j) 01626 { 01627 double th = Theta-j*dth; 01628 double x = radius*cos(th); 01629 double y = radius*sin(th); 01630 SetVert (idx_vert, (j==0 ? -100 : (j==Nth-1 ? -200 : 0)), x, y); 01631 idx_vert++; 01632 } 01633 01634 // vertices: last column 01635 radius += dr/2.0; 01636 for (size_t j=0; j<Nth; ++j) 01637 { 01638 double th = Theta-j*dth; 01639 double x = radius*cos(th); 01640 double y = radius*sin(th); 01641 SetVert (idx_vert, (j==0 ? -100 : (j==Nth-1 ? -200 : 0)), x, y); 01642 idx_vert++; 01643 if (j!=Nth-1) 01644 { 01645 th -= dth/2.0; 01646 x = radius*cos(th); 01647 y = radius*sin(th); 01648 SetVert (idx_vert, 0, x, y); 01649 idx_vert++; 01650 } 01651 } 01652 01653 // set cells 01654 for (size_t j=0; j<Nth-1; ++j) 01655 { 01656 int a = (3*Nth-1)*i + 2*j; 01657 int b = (3*Nth-1)*i + (2*Nth-1) + j; 01658 int c = a + 3*Nth - 1; 01659 SetCell (idx_cell, -1, Array<int>(a+2, c+2, c, a, b+1, c+1, b, a+1)); 01660 if (i==0) SetBryTag (idx_cell, 3, -10); 01661 if (i==Nr-2) SetBryTag (idx_cell, 1, -20); 01662 if (j==Nth-2) SetBryTag (idx_cell, 0, -30); 01663 if (j==0) SetBryTag (idx_cell, 2, -40); 01664 idx_cell++; 01665 } 01666 } 01667 } 01668 01669 inline void Generic::Quad4ToTri3 (bool BackDiagonal) 01670 { 01671 // copy pointers of old mesh 01672 Array<Cell*> old_cells(Cells.Size()); 01673 for (size_t i=0; i<old_cells.Size(); ++i) old_cells[i] = Cells[i]; 01674 Cells .Resize (old_cells.Size()*2); 01675 TgdCells.Resize (0); 01676 Cells.SetValues (NULL); 01677 01678 // erase shares information 01679 for (size_t i=0; i<Verts.Size(); ++i) Verts[i]->Shares.Resize(0); 01680 01681 // new mesh 01682 int icell = 0; 01683 for (size_t i=0; i<old_cells.Size(); ++i) 01684 { 01685 // check 01686 if (old_cells[i]->V.Size()!=4) throw new Fatal("Mesh::Quad4ToTri3: This method only works for Quad4s (NVerts=%d is invalid)",old_cells[i]->V.Size()); 01687 01688 // indices of vertices of Quad4 01689 size_t i0 = old_cells[i]->V[0]->ID; 01690 size_t i1 = old_cells[i]->V[1]->ID; 01691 size_t i2 = old_cells[i]->V[2]->ID; 01692 size_t i3 = old_cells[i]->V[3]->ID; 01693 01694 // new connectivities 01695 Array<int> con0(3), con1(3); 01696 if (BackDiagonal) 01697 { 01698 con0 = i0, i1, i3; 01699 con1 = i3, i1, i2; 01700 } 01701 else 01702 { 01703 con0 = i0, i1, i2; 01704 con1 = i0, i2, i3; 01705 } 01706 01707 // new cells 01708 SetCell (icell++, old_cells[i]->Tag, con0); 01709 SetCell (icell++, old_cells[i]->Tag, con1); 01710 01711 // boundary tags 01712 if (BackDiagonal) 01713 { 01714 for (BryTag_t::const_iterator p=old_cells[i]->BryTags.begin(); p!=old_cells[i]->BryTags.end(); ++p) 01715 { 01716 if (p->first==0) SetBryTag (icell-2, /*side*/0, /*tag*/p->second); 01717 if (p->first==1) SetBryTag (icell-1, /*side*/1, /*tag*/p->second); 01718 if (p->first==2) SetBryTag (icell-1, /*side*/2, /*tag*/p->second); 01719 if (p->first==3) SetBryTag (icell-2, /*side*/2, /*tag*/p->second); 01720 } 01721 } 01722 else 01723 { 01724 for (BryTag_t::const_iterator p=old_cells[i]->BryTags.begin(); p!=old_cells[i]->BryTags.end(); ++p) 01725 { 01726 if (p->first==0) SetBryTag (icell-2, /*side*/0, /*tag*/p->second); 01727 if (p->first==1) SetBryTag (icell-2, /*side*/1, /*tag*/p->second); 01728 if (p->first==2) SetBryTag (icell-1, /*side*/1, /*tag*/p->second); 01729 if (p->first==3) SetBryTag (icell-1, /*side*/2, /*tag*/p->second); 01730 } 01731 } 01732 } 01733 01734 // delete old mesh 01735 for (size_t i=0; i<old_cells.Size(); ++i) delete old_cells[i]; 01736 01737 // info 01738 printf("%s ------- After Quad4ToTri3 -------%s\n", TERM_GREEN, TERM_RST); 01739 printf("%s Num of cells = %zd%s\n", TERM_CLR2, Cells.Size(), TERM_RST); 01740 printf("%s Num of vertices = %zd%s\n", TERM_CLR2, Verts.Size(), TERM_RST); 01741 } 01742 01743 inline void Generic::Quad8ToTri6 (bool BackDiagonal) 01744 { 01745 // copy pointers of old mesh 01746 Array<Cell*> old_cells(Cells.Size()); 01747 for (size_t i=0; i<old_cells.Size(); ++i) old_cells[i] = Cells[i]; 01748 Cells .Resize (old_cells.Size()*2); 01749 TgdCells.Resize (0); 01750 Cells.SetValues (NULL); 01751 01752 // erase shares information 01753 for (size_t i=0; i<Verts.Size(); ++i) Verts[i]->Shares.Resize(0); 01754 01755 // new mesh 01756 int icell = 0; 01757 for (size_t i=0; i<old_cells.Size(); ++i) 01758 { 01759 // check 01760 if (old_cells[i]->V.Size()!=8) throw new Fatal("Mesh::Quad8ToTri6: This method only works for Quad8s (NVerts=%d is invalid)",old_cells[i]->V.Size()); 01761 01762 // indices of vertices of Quad8 01763 size_t i0 = old_cells[i]->V[0]->ID; 01764 size_t i1 = old_cells[i]->V[1]->ID; 01765 size_t i2 = old_cells[i]->V[2]->ID; 01766 size_t i3 = old_cells[i]->V[3]->ID; 01767 size_t i4 = old_cells[i]->V[4]->ID; 01768 size_t i5 = old_cells[i]->V[5]->ID; 01769 size_t i6 = old_cells[i]->V[6]->ID; 01770 size_t i7 = old_cells[i]->V[7]->ID; 01771 01772 // new vertex 01773 Vec3_t xnew = 0.5*(Verts[i0]->C + Verts[i2]->C); 01774 int iv = PushVert (/*tag*/0, xnew(0), xnew(1), xnew(2)); 01775 01776 // new connectivities 01777 Array<int> con0(6), con1(6); 01778 if (BackDiagonal) 01779 { 01780 con0 = i0, i1, i3, i4, iv, i7; 01781 con1 = i3, i1, i2, iv, i5, i6; 01782 } 01783 else 01784 { 01785 con0 = i0, i1, i2, i4, i5, iv; 01786 con1 = i0, i2, i3, iv, i6, i7; 01787 } 01788 01789 // new cells 01790 SetCell (icell++, old_cells[i]->Tag, con0); 01791 SetCell (icell++, old_cells[i]->Tag, con1); 01792 01793 // boundary tags 01794 if (BackDiagonal) 01795 { 01796 for (BryTag_t::const_iterator p=old_cells[i]->BryTags.begin(); p!=old_cells[i]->BryTags.end(); ++p) 01797 { 01798 if (p->first==0) SetBryTag (icell-2, /*side*/0, /*tag*/p->second); 01799 if (p->first==1) SetBryTag (icell-1, /*side*/1, /*tag*/p->second); 01800 if (p->first==2) SetBryTag (icell-1, /*side*/2, /*tag*/p->second); 01801 if (p->first==3) SetBryTag (icell-2, /*side*/2, /*tag*/p->second); 01802 } 01803 } 01804 else 01805 { 01806 for (BryTag_t::const_iterator p=old_cells[i]->BryTags.begin(); p!=old_cells[i]->BryTags.end(); ++p) 01807 { 01808 if (p->first==0) SetBryTag (icell-2, /*side*/0, /*tag*/p->second); 01809 if (p->first==1) SetBryTag (icell-2, /*side*/1, /*tag*/p->second); 01810 if (p->first==2) SetBryTag (icell-1, /*side*/1, /*tag*/p->second); 01811 if (p->first==3) SetBryTag (icell-1, /*side*/2, /*tag*/p->second); 01812 } 01813 } 01814 } 01815 01816 // delete old mesh 01817 for (size_t i=0; i<old_cells.Size(); ++i) delete old_cells[i]; 01818 01819 // info 01820 printf("%s ------- After Quad8ToTri6 -------%s\n", TERM_GREEN, TERM_RST); 01821 printf("%s Num of cells = %zd%s\n", TERM_CLR2, Cells.Size(), TERM_RST); 01822 printf("%s Num of vertices = %zd%s\n", TERM_CLR2, Verts.Size(), TERM_RST); 01823 } 01824 01825 inline void Generic::Tri6ToTri15 () 01826 { 01827 // find neighbours 01828 FindNeigh (); 01829 01830 // expand connectivity array 01831 for (size_t i=0; i<Cells.Size(); ++i) 01832 { 01833 if (Cells[i]->V.Size()!=6) throw new Fatal("Mesh::Tri6ToTri15: This method only works for Tri6s (NVerts=%d is invalid)",Cells[i]->V.Size()); 01834 for (size_t j=0; j<9; ++j) Cells[i]->V.Push (NULL); 01835 } 01836 01837 // data 01838 Vec_t N(6); // Tri6 shape functions 01839 Mat_t C(2,6); // matrix of coordinates 01840 Vec_t R(9); // natural r coord of new nodes (6->14) 01841 Vec_t S(9); // natural s coord of new nodes (6->14) 01842 R = 1.0/4.0 , 3.0/4.0 , 3.0/4.0 , 1.0/4.0 , 0.0 , 0.0 , 1.0/4.0 , 1.0/2.0 , 1.0/4.0; 01843 S = 0.0 , 0.0 , 1.0/4.0 , 3.0/4.0 , 3.0/4.0 , 1.0/4.0 , 1.0/4.0 , 1.0/4.0 , 1.0/2.0; 01844 01845 // convert 01846 for (size_t i=0; i<Cells.Size(); ++i) 01847 { 01848 // indices of vertices of Tri6 01849 size_t i0 = Cells[i]->V[0]->ID; 01850 size_t i1 = Cells[i]->V[1]->ID; 01851 size_t i2 = Cells[i]->V[2]->ID; 01852 size_t i3 = Cells[i]->V[3]->ID; 01853 size_t i4 = Cells[i]->V[4]->ID; 01854 size_t i5 = Cells[i]->V[5]->ID; 01855 01856 // matrix of coordinates 01857 C = Verts[i0]->C(0), Verts[i1]->C(0), Verts[i2]->C(0), Verts[i3]->C(0), Verts[i4]->C(0), Verts[i5]->C(0), 01858 Verts[i0]->C(1), Verts[i1]->C(1), Verts[i2]->C(1), Verts[i3]->C(1), Verts[i4]->C(1), Verts[i5]->C(1); 01859 01860 // border nodes 01861 for (size_t j=6; j<12; ++j) 01862 { 01863 if (Cells[i]->V[j]==NULL) // not set yet 01864 { 01865 // new vertex 01866 Tri6Shape (R(j-6), S(j-6), N); 01867 Vec_t x(C*N); 01868 int iv = PushVert (/*tag*/0, x(0), x(1)); 01869 01870 // set cell and shares 01871 Cells[i]->V[j] = Verts[iv]; 01872 Share sha = {Cells[i],j}; 01873 Verts[iv]->Shares.Push (sha); 01874 01875 // set neighbours 01876 int idx = (j-6)%2; // 0 or 1 (first or second node on side) 01877 int side = (j-6)/2; // side of new vertex 01878 for (Neighs_t::const_iterator p=Cells[i]->Neighs.begin(); p!=Cells[i]->Neighs.end(); ++p) 01879 { 01880 if (side==p->second.first) 01881 { 01882 // find J: index of vertex in neighbour 01883 Cell * neigh = p->second.second; 01884 Neighs_t::const_iterator it = neigh->Neighs.find(p->first); 01885 if (it==neigh->Neighs.end()) throw new Fatal("Mesh::Tri6ToTri15: __internal_error__"); 01886 int neigh_side = it->second.first; 01887 int neigh_idx = (1-idx) + neigh_side*2; 01888 int J = 6 + neigh_idx; 01889 01890 // set cell and shares 01891 neigh->V[J] = Verts[iv]; 01892 Share neigh_sha = {neigh,J}; 01893 Verts[iv]->Shares.Push (neigh_sha); 01894 } 01895 } 01896 } 01897 } 01898 01899 // centre nodes 01900 for (size_t j=12; j<15; ++j) 01901 { 01902 // new vertex 01903 Tri6Shape (R(j-6), S(j-6), N); 01904 Vec_t x(C*N); 01905 int iv = PushVert (/*tag*/0, x(0), x(1)); 01906 01907 // set cell and shares 01908 Cells[i]->V[j] = Verts[iv]; 01909 Share sha = {Cells[i],j}; 01910 Verts[iv]->Shares.Push (sha); 01911 } 01912 } 01913 01914 // info 01915 printf("%s ------- After Tri6ToTri15 -------%s\n", TERM_GREEN, TERM_RST); 01916 printf("%s Num of cells = %zd%s\n", TERM_CLR2, Cells.Size(), TERM_RST); 01917 printf("%s Num of vertices = %zd%s\n", TERM_CLR2, Verts.Size(), TERM_RST); 01918 } 01919 01920 inline void Generic::Tri3ToTri6 () 01921 { 01922 // find neighbours 01923 FindNeigh (); 01924 01925 // expand connectivity array 01926 for (size_t i=0; i<Cells.Size(); ++i) 01927 { 01928 if (Cells[i]->V.Size()!=3) throw new Fatal("Mesh::Tri3ToTri6: This method only works for Tri3s (NVerts=%d is invalid)",Cells[i]->V.Size()); 01929 for (size_t j=0; j<3; ++j) Cells[i]->V.Push (NULL); 01930 } 01931 01932 // convert 01933 for (size_t i=0; i<Cells.Size(); ++i) 01934 { 01935 // border nodes 01936 for (size_t j=3; j<6; ++j) 01937 { 01938 if (Cells[i]->V[j]==NULL) // not set yet 01939 { 01940 // new vertex 01941 int side = j-3; // side of new vertex 01942 BRYKEY(/*nverts*/3,i,side) 01943 double xm = (Verts[vert_a]->C(0)+Verts[vert_b]->C(0))/2.0; 01944 double ym = (Verts[vert_a]->C(1)+Verts[vert_b]->C(1))/2.0; 01945 int iv = PushVert (/*tag*/0, xm, ym); 01946 01947 // set cell and shares 01948 Cells[i]->V[j] = Verts[iv]; 01949 Share sha = {Cells[i],j}; 01950 Verts[iv]->Shares.Push (sha); 01951 01952 // set neighbours 01953 for (Neighs_t::const_iterator p=Cells[i]->Neighs.begin(); p!=Cells[i]->Neighs.end(); ++p) 01954 { 01955 if (side==p->second.first) 01956 { 01957 // find J: index of vertex in neighbour 01958 Cell * neigh = p->second.second; 01959 Neighs_t::const_iterator it = neigh->Neighs.find(p->first); 01960 if (it==neigh->Neighs.end()) throw new Fatal("Mesh::Tri3ToTri6: __internal_error__"); 01961 int neigh_side = it->second.first; 01962 int J = 3 + neigh_side; 01963 01964 // set cell and shares 01965 neigh->V[J] = Verts[iv]; 01966 Share neigh_sha = {neigh,J}; 01967 Verts[iv]->Shares.Push (neigh_sha); 01968 } 01969 } 01970 } 01971 } 01972 } 01973 01974 // info 01975 printf("%s ------- After Tri3ToTri6 --------%s\n", TERM_GREEN, TERM_RST); 01976 printf("%s Num of cells = %zd%s\n", TERM_CLR2, Cells.Size(), TERM_RST); 01977 printf("%s Num of vertices = %zd%s\n", TERM_CLR2, Verts.Size(), TERM_RST); 01978 } 01979 01980 inline void Generic::Refine () 01981 { 01982 size_t old_sz = Cells.Size(); 01983 for (size_t i=0; i<old_sz; ++i) 01984 { 01985 if (Cells[i]->V.Size()!=2) throw new Fatal("Mesh::Refine: This method only works for Lin2 cells (NVerts=%d is invalid)",Cells[i]->V.Size()); 01986 01987 // new vertex 01988 size_t va = Cells[i]->V[0]->ID; 01989 size_t vb = Cells[i]->V[1]->ID; 01990 double xm = (Verts[va]->C(0)+Verts[vb]->C(0))/2.0; 01991 double ym = (Verts[va]->C(1)+Verts[vb]->C(1))/2.0; 01992 double zm = (NDim==3 ? (Verts[va]->C(2)+Verts[vb]->C(2))/2.0 : 0.0); 01993 int iv = PushVert (0, xm, ym, zm); 01994 01995 // new cell 01996 PushCell (Cells[i]->Tag, Array<int>(va, iv)); 01997 01998 // set old cell 01999 Cells[i]->V[0] = Verts[iv]; 02000 } 02001 02002 // info 02003 printf("%s ------- After Refine ------------%s\n", TERM_GREEN, TERM_RST); 02004 printf("%s Num of cells = %zd%s\n", TERM_CLR2, Cells.Size(), TERM_RST); 02005 printf("%s Num of vertices = %zd%s\n", TERM_CLR2, Verts.Size(), TERM_RST); 02006 } 02007 02008 inline void Generic::Tri6Shape (double r, double s, Vec_t & N) const 02009 { 02010 /* s 02011 * ^ 02012 * | 02013 * 2 02014 * @,(0,1) 02015 * | ', 02016 * | ', 02017 * | ', 02018 * | ', 4 02019 * 5 @ @ 02020 * | ', 02021 * | ', 02022 * | ', 02023 * |(0,0) ', (1,0) 02024 * @---------@---------@ --> r 02025 * 0 3 1 02026 */ 02027 N(0) = 1.0-(r+s)*(3.0-2.0*(r+s)); 02028 N(1) = r*(2.0*r-1.0); 02029 N(2) = s*(2.0*s-1.0); 02030 N(3) = 4.0*r*(1.0-(r+s)); 02031 N(4) = 4.0*r*s; 02032 N(5) = 4.0*s*(1.0-(r+s)); 02033 } 02034 02035 #ifdef USE_BOOST_PYTHON 02036 inline void Generic::PyGetVertsEdges (BPy::list & V, BPy::list & E) const 02037 { 02038 if (NDim==3) 02039 { 02040 // vertices 02041 for (size_t i=0; i<Verts.Size(); ++i) 02042 V.append (BPy::make_tuple(Verts[i]->C(0), Verts[i]->C(1), Verts[i]->C(2))); 02043 02044 // edges 02045 for (size_t i=0; i<Cells.Size(); ++i) 02046 { 02047 size_t nv = Cells[i]->V.Size(); 02048 for (size_t j=0; j<NVertsToNEdges3D[nv]; ++j) 02049 { 02050 BPy::list pair; 02051 pair.append (Cells[i]->V[NVertsToEdge3D[nv][j][0]]->ID); 02052 pair.append (Cells[i]->V[NVertsToEdge3D[nv][j][1]]->ID); 02053 E.append (pair); 02054 } 02055 } 02056 } 02057 else 02058 { 02059 // vertices 02060 for (size_t i=0; i<Verts.Size(); ++i) 02061 V.append (BPy::make_tuple(Verts[i]->C(0), Verts[i]->C(1), 0.0)); 02062 02063 // edges 02064 for (size_t i=0; i<Cells.Size(); ++i) 02065 { 02066 size_t nv = Cells[i]->V.Size(); 02067 for (size_t j=0; j<NVertsToNEdges2D[nv]; ++j) 02068 { 02069 BPy::list pair; 02070 pair.append (Cells[i]->V[NVertsToEdge2D[nv][j][0]]->ID); 02071 pair.append (Cells[i]->V[NVertsToEdge2D[nv][j][1]]->ID); 02072 E.append (pair); 02073 } 02074 } 02075 } 02076 } 02077 #endif 02078 02079 }; // namespace Mesh 02080 02081 #endif // MECHSYS_MESH_H