QuadraticMesh.cpp

00001 /*
00002 
00003 Copyright (c) 2005-2015, University of Oxford.
00004 All rights reserved.
00005 
00006 University of Oxford means the Chancellor, Masters and Scholars of the
00007 University of Oxford, having an administrative office at Wellington
00008 Square, Oxford OX1 2JD, UK.
00009 
00010 This file is part of Chaste.
00011 
00012 Redistribution and use in source and binary forms, with or without
00013 modification, are permitted provided that the following conditions are met:
00014  * Redistributions of source code must retain the above copyright notice,
00015    this list of conditions and the following disclaimer.
00016  * Redistributions in binary form must reproduce the above copyright notice,
00017    this list of conditions and the following disclaimer in the documentation
00018    and/or other materials provided with the distribution.
00019  * Neither the name of the University of Oxford nor the names of its
00020    contributors may be used to endorse or promote products derived from this
00021    software without specific prior written permission.
00022 
00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00024 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00025 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00026 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033 
00034 */
00035 
00036 #include "QuadraticMesh.hpp"
00037 #include "OutputFileHandler.hpp"
00038 #include "TrianglesMeshReader.hpp"
00039 #include "Warnings.hpp"
00040 #include "QuadraticMeshHelper.hpp"
00041 
00042 //Jonathan Shewchuk's Triangle and Hang Si's TetGen
00043 #define REAL double
00044 #define VOID void
00045 #include "triangle.h"
00046 #include "tetgen.h"
00047 #undef REAL
00048 #undef VOID
00049 
00050 template<unsigned DIM>
00051 void QuadraticMesh<DIM>::CountVertices()
00052 {
00053     mNumVertices = 0;
00054     for (unsigned i=0; i<this->GetNumNodes(); i++)
00055     {
00056         bool is_internal = this->GetNode(i)->IsInternal();
00057         if (is_internal==false)
00058         {
00059             mNumVertices++;
00060         }
00061     }
00062 }
00063 
00064 template<unsigned DIM>
00065 QuadraticMesh<DIM>::QuadraticMesh(double spaceStep, double width, double height, double depth)
00066 {
00067     this->ConstructRegularSlabMesh(spaceStep, width, height, depth);
00068 }
00069 
00071 // Badly-named (name inherited from parent class),
00072 // 'linear' here refers to the fact it creates a 1d mesh
00073 // on a line
00075 template<unsigned DIM>
00076 void QuadraticMesh<DIM>::ConstructLinearMesh(unsigned numElemX)
00077 {
00078     assert(DIM==1);
00079 
00080     AbstractTetrahedralMesh<DIM,DIM>::ConstructLinearMesh(numElemX);
00081     assert (this->mNodes.size() == numElemX+1);
00082     mNumVertices = numElemX+1;
00083     c_vector<double, DIM> top;
00084     top[0] = numElemX;
00085 
00086     unsigned mid_node_index=mNumVertices;
00087     for (unsigned element_index=0; element_index<numElemX; element_index++)
00088     {
00089         c_vector<double, DIM> x_value_mid_node;
00090         x_value_mid_node[0] = element_index+0.5;
00091 
00092         Node<DIM>* p_mid_node = MakeNewInternalNode(mid_node_index, x_value_mid_node, top);
00093 
00094         //Put in element and cross-reference
00095         this->mElements[element_index]->AddNode(p_mid_node);
00096         p_mid_node->AddElement(element_index);
00097     }
00098 
00099     this->RefreshMesh();
00100 }
00101 
00102 
00103 
00104 
00105 
00106 template<unsigned DIM>
00107 void QuadraticMesh<DIM>::ConstructRectangularMesh(unsigned numElemX, unsigned numElemY, bool stagger)
00108 {
00109     assert(DIM==2);
00110     assert(numElemX > 0);
00111     assert(numElemY > 0);
00112 
00113     AbstractTetrahedralMesh<DIM,DIM>::ConstructRectangularMesh(numElemX, numElemY, stagger);
00114 
00115     this->mMeshIsLinear=false;
00116     //Make the internal nodes in y-order.  This is important for the distributed case, since we want the top and bottom
00117     //layers to have predictable numbers
00118     std::map<std::pair<unsigned, unsigned>, unsigned> edge_to_internal_map;
00119 
00120     unsigned node_index = this->GetNumNodes();
00121     c_vector<double, DIM> top;
00122     top[0]=numElemX;
00123     top[1]=numElemY;
00124     c_vector<double, DIM> node_pos;
00125 
00126     for (unsigned j=0; j<numElemY+1; j++)
00127     {
00128         node_pos[1]=j;
00129         //Add mid-way nodes to horizontal edges in this slice
00130         for (unsigned i=0; i<numElemX; i++)
00131         {
00132             unsigned left_index = j*(numElemX+1) + i;
00133             std::pair<unsigned,unsigned> edge(left_index, left_index+1 ) ;
00134             edge_to_internal_map[edge] = node_index;
00135             node_pos[0]=i+0.5;
00136             MakeNewInternalNode(node_index, node_pos, top);
00137         }
00138 
00139         //Add the vertical and diagonal nodes to the mid-way above the last set of horizontal edges
00140         node_pos[1] = j+0.5;
00141         for (unsigned i=0; i<numElemX+1; i++)
00142         {
00143             node_pos[0] = i;
00144             unsigned left_index = j*(numElemX+1) + i;
00145             std::pair<unsigned,unsigned> edge(left_index, left_index+(numElemX+1) ) ;
00146             edge_to_internal_map[edge] = node_index;
00147             MakeNewInternalNode(node_index, node_pos, top);
00148             unsigned parity=(i+(numElemY-j))%2;
00149             if (stagger==false || parity==1) //Default when no stagger
00150             {
00151                 //backslash
00152                 std::pair<unsigned,unsigned> back_edge(left_index+1, left_index+(numElemX+1) ) ;
00153                 edge_to_internal_map[back_edge] = node_index;
00154             }
00155             else
00156             {
00157                 //foward slash
00158                 std::pair<unsigned,unsigned> forward_edge(left_index, left_index+(numElemX+1)+1 ) ;
00159                 edge_to_internal_map[forward_edge] = node_index;
00160             }
00161             node_pos[0] = i+0.5;
00162             MakeNewInternalNode(node_index, node_pos, top);
00163         }
00164     }
00165     CountVertices();
00166 
00167 //    assert(edge_to_internal_map.size() == this->GetNumNodes()-this->GetNumVertices());
00168     for (typename AbstractTetrahedralMesh<DIM,DIM>::ElementIterator iter = this->GetElementIteratorBegin();
00169          iter != this->GetElementIteratorEnd();
00170          ++iter)
00171     {
00172         unsigned local_index1=0;
00173         for (unsigned index=0; index<=DIM; index++)
00174         {
00175             local_index1 = (local_index1+1)%(DIM+1);
00176             unsigned local_index2 = (local_index1+1)%(DIM+1);
00177             unsigned global_index1 =  iter->GetNodeGlobalIndex(local_index1);
00178             unsigned global_index2 =  iter->GetNodeGlobalIndex(local_index2);
00179             unsigned new_node_index = LookupInternalNode(global_index1, global_index2, edge_to_internal_map);
00180             iter->AddNode(this->mNodes[new_node_index]);
00181             this->mNodes[new_node_index]->AddElement(iter->GetIndex());
00182         }
00183     }
00184 
00185     for (typename AbstractTetrahedralMesh<DIM,DIM>::BoundaryElementIterator iter = this->GetBoundaryElementIteratorBegin();
00186          iter != this->GetBoundaryElementIteratorEnd();
00187          ++iter)
00188     {
00189         unsigned global_index1 =  (*iter)->GetNodeGlobalIndex(0);
00190         unsigned global_index2 =  (*iter)->GetNodeGlobalIndex(1);
00191         unsigned new_node_index = LookupInternalNode(global_index1, global_index2, edge_to_internal_map);
00192         (*iter)->AddNode(this->mNodes[new_node_index]);
00193         this->mNodes[new_node_index]->AddBoundaryElement((*iter)->GetIndex());
00194     }
00195 
00196     this->RefreshMesh();
00197 }
00198 
00199 template<unsigned DIM>
00200 Node<DIM>* QuadraticMesh<DIM>::MakeNewInternalNode(unsigned& rIndex, c_vector<double, DIM>& rLocation, c_vector<double, DIM>& rTop)
00201 {
00202     bool boundary = false;
00203     for (unsigned dim=0; dim<DIM; dim++)
00204     {
00205         if (rLocation[dim] > rTop[dim])
00206         {
00207             //Outside the box so don't do anything
00208             return NULL;
00209         }
00210         if ( (rLocation[dim] == 0.0) || (rLocation[dim] == rTop[dim]) )
00211         {
00212             boundary = true;
00213         }
00214     }
00215     //The caller needs to know that rIndex is in sync with what's in the mesh
00216     assert(rIndex == this->mNodes.size());
00217     Node<DIM>* p_node   = new Node<DIM>(rIndex++, rLocation, boundary);
00218     p_node->MarkAsInternal();
00219     //Put in mesh
00220     this->mNodes.push_back(p_node);
00221     if (boundary)
00222     {
00223         this->mBoundaryNodes.push_back(p_node);
00224     }
00225     return p_node;
00226 }
00227 
00228 template<unsigned DIM>
00229 unsigned QuadraticMesh<DIM>::LookupInternalNode(unsigned globalIndex1, unsigned globalIndex2, std::map<std::pair<unsigned, unsigned>, unsigned>& rEdgeMap)
00230 {
00231     unsigned node_index = 0u;
00232     assert(globalIndex1 != globalIndex2);
00233     if (globalIndex1 < globalIndex2)
00234     {
00235         node_index = rEdgeMap[std::pair<unsigned,unsigned>(globalIndex1, globalIndex2)];
00236     }
00237     else
00238     {
00239         node_index = rEdgeMap[std::pair<unsigned,unsigned>(globalIndex2, globalIndex1)];
00240     }
00241     //A failure to find the key would result in a new zero entry in the map.  Note that no *internal* node will have global index zero.
00242     assert(node_index != 0u);
00243     return node_index;
00244 }
00245 
00246 template<unsigned DIM>
00247 void QuadraticMesh<DIM>::ConstructCuboid(unsigned numElemX, unsigned numElemY, unsigned numElemZ)
00248 {
00249     assert(DIM==3);
00250 
00251     assert(numElemX > 0);
00252     assert(numElemY > 0);
00253     assert(numElemZ > 0);
00254 
00255     AbstractTetrahedralMesh<DIM,DIM>::ConstructCuboid(numElemX, numElemY, numElemZ);
00256     c_vector<double, DIM> top;
00257     top[0]=numElemX;
00258     top[1]=numElemY;
00259     top[2]=numElemZ;
00260     c_vector<double, DIM> node_pos;
00261     this->mMeshIsLinear=false;
00262     //Make the internal nodes in z-order.  This is important for the distributed case, since we want the top and bottom
00263     //layers to have predictable numbers
00264     std::map<std::pair<unsigned, unsigned>, unsigned> edge_to_internal_map;
00265     unsigned node_index = this->GetNumNodes();
00266     for (unsigned k=0; k<numElemZ+1; k++)
00267     {
00268         //Add a slice of the mid-points to the edges and faces at this z=level
00269         node_pos[2] = k;
00270         for (unsigned j=0; j<numElemY+1; j++)
00271         {
00272             unsigned lo_z_lo_y = (numElemX+1)*((numElemY+1)*k + j);
00273             unsigned lo_z_hi_y = (numElemX+1)*((numElemY+1)*k + j + 1);
00274 
00275             node_pos[1] = j;
00276 
00277             //The midpoints along the horizontal (y fixed) edges
00278             for (unsigned i=0; i<numElemX+1; i++)
00279             {
00280                 // i+.5, j, k
00281                 std::pair<unsigned,unsigned> edge(lo_z_lo_y+i, lo_z_lo_y+i+1);
00282                 edge_to_internal_map[edge] = node_index;
00283                 node_pos[0] = i+0.5;
00284                 MakeNewInternalNode(node_index, node_pos, top);
00285             }
00286             //The midpoints and face centres between two horizontal (y-fixed) strips
00287             node_pos[1] = j+0.5;
00288             for (unsigned i=0; i<numElemX+1; i++)
00289             {
00290                 // i, j+0.5, k
00291                 std::pair<unsigned,unsigned> edge(lo_z_lo_y+i, lo_z_hi_y+i);
00292                 edge_to_internal_map[edge] = node_index;
00293                 node_pos[0] = i;
00294                 MakeNewInternalNode(node_index, node_pos, top);
00295                 //Centre of face node
00296                 // i+0.5, j+0.5, k
00297                 std::pair<unsigned,unsigned> edge2(lo_z_lo_y+i, lo_z_hi_y+i+1);
00298                 edge_to_internal_map[edge2] = node_index;
00299                 node_pos[0] = i+0.5;
00300                 MakeNewInternalNode(node_index, node_pos, top);
00301             }
00302         }
00303         //Add a slice of the mid-points to the edges and faces mid-way up the cube z=level
00304         node_pos[2] = k+0.5;
00305         for (unsigned j=0; j<numElemY+1; j++)
00306         {
00307             node_pos[1] = j;
00308             unsigned lo_z_lo_y = (numElemX+1)*((numElemY+1)*k + j);
00309             unsigned hi_z_lo_y = (numElemX+1)*((numElemY+1)*(k+1) + j);
00310             unsigned hi_z_hi_y = (numElemX+1)*((numElemY+1)*(k+1) + j + 1);
00311 
00312             //The midpoints along the horizontal (y fixed) edges
00313             for (unsigned i=0; i<numElemX+1; i++)
00314             {
00315                 // i, j, k+0.5
00316                 std::pair<unsigned,unsigned> edge(lo_z_lo_y+i, hi_z_lo_y+i);
00317                 edge_to_internal_map[edge] = node_index;
00318                 node_pos[0] = i;
00319                 MakeNewInternalNode(node_index, node_pos, top);
00320 
00321                 // i+0.5, j, k+0.5
00322                 node_pos[0] = i+0.5;
00323                 std::pair<unsigned,unsigned> edge2(lo_z_lo_y+i, hi_z_lo_y+i+1);
00324                 edge_to_internal_map[edge2] = node_index;
00325                 MakeNewInternalNode(node_index, node_pos, top);
00326             }
00327             //The midpoints and face centres between two horizontal (y-fixed) strips
00328             node_pos[1] = j+0.5;
00329             for (unsigned i=0; i<numElemX+1; i++)
00330             {
00331                 // i, j+0.5, k+0.5
00332                 std::pair<unsigned,unsigned> edge(lo_z_lo_y+i, hi_z_hi_y+i);
00333                 edge_to_internal_map[edge] = node_index;
00334                 node_pos[0] = i;
00335                 MakeNewInternalNode(node_index, node_pos, top);
00336                 //Centre of face node on the main diagonal
00337                 // i+0.5, j+0.5, k+0.5
00338                 std::pair<unsigned,unsigned> edge2(lo_z_lo_y+i, hi_z_hi_y+i+1);
00339                 edge_to_internal_map[edge2] = node_index;
00340                 node_pos[0] = i+0.5;
00341                 MakeNewInternalNode(node_index, node_pos, top);
00342             }
00343         }
00344 
00345     }
00346     CountVertices();
00347     for (typename AbstractTetrahedralMesh<DIM,DIM>::ElementIterator iter = this->GetElementIteratorBegin();
00348          iter != this->GetElementIteratorEnd();
00349          ++iter)
00350     {
00351         /* The standard tetgen ordering of the internal nodes 4,5,6..9 (using the
00352          * zero-based numbering scheme) is
00353          * 4 (0,1), 5 (1,2), 6 (0,2) 7 (0,3), 8 (1,3), 9 (2,3)
00354          * i.e. internal node with local index 4 is half-way between vertex nodes
00355          * with local indices 0 and 1.
00356          */
00357          unsigned v0=iter->GetNodeGlobalIndex(0);
00358          unsigned v1=iter->GetNodeGlobalIndex(1);
00359          unsigned v2=iter->GetNodeGlobalIndex(2);
00360          unsigned v3=iter->GetNodeGlobalIndex(3);
00361          unsigned internal_index;
00362 
00363          //4
00364          internal_index=LookupInternalNode(v0, v1, edge_to_internal_map);
00365          iter->AddNode(this->mNodes[internal_index]);
00366          this->mNodes[internal_index]->AddElement(iter->GetIndex());
00367          //5
00368          internal_index=LookupInternalNode(v1, v2, edge_to_internal_map);
00369          iter->AddNode(this->mNodes[internal_index]);
00370          this->mNodes[internal_index]->AddElement(iter->GetIndex());
00371          //6
00372          internal_index=LookupInternalNode(v0, v2, edge_to_internal_map);
00373          iter->AddNode(this->mNodes[internal_index]);
00374          this->mNodes[internal_index]->AddElement(iter->GetIndex());
00375          //7
00376          internal_index=LookupInternalNode(v0, v3, edge_to_internal_map);
00377          iter->AddNode(this->mNodes[internal_index]);
00378          this->mNodes[internal_index]->AddElement(iter->GetIndex());
00379          //8
00380          internal_index=LookupInternalNode(v1, v3, edge_to_internal_map);
00381          iter->AddNode(this->mNodes[internal_index]);
00382          this->mNodes[internal_index]->AddElement(iter->GetIndex());
00383          //9
00384          internal_index=LookupInternalNode(v2, v3, edge_to_internal_map);
00385          iter->AddNode(this->mNodes[internal_index]);
00386          this->mNodes[internal_index]->AddElement(iter->GetIndex());
00387 
00388     }
00389     for (typename AbstractTetrahedralMesh<DIM,DIM>::BoundaryElementIterator iter = this->GetBoundaryElementIteratorBegin();
00390          iter != this->GetBoundaryElementIteratorEnd();
00391          ++iter)
00392     {
00393         unsigned local_index1=0;
00394         for (unsigned index=0; index<DIM; index++)
00395         {
00396             local_index1 = (local_index1+1)%(DIM);
00397             unsigned local_index2 = (local_index1+1)%(DIM);
00398             unsigned global_index1 =  (*iter)->GetNodeGlobalIndex(local_index1);
00399             unsigned global_index2 =  (*iter)->GetNodeGlobalIndex(local_index2);
00400             unsigned new_node_index = LookupInternalNode(global_index1, global_index2, edge_to_internal_map);
00401             (*iter)->AddNode(this->mNodes[new_node_index]);
00402             this->mNodes[new_node_index]->AddBoundaryElement((*iter)->GetIndex());
00403         }
00404 
00405     }
00406     this->RefreshMesh();
00407 }
00408 
00409 
00410 
00411 template<unsigned DIM>
00412 unsigned QuadraticMesh<DIM>::GetNumVertices() const
00413 {
00414     return mNumVertices;
00415 }
00416 
00417 
00418 template<unsigned DIM>
00419 void QuadraticMesh<DIM>::ConstructFromLinearMeshReader(AbstractMeshReader<DIM, DIM>& rMeshReader)
00420 {
00421     assert(DIM != 1);
00422 
00423     //Make a linear mesh
00424     TetrahedralMesh<DIM,DIM>::ConstructFromMeshReader(rMeshReader);
00425 
00426     NodeMap unused_map(this->GetNumNodes());
00427 
00428     if (DIM==2)  // In 2D, remesh using triangle via library calls
00429     {
00430         struct triangulateio mesher_input, mesher_output;
00431         this->InitialiseTriangulateIo(mesher_input);
00432         this->InitialiseTriangulateIo(mesher_output);
00433 
00434         mesher_input.numberoftriangles = this->GetNumElements();
00435         mesher_input.trianglelist = (int *) malloc(this->GetNumElements() * (DIM+1) * sizeof(int));
00436         this->ExportToMesher(unused_map, mesher_input, mesher_input.trianglelist);
00437 
00438         // Library call
00439         triangulate((char*)"Qzero2", &mesher_input, &mesher_output, NULL);
00440 
00441         this->ImportFromMesher(mesher_output, mesher_output.numberoftriangles, mesher_output.trianglelist, mesher_output.numberofedges, mesher_output.edgelist, mesher_output.edgemarkerlist);
00442         CountVertices();
00443         QuadraticMeshHelper<DIM>::AddNodesToBoundaryElements(this, NULL);
00444 
00445         //Tidy up triangle
00446         this->FreeTriangulateIo(mesher_input);
00447         this->FreeTriangulateIo(mesher_output);
00448     }
00449     else // in 3D, remesh using tetgen
00450     {
00451 
00452         class tetgen::tetgenio mesher_input, mesher_output;
00453 
00454         mesher_input.numberoftetrahedra = this->GetNumElements();
00455         mesher_input.tetrahedronlist = new int[this->GetNumElements() * (DIM+1)];
00456         this->ExportToMesher(unused_map, mesher_input, mesher_input.tetrahedronlist);
00457 
00458         // Library call
00459         tetgen::tetrahedralize((char*)"Qzro2", &mesher_input, &mesher_output);
00460 
00461         this->ImportFromMesher(mesher_output, mesher_output.numberoftetrahedra, mesher_output.tetrahedronlist, mesher_output.numberoftrifaces, mesher_output.trifacelist, NULL);
00462         CountVertices();
00463         QuadraticMeshHelper<DIM>::AddNodesToBoundaryElements(this, NULL);
00464     }
00465 }
00466 
00467 
00468 template<unsigned DIM>
00469 void QuadraticMesh<DIM>::ConstructFromMeshReader(AbstractMeshReader<DIM, DIM>& rAbsMeshReader)
00470 {
00471     //Some mesh readers will let you read with non-linear elements
00472     unsigned order_of_elements = rAbsMeshReader.GetOrderOfElements();
00473 
00474     // If it is a linear mesh reader
00475     if (order_of_elements == 1)
00476     {
00477         WARNING("Reading a (linear) tetrahedral mesh and converting it to a QuadraticMesh.  This involves making an external library call to Triangle/Tetgen in order to compute internal nodes");
00478         ConstructFromLinearMeshReader(rAbsMeshReader);
00479         return;
00480     }
00481 
00482     TetrahedralMesh<DIM,DIM>::ConstructFromMeshReader(rAbsMeshReader);
00483     assert(this->GetNumBoundaryElements() > 0);
00484 
00485     QuadraticMeshHelper<DIM>::AddInternalNodesToElements(this, &rAbsMeshReader);
00486     CountVertices();
00487     QuadraticMeshHelper<DIM>::AddInternalNodesToBoundaryElements(this, &rAbsMeshReader);
00488     QuadraticMeshHelper<DIM>::CheckBoundaryElements(this);
00489 }
00490 
00492 // Explicit instantiation
00494 
00495 
00496 template class QuadraticMesh<1>;
00497 template class QuadraticMesh<2>;
00498 template class QuadraticMesh<3>;
00499 
00500 
00501 // Serialization for Boost >= 1.36
00502 #include "SerializationExportWrapperForCpp.hpp"
00503 EXPORT_TEMPLATE_CLASS_SAME_DIMS(QuadraticMesh)

Generated by  doxygen 1.6.2