Chaste Release::3.1
QuadraticMesh.cpp
00001 /*
00002 
00003 Copyright (c) 2005-2012, 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>::CountAndCheckVertices()
00052 {
00053     // count the number of vertices, and also check all vertices come before the
00054     // rest of the nodes (as this is assumed in
00055     // AbstractNonlinearElasticitySolver<DIM>::AllocateMatrixMemory() )
00056     //
00057     mNumVertices = 0;
00058     for (unsigned i=0; i<this->GetNumNodes(); i++)
00059     {
00060         bool is_internal = this->GetNode(i)->IsInternal();
00061         if (is_internal==false)
00062         {
00063             mNumVertices++;
00064         }
00065     }
00066 }
00067 
00068 template<unsigned DIM>
00069 QuadraticMesh<DIM>::QuadraticMesh(double spaceStep, double width, double height, double depth)
00070 {
00071     this->ConstructRegularSlabMesh(spaceStep, width, height, depth);
00072 }
00073 
00074 template<unsigned DIM>
00075 void QuadraticMesh<DIM>::ConstructLinearMesh(unsigned numElemX)
00076 {
00077     AbstractTetrahedralMesh<DIM,DIM>::ConstructLinearMesh(numElemX);
00078     assert (this->mNodes.size() == numElemX+1);
00079     mNumVertices = numElemX+1;
00080     this->mNodes.resize(2*numElemX+1);
00081 
00082     for (unsigned element_index=0; element_index<numElemX; element_index++)
00083     {
00084         unsigned mid_node_index = mNumVertices + element_index;
00085         double x_value_mid_node = element_index+0.5;
00086 
00087         //Make internal node
00088         Node<DIM>* p_mid_node   = new Node<DIM>(mid_node_index, false, x_value_mid_node);
00089         p_mid_node->MarkAsInternal();
00090         //Put in mesh
00091         this->mNodes[mid_node_index] = p_mid_node;
00092         //Put in element and cross-reference
00093         this->mElements[element_index]->AddNode(p_mid_node);
00094         p_mid_node->AddElement(element_index);
00095 
00096     }
00097 
00098     this->RefreshMesh();
00099 }
00100 
00101 
00102 
00103 
00104 template<unsigned DIM>
00105 void QuadraticMesh<DIM>::ConstructRectangularMesh(unsigned numElemX, unsigned numElemY, bool unused)
00106 {
00107     assert(DIM==2);
00108 
00109     assert(numElemX > 0);
00110     assert(numElemY > 0);
00111     assert(unused);
00112 
00113     this->mMeshIsLinear=false;
00114     unsigned num_nodes=(numElemX+1)*(numElemY+1);
00115     struct triangulateio mesher_input;
00116 
00117     this->InitialiseTriangulateIo(mesher_input);
00118     mesher_input.pointlist = (double *) malloc( num_nodes * DIM * sizeof(double));
00119     mesher_input.numberofpoints = num_nodes;
00120 
00121     unsigned new_index = 0;
00122     for (unsigned j=0; j<=numElemY; j++)
00123     {
00124         double y = j;
00125         for (unsigned i=0; i<=numElemX; i++)
00126         {
00127             double x = i;
00128 
00129             mesher_input.pointlist[DIM*new_index] = x;
00130             mesher_input.pointlist[DIM*new_index + 1] = y;
00131             new_index++;
00132         }
00133     }
00134 
00135     // Make structure for output
00136     struct triangulateio mesher_output;
00137 
00138     this->InitialiseTriangulateIo(mesher_output);
00139 
00140     // Library call
00141     triangulate((char*)"Qzeo2", &mesher_input, &mesher_output, NULL);
00142 
00143     assert(mesher_output.numberofcorners == (DIM+1)*(DIM+2)/2);//Nodes per element (including internals, one per edge)
00144 
00145     this->ImportFromMesher(mesher_output, mesher_output.numberoftriangles, mesher_output.trianglelist, mesher_output.numberofedges, mesher_output.edgelist, mesher_output.edgemarkerlist);
00146 
00147     CountAndCheckVertices();
00148     QuadraticMeshHelper<DIM>::AddNodesToBoundaryElements(this, NULL);
00149 
00150     this->FreeTriangulateIo(mesher_input);
00151     this->FreeTriangulateIo(mesher_output);
00152 }
00153 
00154 
00155 
00156 template<unsigned DIM>
00157 void QuadraticMesh<DIM>::ConstructCuboid(unsigned numElemX, unsigned numElemY, unsigned numElemZ)
00158 {
00159     assert(DIM==3);
00160 
00161     assert(numElemX > 0);
00162     assert(numElemY > 0);
00163     assert(numElemZ > 0);
00164     this->mMeshIsLinear = false;
00165     unsigned num_nodes = (numElemX+1)*(numElemY+1)*(numElemZ+1);
00166 
00167     struct tetgen::tetgenio mesher_input;
00168     mesher_input.pointlist = new double[num_nodes * DIM];
00169     mesher_input.numberofpoints = num_nodes;
00170     unsigned new_index = 0;
00171     for (unsigned k=0; k<=numElemZ; k++)
00172     {
00173         double z = k;
00174         for (unsigned j=0; j<=numElemY; j++)
00175         {
00176             double y = j;
00177             for (unsigned i=0; i<=numElemX; i++)
00178             {
00179                 double x = i;
00180                 mesher_input.pointlist[DIM*new_index] = x;
00181                 mesher_input.pointlist[DIM*new_index + 1] = y;
00182                 mesher_input.pointlist[DIM*new_index + 2] = z;
00183                 new_index++;
00184             }
00185         }
00186     }
00187 
00188     // Library call
00189     struct tetgen::tetgenio mesher_output;
00190     tetgen::tetrahedralize((char*)"Qo2", &mesher_input, &mesher_output, NULL);
00191 
00192     assert(mesher_output.numberofcorners == (DIM+1)*(DIM+2)/2);//Nodes per element (including internals, one per edge)
00193 
00194     this->ImportFromMesher(mesher_output, mesher_output.numberoftetrahedra, mesher_output.tetrahedronlist, mesher_output.numberoftrifaces, mesher_output.trifacelist, NULL);
00195 
00196     CountAndCheckVertices();
00197     QuadraticMeshHelper<DIM>::AddNodesToBoundaryElements(this, NULL);
00198 }
00199 
00200 
00201 template<unsigned DIM>
00202 unsigned QuadraticMesh<DIM>::GetNumVertices() const
00203 {
00204     return mNumVertices;
00205 }
00206 
00207 
00208 template<unsigned DIM>
00209 void QuadraticMesh<DIM>::ConstructFromLinearMeshReader(AbstractMeshReader<DIM, DIM>& rMeshReader)
00210 {
00211     assert(DIM != 1);
00212 
00213     //Make a linear mesh
00214     TetrahedralMesh<DIM,DIM>::ConstructFromMeshReader(rMeshReader);
00215 
00216     NodeMap unused_map(this->GetNumNodes());
00217 
00218     if (DIM==2)  // In 2D, remesh using triangle via library calls
00219     {
00220         struct triangulateio mesher_input, mesher_output;
00221         this->InitialiseTriangulateIo(mesher_input);
00222         this->InitialiseTriangulateIo(mesher_output);
00223 
00224         mesher_input.numberoftriangles = this->GetNumElements();
00225         mesher_input.trianglelist = (int *) malloc(this->GetNumElements() * (DIM+1) * sizeof(int));
00226         this->ExportToMesher(unused_map, mesher_input, mesher_input.trianglelist);
00227 
00228         // Library call
00229         triangulate((char*)"Qzero2", &mesher_input, &mesher_output, NULL);
00230 
00231         this->ImportFromMesher(mesher_output, mesher_output.numberoftriangles, mesher_output.trianglelist, mesher_output.numberofedges, mesher_output.edgelist, mesher_output.edgemarkerlist);
00232         CountAndCheckVertices();
00233         QuadraticMeshHelper<DIM>::AddNodesToBoundaryElements(this, NULL);
00234 
00235         //Tidy up triangle
00236         this->FreeTriangulateIo(mesher_input);
00237         this->FreeTriangulateIo(mesher_output);
00238     }
00239     else // in 3D, remesh using tetgen
00240     {
00241 
00242         struct tetgen::tetgenio mesher_input, mesher_output;
00243 
00244         mesher_input.numberoftetrahedra = this->GetNumElements();
00245         mesher_input.tetrahedronlist = new int[this->GetNumElements() * (DIM+1)];
00246         this->ExportToMesher(unused_map, mesher_input, mesher_input.tetrahedronlist);
00247 
00248         // Library call
00249         tetgen::tetrahedralize((char*)"Qzro2", &mesher_input, &mesher_output);
00250 
00251         this->ImportFromMesher(mesher_output, mesher_output.numberoftetrahedra, mesher_output.tetrahedronlist, mesher_output.numberoftrifaces, mesher_output.trifacelist, NULL);
00252         CountAndCheckVertices();
00253         QuadraticMeshHelper<DIM>::AddNodesToBoundaryElements(this, NULL);
00254     }
00255 }
00256 
00257 
00258 template<unsigned DIM>
00259 void QuadraticMesh<DIM>::ConstructFromMeshReader(AbstractMeshReader<DIM, DIM>& rAbsMeshReader)
00260 {
00261     TrianglesMeshReader<DIM, DIM>* p_mesh_reader=dynamic_cast<TrianglesMeshReader<DIM, DIM>*>(&rAbsMeshReader);
00262 
00263     unsigned order_of_elements = 1;
00264     if (p_mesh_reader)
00265     {
00266         //A triangles mesh reader will let you read with non-linear elements
00267         order_of_elements = p_mesh_reader->GetOrderOfElements();
00268     }
00269 
00270     // If it is a linear TrianglesMeshReader or any other reader (which are all linear)
00271     if (order_of_elements == 1)
00272     {
00273         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");
00274         ConstructFromLinearMeshReader(rAbsMeshReader);
00275         return;
00276     }
00277 
00278     TetrahedralMesh<DIM,DIM>::ConstructFromMeshReader(*p_mesh_reader);
00279     assert(this->GetNumBoundaryElements() > 0);
00280 
00281     QuadraticMeshHelper<DIM>::AddInternalNodesToElements(this, p_mesh_reader);
00282     CountAndCheckVertices();
00283     QuadraticMeshHelper<DIM>::AddInternalNodesToBoundaryElements(this, p_mesh_reader);
00284     QuadraticMeshHelper<DIM>::CheckBoundaryElements(this);
00285 }
00286 
00288 // Explicit instantiation
00290 
00291 
00292 template class QuadraticMesh<1>;
00293 template class QuadraticMesh<2>;
00294 template class QuadraticMesh<3>;
00295 
00296 
00297 // Serialization for Boost >= 1.36
00298 #include "SerializationExportWrapperForCpp.hpp"
00299 EXPORT_TEMPLATE_CLASS_SAME_DIMS(QuadraticMesh)