MechSys  1.0
Computing library for simulations in continuum and discrete mechanics
/home/dorival/mechsys/lib/mesh/mesh.h
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines