src/tetmesh/tetmesh.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                           tetmesh.cpp  -  description
00003                              -------------------
00004     begin                : Mon Dec 15 2003
00005     copyright            : (C) 2003 by Roman Geus
00006     email                : roman.geus@psi.ch
00007 ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 #include <cassert>
00019 #include <iomanip>
00020 #include <new>
00021 #include <vector>
00022 #include <stdexcept>
00023 #include "myrlog.h"
00024 #include "pbedefs.h"
00025 #include "tetmesh.h"
00026 
00027 namespace mesh {
00028 
00029 using namespace std;
00030 
00031 TetMesh* TetMesh::instance_ = 0;        // Pointer to TetMesh singleton.
00032 
00033 TetMesh::TetMesh()
00034     : _nofTet(0),
00035       _nofPoint(0),
00036       _nofEdge(0),
00037       _nofFace(0),
00038       _nofSym(0),
00039       _tetCounter(0),
00040       _octree(0)
00041 {
00042     assert(instance_ == 0);
00043     instance_ = this;
00044 }
00045 
00046 TetMesh::~TetMesh() {
00047     // delete octree
00048     if (_octree)
00049         delete _octree;
00050     instance_ = 0;
00051 }
00052 
00053 
00054 void TetMesh::load_materials(const char* fileName){
00055   _materials = new Materials(fileName);
00056 }
00057 
00058 Materials* TetMesh::get_materials() const{
00059   return _materials;
00060 }
00061 
00062 
00063 void TetMesh::initPoint(int nofPoint) {
00064     _nofPoint = nofPoint;
00065     _points.reserve(nofPoint);
00066 }
00067 
00068 void TetMesh::initTet(int nofTet) {
00069     _nofTet = nofTet;
00070     _tets.reserve(nofTet);
00071 }
00072 
00073 void TetMesh::insertPoint(int id, double x, double y, double z) {
00074     assert(static_cast<size_t>(id) == _points.size());
00075     _points.push_back(Point(id, x, y, z));
00076 }
00077 
00078   void TetMesh::insertTet(id_t global_id, id_t id0, id_t id1, id_t id2, id_t id3, id_t material) {
00079 
00080     id_t id = _tetCounter ++;
00081     id_t corners[4] = {id0, id1, id2, id3};
00082     assert(id == _tets.size());
00083     _tets.push_back(Tet(*this, id, corners, material));
00084 }
00085 
00086 void TetMesh::generateEdges() {
00087     const int edgeNodeLocal[6][2] = {{0, 1}, {0, 2}, {0, 3},
00088                                      {1, 2}, {1, 3}, {2, 3}};
00089     id_t node0_id;
00090     id_t node1_id;
00091     id_t edge_id;
00092 
00093     for (tet_iterator iter = tet_begin(); iter != tet_end(); ++ iter) {
00094         for (int j = 0; j < 6; j ++) {
00095             node0_id = (*iter).get_corner_id(edgeNodeLocal[j][0]);
00096             node1_id = (*iter).get_corner_id(edgeNodeLocal[j][1]);
00097             edge_id = insertEdge(node0_id, node1_id);
00098             (*iter).set_edge_id(j, edge_id);
00099             // FIXME: orientation edges must be consistent globally
00100             (*iter).set_edge_orientation(j, get_edge(edge_id)->get_start_id() == node0_id);
00101         }
00102     }
00103 }
00104 
00105 void TetMesh::generateFaces() {
00106     int node0, node1, node2;
00107     for (tet_iterator iter = tet_begin(); iter != tet_end(); ++ iter) {
00108         for (int j = 0; j < 4; j ++) {
00109             Tet::get_face_point_lids(j, node0, node1, node2);
00110             id_t face_id = insertFace((*iter).get_id(),
00111                                       (*iter).get_corner_id(node0),
00112                                       (*iter).get_corner_id(node1),
00113                                       (*iter).get_corner_id(node2));
00114             (*iter).set_face_id(j, face_id);
00115         }
00116     }
00117     // dump_face_map(cerr);
00118 }
00119 
00120 id_t TetMesh::insertEdge(id_t node0, id_t node1) {
00121     if (node0 > node1)    /* force n0 < n1 */
00122         std::swap<id_t>(node0, node1);
00123     EdgeMapKey key(node0, node1);
00124     EdgeMap::iterator iter = _edgeMap.find(key);
00125     if (iter == _edgeMap.end()) {
00126         _edges.push_back(Edge(_nofEdge, node0, node1));
00127         id_t edge = _nofEdge;
00128         _edgeMap[key] = edge;
00129         _nofEdge += 1;
00130         return edge;
00131     } else
00132         return (*iter).second;
00133 }
00134 
00135 id_t TetMesh::insertFace(id_t tet, id_t node0, id_t node1, id_t node2) {
00136     // sort node ids in ascending order
00137     if (node0 > node1)
00138         std::swap<id_t>(node0, node1);
00139     if (node1 > node2)
00140         std::swap<id_t>(node1, node2);
00141     if (node0 > node1)
00142         std::swap<id_t>(node0, node1);
00143 
00144     // generate key for map
00145     FaceMapKey key(node0, node1, node2);
00146     // find corresponding entry in map
00147     FaceMap::iterator iter = _faceMap.find(key);
00148     
00149     //cout << "TetMesh inserting "<<tet<<" local nodes "<<node0<<","<<node1<<","<<node2<<endl;
00150     
00151     if (iter == _faceMap.end()) {
00152         // no entry found: create new face and insert it in map
00153         _faces.push_back(Face(_nofFace, node0, node1, node2, tet));
00154         _faceMap[key] = _nofFace;
00155         return _nofFace ++;
00156     } else {
00157         // set 2nd parent tet for face
00158         id_t face_id = (*iter).second;
00159         get_face(face_id)->set_tet_id(tet);
00160         // return id of face stored in map
00161         return face_id;
00162     }
00163 }
00164 
00165 id_t TetMesh::lookupEdge(id_t node0, id_t node1) {
00166     if (node0 > node1)    /* force n0 < n1 */
00167         std::swap<id_t>(node0, node1);
00168 
00169     EdgeMap::iterator iter = _edgeMap.find(EdgeMapKey(node0, node1));
00170     if (iter == _edgeMap.end())
00171         throw std::runtime_error("Accessed non-existing edge.");
00172     return (*iter).second;
00173 }
00174 
00175 id_t TetMesh::lookupFace(id_t node0, id_t node1, id_t node2) {
00176     // sort node ids in ascending order
00177     if (node0 > node1)
00178         std::swap<id_t>(node0, node1);
00179     if (node1 > node2)
00180         std::swap<id_t>(node1, node2);
00181     if (node0 > node1)
00182         std::swap<id_t>(node0, node1);
00183 
00184     FaceMap::iterator iter = _faceMap.find(FaceMapKey(node0, node1, node2));
00185     if (iter == _faceMap.end())    
00186         throw std::runtime_error("Accessed non-existing face.");
00187     return (*iter).second;
00188 }
00189 
00190 void TetMesh::dump_face_map(ostream& os) {
00191     os << "face map dump:" << endl;
00192     FaceMap::iterator it(_faceMap.begin());
00193     for (; it != _faceMap.end(); ++ it) {
00194         os << (*it).first.first << ", " <<  
00195               (*it).first.second << ", " <<  
00196               (*it).first.third << ": " <<  
00197               (*it).second <<  
00198               endl;
00199     }
00200 }
00201 
00202 void TetMesh::setBoundaryOnFace(id_t face_id) {
00203     Face* face = get_face(face_id);
00204     id_t corners[3] = { face->get_corner_id(0),
00205                         face->get_corner_id(1),
00206                         face->get_corner_id(2) };
00207     face->set_boundary(true);
00208 
00209     for (int i = 0; i < 3; i ++)
00210         get_point(corners[i])->set_boundary(true);
00211 
00212     get_edge(lookupEdge(corners[0], corners[1]))->set_boundary(true);
00213     get_edge(lookupEdge(corners[0], corners[2]))->set_boundary(true);
00214     get_edge(lookupEdge(corners[1], corners[2]))->set_boundary(true);
00215 }
00216 
00217 void TetMesh::setSymmetryPlaneOnFace(id_t face_id, int sym_id) {
00218     Face* face = get_face(face_id);
00219     id_t corners[3] = { face->get_corner_id(0),
00220                         face->get_corner_id(1),
00221                         face->get_corner_id(2) };
00222     face->set_symmetry_plane(sym_id);
00223 
00224     for (int i = 0; i < 3; i ++)
00225         get_point(corners[i])->set_symmetry_plane(sym_id);
00226 
00227     get_edge(lookupEdge(corners[0], corners[1]))->set_symmetry_plane(sym_id);
00228     get_edge(lookupEdge(corners[0], corners[2]))->set_symmetry_plane(sym_id);
00229     get_edge(lookupEdge(corners[1], corners[2]))->set_symmetry_plane(sym_id);
00230 }
00231 
00232 void TetMesh::finalize_mesh(int nofSym) {
00233     _nofSym = nofSym;
00234     // Edge and face maps are no longer needed. Erase all their data.
00235     // FIXME: Hopefully clear() really frees up the allocated memory (at least glibc++ 
00236     //        delallocates all memory).
00237     _edgeMap.clear();
00238     _faceMap.clear();
00239 }
00240 
00241 Tet* TetMesh::get_tet(id_t id) const { 
00242     return const_cast<Tet *>(&_tets[id]); 
00243 }
00244 
00245 Face* TetMesh::get_face(id_t id) const {
00246     return const_cast<Face *>(&_faces[id]); 
00247 }
00248 
00249 Edge* TetMesh::get_edge(id_t id) const { 
00250     return const_cast<Edge *>(&_edges[id]); 
00251 }
00252 
00253 Point* TetMesh::get_point(id_t id) const { 
00254     return const_cast<Point *>(&_points[id]);
00255 }
00256 
00257 void TetMesh::log_mesh_info() {
00258     // estimate mem consumption of tet, face, edge and point objects
00259     unsigned long size = _nofTet * sizeof(Tet) * 11 / 10;
00260     size += _nofFace * sizeof(Face) * 11 / 10;
00261     size += _nofEdge * sizeof(Edge) * 11 / 10;
00262     size += _nofPoint * sizeof(Point) * 11 / 10;
00263     // estimate mem consumption of edge and face maps (raw data + 10% overhead)
00264     size += _nofEdge * sizeof(EdgeMapKey) + sizeof(id_t) * 11 / 10;
00265     size += _nofFace * sizeof(FaceMapKey) + sizeof(id_t) * 11 / 10;
00266     rInfo("Mesh stats: #tets=%d, #faces=%d, #edges=%d, #nodes=%d, #symplanes=%d, mem=%s",
00267           _nofTet, _nofFace, _nofEdge, _nofPoint, _nofSym, rlog::bytes2str(size).c_str());
00268     rDebug("sizeof(Tet)=%d, sizeof(Face)=%d, sizeof(Edge)=%d, sizeof(Point)=%d",
00269            static_cast<int>(sizeof(Tet)),
00270            static_cast<int>(sizeof(Face)),
00271            static_cast<int>(sizeof(Edge)),
00272            static_cast<int>(sizeof(Point)));
00273 }
00274 
00275 void TetMesh::get_bounding_box(Vector3& center, Vector3& extent) const {
00276     Vector3 min, max, coord;
00277 
00278     Point* point = get_point(0);
00279     min = point->get_coord();
00280     max = min;
00281     for (id_t i = 1; i < get_nof_points(); i ++) {
00282         coord = get_point(i)->get_coord();
00283         min.make_floor(coord);
00284         max.make_ceil(coord);
00285     }
00286     center = max.mid_point(min);
00287     extent = 0.5 * (max - min);
00288 }
00289 
00290 void TetMesh::construct_octree() {
00291     rAssert(_octree == 0);
00292     
00293     // bounding box of whole mesh
00294     Vector3 center, extent;
00295     get_bounding_box(center, extent);
00296 
00297     // octree length is the largest component of extent
00298     double length = extent.x;
00299     if (extent.y > length)
00300         length = extent.y;
00301     if (extent.z > length)
00302         length = extent.z;
00303   
00304     // construct LooseOctree with large max depth
00305     _octree = new LooseOctree<Tet>(center, length, 100);
00306 
00307     // loop over all tets and insert them in the octree
00308     for (id_t t = 0; t < get_nof_tets(); t ++) {
00309         _octree->add_node(get_tet(t));
00310     }
00311     int max_depth, nof_octants, nof_nodes;
00312     double avg_node_depth;
00313     _octree->get_statistics(max_depth, avg_node_depth, nof_octants, nof_nodes);
00314     rInfo("Octree stats: max. depth=%d, #octants=%d, #nodes=%d, avg. #node per octant=%.2f, avg. node depth=%.2f",
00315           max_depth, nof_octants, nof_nodes, static_cast<double>(nof_nodes)/nof_octants, avg_node_depth);
00316 
00317 #if 0
00318     // Vector3 p (0.000001, 0.000001, 0.000001);
00319     // Vector3 p (0.000000, 0.000000, 0.000000);
00320     // Vector3 p (1.00000071059, 0.500001458653, 0.106184447056);
00321     Vector3 p (0.1, 0.0, 2.6);
00322     std::vector<OctreeNode *> nodes;
00323     int nof_visited;
00324 
00325     cout << "Finding tets containing " << p << "\n\n";
00326 
00327     tet_iterator tet_it;
00328     cout << "Exhausive search yields (is_inside_bounding_box_gracious)\n";
00329     for (tet_it = tet_begin(); tet_it != tet_end(); ++ tet_it) {
00330         Tet* tet = *tet_it;
00331         if (tet->is_inside_bounding_box_gracious(p)) {
00332             std::cout << "inside tet " << tet->get_id() << "\n";
00333             for (int i = 0; i < 4; i ++) {
00334                 cout << "   " << tet->get_corner(i)->get_coord() << "\n";
00335             }
00336         }
00337     }
00338 
00339     cout << "Exhausive search yields (is_inside_bounding_box)\n";
00340     for (tet_it = tet_begin(); tet_it != tet_end(); ++ tet_it) {
00341         Tet* tet = *tet_it;
00342         if (tet->is_inside_bounding_box(p)) {
00343             std::cout << "inside tet " << tet->get_id() << "\n";
00344             for (int i = 0; i < 4; i ++) {
00345                 cout << "   " << tet->get_corner(i)->get_coord() << "\n";
00346             }
00347         }
00348     }
00349 
00350     cout << "Exhausive search yields (is_inside)\n";
00351     for (tet_it = tet_begin(); tet_it != tet_end(); ++ tet_it) {
00352         Tet* tet = *tet_it;
00353         if (tet->is_inside(p)) {
00354             std::cout << "inside tet " << tet->get_id() << "\n";
00355             for (int i = 0; i < 4; i ++) {
00356                 cout << "   " << tet->get_corner(i)->get_coord() << "\n";
00357             }
00358         }
00359     }
00360 
00361     cout << "\nOctree: is_inside_bounding_box\n";
00362     nof_visited = 0; nodes.resize(0);
00363     _octree->find_nodes_by_point(p, nodes, nof_visited,
00364                                  (&OctreeNode::is_inside_bounding_box));
00365     std::cout << "nof. nodes visited=" << nof_visited << "\n";
00366     std::cout << "nof. nodes found=" << nodes.size() << "\n";
00367     std::vector<OctreeNode *>::iterator it;
00368     for (it = nodes.begin(); it != nodes.end(); it ++) {
00369         Tet *tet = dynamic_cast<Tet*>(*it);
00370         if (tet->is_inside(p)) {
00371             std::cout << "inside tet " << tet->get_id() << "\n";
00372             for (int i = 0; i < 4; i ++) {
00373                 cout << "   " << tet->get_corner(i)->get_coord() << "\n";
00374             }
00375         }
00376     }
00377 
00378     cout << "\nOctree: is_inside_bounding_box_gracious\n";
00379     nof_visited = 0; nodes.resize(0);
00380     _octree->find_nodes_by_point(p, nodes, nof_visited,
00381                                  (&OctreeNode::is_inside_bounding_box_gracious));
00382     std::cout << "nof. nodes visited=" << nof_visited << "\n";
00383     std::cout << "nof. nodes found=" << nodes.size() << "\n";
00384     for (it = nodes.begin(); it != nodes.end(); it ++) {
00385         Tet *tet = dynamic_cast<Tet*>(*it);
00386         if (tet->is_inside(p)) {
00387             std::cout << "inside tet " << tet->get_id() << "\n";
00388             for (int i = 0; i < 4; i ++) {
00389                 cout << "   " << tet->get_corner(i)->get_coord() << "\n";
00390             }
00391         }
00392     }
00393    
00394     cout << "\nOctree: Tet::is_inside\n";
00395     nof_visited = 0; nodes.resize(0);
00396     _octree->find_nodes_by_point(p, nodes, nof_visited,
00397                                  (LooseOctree::filter)(&Tet::is_inside));
00398     std::cout << "nof. nodes visited=" << nof_visited << "\n";
00399     std::cout << "nof. nodes found=" << nodes.size() << "\n";
00400     for (it = nodes.begin(); it != nodes.end(); it ++) {
00401         Tet *tet = dynamic_cast<Tet*>(*it);
00402         if (tet->is_inside(p)) {
00403             std::cout << "inside tet " << tet->get_id() << "\n";
00404             for (int i = 0; i < 4; i ++) {
00405                 cout << "   " << tet->get_corner(i)->get_coord() << "\n";
00406             }
00407         }
00408     }
00409 
00410     cout << "\nOctree, find_one: Tet::is_inside\n";
00411     nof_visited = 0;
00412     // this is a dangerous typecast: it's only valid since we know all nodes in the
00413     // octree are Tets.
00414     OctreeNode* node = _octree->find_one_node_by_point(p, nof_visited, (LooseOctree::filter)(&Tet::is_inside));
00415     std::cout << "nof. nodes visited=" << nof_visited << "\n";
00416     if (node) {
00417         std::cout << "nof. nodes found=" << 1 << "\n";
00418         Vector4 p_simplex;
00419         dynamic_cast<Tet *>(node)->cartesian_to_simplex(p, p_simplex);
00420         cout << "is_inside(p) is " << dynamic_cast<Tet *>(node)->is_inside(p) << "\n";
00421         std::cout << "inside tet " << dynamic_cast<Tet *>(node)->get_id() << "\n";
00422         for (int i = 0; i < 4; i ++) {
00423             cout << "   " << dynamic_cast<Tet*>(node)->get_corner(i)->get_coord() << "\n";
00424         }
00425         cout << "p_simplex=" << p_simplex << "\n";
00426     }
00427 
00428     {
00429         Vector3 center, extent;
00430         get_tet(6488)->get_bounding_box(center, extent);
00431         cout.precision(17);
00432         cout << "\n\ncenter: " << center << "\nextent: " << extent << "\n";
00433         center -= p;
00434         center.x = fabs(center.x);
00435         center.y = fabs(center.y);
00436         center.z = fabs(center.z);
00437         cout << "|c-p|: " << center
00438              << "\nextend - |c-p|:" << extent - center
00439              << "\nextend_ - |c-p|:" << extent*(1+1e-13) - center
00440              << "\nbool: " << (center <= extent) << "\n";
00441         _octree->add_node(get_tet(6488))->dump(cout);
00442         cout << "eps_mach=" << std::numeric_limits<double>::epsilon() << "\n";
00443     }
00444 #endif
00445 }
00446 
00447 void TetMesh::find_tets_by_point(const Vector3& p, vector<Tet *>& tets) const {
00448     assert(_octree);
00449 
00450     pbe_start(132, "Octree traversal");
00451 
00452     // Get list of nodes (Tets) whose bounding box contain point p
00453     std::vector<Tet*> nodes;
00454     int nof_visited = 0;
00455     _octree->find_nodes_by_point(p, nodes, nof_visited, &Tet::is_inside_bounding_box_gracious);
00456 
00457     // Create list of tets containing point p
00458     tets.resize(0);
00459     std::vector<Tet*>::iterator it;
00460     for (it = nodes.begin(); it != nodes.end(); ++ it) {
00461         if ((*it)->is_inside_gracious(p))
00462             tets.push_back(*it);
00463     }
00464 
00465     pbe_stop(132);
00466     // rDebug("find_tets_by_point: nof_found=%d, nof_visited=%d", static_cast<int>(nodes.size()), nof_visited);
00467 }
00468 
00469 } // namespace mesh

Generated on Fri Oct 26 13:35:13 2007 for FEMAXX (Finite Element Maxwell Eigensolver) by  doxygen 1.4.7