QuadraticMesh.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2011
00004 
00005 University of Oxford means the Chancellor, Masters and Scholars of the
00006 University of Oxford, having an administrative office at Wellington
00007 Square, Oxford OX1 2JD, UK.
00008 
00009 This file is part of Chaste.
00010 
00011 Chaste is free software: you can redistribute it and/or modify it
00012 under the terms of the GNU Lesser General Public License as published
00013 by the Free Software Foundation, either version 2.1 of the License, or
00014 (at your option) any later version.
00015 
00016 Chaste is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00019 License for more details. The offer of Chaste under the terms of the
00020 License is subject to the License being interpreted in accordance with
00021 English Law and subject to any action against the University of Oxford
00022 being under the jurisdiction of the English Courts.
00023 
00024 You should have received a copy of the GNU Lesser General Public License
00025 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
00026 
00027 */
00028 
00029 #include "QuadraticMesh.hpp"
00030 #include "OutputFileHandler.hpp"
00031 #include "TrianglesMeshReader.hpp"
00032 #include "Warnings.hpp"
00033 
00034 //Jonathan Shewchuk's triangle and Hang Si's tetgen
00035 #define REAL double
00036 #define VOID void
00037 #include "triangle.h"
00038 #include "tetgen.h"
00039 #undef REAL
00040 #undef VOID
00041 
00042 template<unsigned DIM>
00043 void QuadraticMesh<DIM>::CountAndCheckVertices()
00044 {
00045     // count the number of vertices, and also check all vertices come before the
00046     // rest of the nodes (as this is assumed in
00047     // AbstractNonlinearElasticitySolver<DIM>::AllocateMatrixMemory() )
00048     //
00049     mNumVertices = 0;
00050     for (unsigned i=0; i<this->GetNumNodes(); i++)
00051     {
00052         bool is_internal = this->GetNode(i)->IsInternal();
00053         if (is_internal==false)
00054         {
00055             mNumVertices++;
00056         }
00057     }
00058 }
00059 
00060 template<unsigned DIM>
00061 QuadraticMesh<DIM>::QuadraticMesh(double spaceStep, double width, double height, double depth)
00062 {
00063     this->ConstructRegularSlabMesh(spaceStep, width, height, depth);
00064 }
00065 
00066 template<unsigned DIM>
00067 void QuadraticMesh<DIM>::ConstructLinearMesh(unsigned numElemX)
00068 {
00069     this->mNodes.resize(2*numElemX+1);
00070     mNumVertices = numElemX+1;
00071 
00072     // create the left-most node
00073     Node<DIM>* p_edge_node = new Node<DIM>(0, true, 0.0);
00074     this->mNodes[0] = p_edge_node; // create nodes
00075     this->mBoundaryNodes.push_back(p_edge_node);
00076     this->mBoundaryElements.push_back(new BoundaryElement<DIM-1,DIM>(0, p_edge_node) );
00077 
00078     for (unsigned element_index=0; element_index<numElemX; element_index++)
00079     {
00080         unsigned right_node_index = element_index+1;
00081         unsigned mid_node_index = mNumVertices + element_index;
00082 
00083         double x_value_right_x = right_node_index;
00084         double x_value_mid_node = x_value_right_x-0.5;
00085 
00086         bool is_boundary = (element_index+1==numElemX);
00087         Node<DIM>* p_right_node = new Node<DIM>(right_node_index, is_boundary, x_value_right_x);
00088         Node<DIM>* p_mid_node   = new Node<DIM>(mid_node_index, false, x_value_mid_node);
00089 
00090         this->mNodes[right_node_index] = p_right_node;
00091         this->mNodes[mid_node_index] = p_mid_node;
00092 
00093         if (element_index+1==numElemX) // right boundary
00094         {
00095             this->mBoundaryNodes.push_back(p_right_node);
00096             this->mBoundaryElements.push_back(new BoundaryElement<DIM-1,DIM>(1, p_right_node) );
00097         }
00098 
00099         std::vector<Node<DIM>*> nodes;
00100         nodes.push_back(this->mNodes[right_node_index-1]);
00101         nodes.push_back(this->mNodes[right_node_index]);
00102         nodes.push_back(this->mNodes[mid_node_index]);
00103         this->mElements.push_back(new Element<DIM,DIM>(element_index, nodes) );
00104     }
00105 
00106     this->RefreshMesh();
00107 }
00108 
00109 
00110 
00111 
00112 template<unsigned DIM>
00113 void QuadraticMesh<DIM>::ConstructRectangularMesh(unsigned numElemX, unsigned numElemY, bool unused)
00114 {
00115     assert(DIM==2);
00116 
00117     assert(numElemX > 0);
00118     assert(numElemY > 0);
00119     assert(unused);
00120 
00121     this->mMeshIsLinear=false;
00122     unsigned num_nodes=(numElemX+1)*(numElemY+1);
00123     struct triangulateio mesher_input;
00124 
00125     this->InitialiseTriangulateIo(mesher_input);
00126     mesher_input.pointlist = (double *) malloc( num_nodes * DIM * sizeof(double));
00127     mesher_input.numberofpoints = num_nodes;
00128 
00129     unsigned new_index = 0;
00130     for (unsigned j=0; j<=numElemY; j++)
00131     {
00132         double y = j;
00133         for (unsigned i=0; i<=numElemX; i++)
00134         {
00135             double x = i;
00136 
00137             mesher_input.pointlist[DIM*new_index] = x;
00138             mesher_input.pointlist[DIM*new_index + 1] = y;
00139             new_index++;
00140         }
00141     }
00142 
00143     // Make structure for output
00144     struct triangulateio mesher_output;
00145 
00146     this->InitialiseTriangulateIo(mesher_output);
00147 
00148     // Library call
00149     triangulate((char*)"Qzeo2", &mesher_input, &mesher_output, NULL);
00150 
00151     assert(mesher_output.numberofcorners == (DIM+1)*(DIM+2)/2);//Nodes per element (including internals, one per edge)
00152 
00153     this->ImportFromMesher(mesher_output, mesher_output.numberoftriangles, mesher_output.trianglelist, mesher_output.numberofedges, mesher_output.edgelist, mesher_output.edgemarkerlist);
00154 
00155     CountAndCheckVertices();
00156     AddNodesToBoundaryElements(NULL);
00157 
00158     this->FreeTriangulateIo(mesher_input);
00159     this->FreeTriangulateIo(mesher_output);
00160 }
00161 
00162 
00163 
00164 template<unsigned DIM>
00165 void QuadraticMesh<DIM>::ConstructCuboid(unsigned numElemX, unsigned numElemY, unsigned numElemZ)
00166 {
00167     assert(DIM==3);
00168 
00169     assert(numElemX > 0);
00170     assert(numElemY > 0);
00171     assert(numElemZ > 0);
00172     this->mMeshIsLinear = false;
00173     unsigned num_nodes = (numElemX+1)*(numElemY+1)*(numElemZ+1);
00174 
00175     struct tetgen::tetgenio mesher_input;
00176     mesher_input.pointlist = new double[num_nodes * DIM];
00177     mesher_input.numberofpoints = num_nodes;
00178     unsigned new_index = 0;
00179     for (unsigned k=0; k<=numElemZ; k++)
00180     {
00181         double z = k;
00182         for (unsigned j=0; j<=numElemY; j++)
00183         {
00184             double y = j;
00185             for (unsigned i=0; i<=numElemX; i++)
00186             {
00187                 double x = i;
00188                 mesher_input.pointlist[DIM*new_index] = x;
00189                 mesher_input.pointlist[DIM*new_index + 1] = y;
00190                 mesher_input.pointlist[DIM*new_index + 2] = z;
00191                 new_index++;
00192             }
00193         }
00194     }
00195 
00196     // Library call
00197     struct tetgen::tetgenio mesher_output;
00198     tetgen::tetrahedralize((char*)"Qo2", &mesher_input, &mesher_output, NULL);
00199 
00200     assert(mesher_output.numberofcorners == (DIM+1)*(DIM+2)/2);//Nodes per element (including internals, one per edge)
00201 
00202     this->ImportFromMesher(mesher_output, mesher_output.numberoftetrahedra, mesher_output.tetrahedronlist, mesher_output.numberoftrifaces, mesher_output.trifacelist, NULL);
00203 
00204     CountAndCheckVertices();
00205     AddNodesToBoundaryElements(NULL);
00206 }
00207 
00208 
00209 template<unsigned DIM>
00210 unsigned QuadraticMesh<DIM>::GetNumVertices()
00211 {
00212     return mNumVertices;
00213 }
00214 
00215 
00216 template<unsigned DIM>
00217 void QuadraticMesh<DIM>::ConstructFromLinearMeshReader(AbstractMeshReader<DIM, DIM>& rMeshReader)
00218 {
00219     assert(DIM != 1);
00220 
00221     //Make a linear mesh
00222     TetrahedralMesh<DIM,DIM>::ConstructFromMeshReader(rMeshReader);
00223 
00224     NodeMap unused_map(this->GetNumNodes());
00225 
00226     if (DIM==2)  // In 2D, remesh using triangle via library calls
00227     {
00228         struct triangulateio mesher_input, mesher_output;
00229         this->InitialiseTriangulateIo(mesher_input);
00230         this->InitialiseTriangulateIo(mesher_output);
00231 
00232         mesher_input.numberoftriangles = this->GetNumElements();
00233         mesher_input.trianglelist = (int *) malloc(this->GetNumElements() * (DIM+1) * sizeof(int));
00234         this->ExportToMesher(unused_map, mesher_input, mesher_input.trianglelist);
00235 
00236         // Library call
00237         triangulate((char*)"Qzero2", &mesher_input, &mesher_output, NULL);
00238 
00239         this->ImportFromMesher(mesher_output, mesher_output.numberoftriangles, mesher_output.trianglelist, mesher_output.numberofedges, mesher_output.edgelist, mesher_output.edgemarkerlist);
00240         CountAndCheckVertices();
00241         AddNodesToBoundaryElements(NULL);
00242 
00243         //Tidy up triangle
00244         this->FreeTriangulateIo(mesher_input);
00245         this->FreeTriangulateIo(mesher_output);
00246     }
00247     else // in 3D, remesh using tetgen
00248     {
00249 
00250         struct tetgen::tetgenio mesher_input, mesher_output;
00251 
00252         mesher_input.numberoftetrahedra = this->GetNumElements();
00253         mesher_input.tetrahedronlist = new int[this->GetNumElements() * (DIM+1)];
00254         this->ExportToMesher(unused_map, mesher_input, mesher_input.tetrahedronlist);
00255 
00256         // Library call
00257         tetgen::tetrahedralize((char*)"Qzro2", &mesher_input, &mesher_output);
00258 
00259         this->ImportFromMesher(mesher_output, mesher_output.numberoftetrahedra, mesher_output.tetrahedronlist, mesher_output.numberoftrifaces, mesher_output.trifacelist, NULL);
00260         CountAndCheckVertices();
00261         AddNodesToBoundaryElements(NULL);
00262     }
00263 }
00264 
00265 
00266 template<unsigned DIM>
00267 void QuadraticMesh<DIM>::ConstructFromMeshReader(AbstractMeshReader<DIM, DIM>& rAbsMeshReader)
00268 {
00269     TrianglesMeshReader<DIM, DIM>* p_mesh_reader=dynamic_cast<TrianglesMeshReader<DIM, DIM>*>(&rAbsMeshReader);
00270 
00271     unsigned order_of_elements = 1;
00272     if (p_mesh_reader)
00273     {
00274         //A triangles mesh reader will let you read with non-linear elements
00275         order_of_elements = p_mesh_reader->GetOrderOfElements();
00276     }
00277 
00278     // If it is a linear TrianglesMeshReader or any other reader (which are all linear)
00279     if (order_of_elements == 1)
00280     {
00281         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 in internal nodes");
00282         ConstructFromLinearMeshReader(rAbsMeshReader);
00283         return;
00284     }
00285 
00286     TetrahedralMesh<DIM,DIM>::ConstructFromMeshReader(*p_mesh_reader);
00287     assert(this->GetNumBoundaryElements() > 0);
00288 
00289     p_mesh_reader->Reset();
00290 
00291     // Add the extra nodes (1 extra node in 1D, 3 in 2D, 6 in 3D) to the element data
00292     for (unsigned i=0; i<this->GetNumElements(); i++)
00293     {
00294         std::vector<unsigned> nodes = p_mesh_reader->GetNextElementData().NodeIndices;
00295         assert(nodes.size()==(DIM+1)*(DIM+2)/2);
00296         assert(this->GetElement(i)->GetNumNodes()==DIM+1); // element is initially linear
00297 
00298         // Add extra nodes to make it a quad element
00299         for (unsigned j=DIM+1; j<(DIM+1)*(DIM+2)/2; j++)
00300         {
00301             this->GetElement(i)->AddNode( this->GetNode(nodes[j]) );
00302             this->GetNode(nodes[j])->AddElement(this->GetElement(i)->GetIndex());
00303             this->GetNode(nodes[j])->MarkAsInternal();
00304         }
00305     }
00306 
00307     CountAndCheckVertices();
00308 
00309     if (DIM > 1)
00310     {
00311         // if  OrderOfBoundaryElements is 2 it can read in the extra nodes for each boundary element, other have to compute them.
00312         if (p_mesh_reader->GetOrderOfBoundaryElements() == 2u)
00313         {
00314             p_mesh_reader->Reset();
00315             for (typename TetrahedralMesh<DIM,DIM>::BoundaryElementIterator iter
00316                   = this->GetBoundaryElementIteratorBegin();
00317                  iter != this->GetBoundaryElementIteratorEnd();
00318                  ++iter)
00319             {
00320                 std::vector<unsigned> nodes = p_mesh_reader->GetNextFaceData().NodeIndices;
00321 
00322                 assert((*iter)->GetNumNodes()==DIM); // so far just the vertices
00323                 assert(nodes.size()==DIM*(DIM+1)/2); // the reader should have got 6 nodes (3d) for each face
00324 
00325                 for (unsigned j=DIM; j<DIM*(DIM+1)/2; j++)
00326                 {
00327                     Node <DIM> *p_internal_node = this->GetNode(nodes[j]);
00328                     (*iter)->AddNode( p_internal_node );
00329                     // add node to the boundary node list
00330                     if (!p_internal_node->IsBoundaryNode())
00331                     {
00332                         p_internal_node->SetAsBoundaryNode();
00333                         this->mBoundaryNodes.push_back(p_internal_node);
00334                     }
00335                 }
00336             }
00337         }
00338         else
00339         {
00340             AddNodesToBoundaryElements(p_mesh_reader);
00341         }
00342     }
00343 
00344     // Check each boundary element has a quadratic number of nodes
00345 #ifndef NDEBUG
00346     unsigned expected_num_nodes = DIM*(DIM+1)/2;
00347     for (typename TetrahedralMesh<DIM,DIM>::BoundaryElementIterator iter
00348           = this->GetBoundaryElementIteratorBegin();
00349           iter != this->GetBoundaryElementIteratorEnd();
00350           ++iter)
00351     {
00352         assert((*iter)->GetNumNodes()==expected_num_nodes);
00353     }
00354 #endif
00355 }
00356 
00357 template<unsigned DIM>
00358 void QuadraticMesh<DIM>::AddNodesToBoundaryElements(TrianglesMeshReader<DIM,DIM>* pMeshReader)
00359  {
00360     // Loop over all boundary elements, find the equivalent face from all
00361     // the elements, and add the extra nodes to the boundary element
00362     bool boundary_element_file_has_containing_element_info=false;
00363 
00364     if (pMeshReader)
00365     {
00366         boundary_element_file_has_containing_element_info=pMeshReader->GetReadContainingElementOfBoundaryElement();
00367     }
00368 
00369     if (DIM > 1)
00370     {
00371         if (boundary_element_file_has_containing_element_info)
00372         {
00373             pMeshReader->Reset();
00374         }
00375 
00376         for (typename TetrahedralMesh<DIM,DIM>::BoundaryElementIterator iter
00377                = this->GetBoundaryElementIteratorBegin();
00378              iter != this->GetBoundaryElementIteratorEnd();
00379              ++iter)
00380         {
00381 
00382             // collect the nodes of this boundary element in a set
00383             std::set<unsigned> boundary_element_node_indices;
00384             for (unsigned i=0; i<DIM; i++)
00385             {
00386                 boundary_element_node_indices.insert( (*iter)->GetNodeGlobalIndex(i) );
00387             }
00388 
00389             bool found_this_boundary_element = false;
00390 
00391             // Loop over elements surrounding this face, then loop over each face of that element, and see if it matches
00392             // this boundary element.
00393             // Note, if we know what elem it should be in (boundary_element_file_has_containing_element_info==true)
00394             // we will reset elem_index immediately (below)
00395             Node<DIM>* p_representative_node = (*iter)->GetNode(0);
00396             for (typename Node<DIM>::ContainingElementIterator element_iter = p_representative_node->ContainingElementsBegin();
00397                  element_iter != p_representative_node->ContainingElementsEnd();
00398                  ++element_iter)
00399             {
00400                 unsigned elem_index = *element_iter;
00401 
00402                 // We know what elem it should be in
00403                 if (boundary_element_file_has_containing_element_info)
00404                 {
00405                     elem_index = pMeshReader->GetNextFaceData().ContainingElement;
00406                 }
00407 
00408                 Element<DIM,DIM>* p_element = this->GetElement(elem_index);
00409 
00410                 // For each element, loop over faces (the opposites to a node)
00411                 for (unsigned face=0; face<DIM+1; face++)
00412                 {
00413                     // Collect the node indices for this face
00414                     std::set<unsigned> node_indices;
00415                     for (unsigned local_node_index=0; local_node_index<DIM+1; local_node_index++)
00416                     {
00417                         if (local_node_index!=face)
00418                         {
00419                             node_indices.insert( p_element->GetNodeGlobalIndex(local_node_index) );
00420                         }
00421                     }
00422 
00423                     assert(node_indices.size()==DIM);
00424 
00425                     // see if this face matches the boundary element,
00426                     // and call AddExtraBoundaryNodes() if so
00427                     if (node_indices==boundary_element_node_indices)
00428                     {
00429                         AddExtraBoundaryNodes(*iter, p_element, face);
00430 
00431                         found_this_boundary_element = true;
00432                         break;
00433                     }
00434                 }
00435 
00436                 // If the containing element info was given, we must have found the face first time
00437                 if (boundary_element_file_has_containing_element_info && !found_this_boundary_element)
00438                 {
00439                     #define COVERAGE_IGNORE
00440                     //std::cout << (*iter)->GetIndex() << " " <<  pMeshReader->GetNextFaceData().ContainingElement << "\n";
00441                     EXCEPTION("Boundary element " << (*iter)->GetIndex()
00442                        << "wasn't found in the containing element given for it "
00443                        << elem_index);
00444                     #undef COVERAGE_IGNORE
00445                 }
00446 
00447                 if (found_this_boundary_element)
00448                 {
00449                     break;
00450                 }
00451             }
00452 
00453             if (!found_this_boundary_element)
00454             {
00455                 #define COVERAGE_IGNORE
00456                 EXCEPTION("Unable to find a face of an element which matches one of the boundary elements");
00457                 #undef COVERAGE_IGNORE
00458             }
00459         }
00460     }
00461 }
00462 
00463 
00464 template<unsigned DIM>
00465 void QuadraticMesh<DIM>::AddNodeToBoundaryElement(BoundaryElement<DIM-1,DIM>* pBoundaryElement,
00466                                                   Element<DIM,DIM>* pElement,
00467                                                   unsigned internalNode)
00468 {
00469     assert(DIM > 1);
00470     assert(internalNode >= DIM+1);
00471     assert(internalNode < (DIM+1)*(DIM+2)/2);
00472     Node<DIM>* p_internal_node = pElement->GetNode(internalNode);
00473 
00474     // Add node to the boundary node list
00475     if (!p_internal_node->IsBoundaryNode())
00476     {
00477         p_internal_node->SetAsBoundaryNode();
00478         this->mBoundaryNodes.push_back(p_internal_node);
00479     }
00480 
00481     pBoundaryElement->AddNode( p_internal_node );
00482 }
00483 
00484 
00485 template<unsigned DIM>
00486 void QuadraticMesh<DIM>::AddExtraBoundaryNodes(BoundaryElement<DIM-1,DIM>* pBoundaryElement,
00487                                                Element<DIM,DIM>* pElement,
00488                                                unsigned nodeIndexOppositeToFace)
00489 {
00490     assert(DIM!=1);
00491     if (DIM==2)
00492     {
00493         assert(nodeIndexOppositeToFace<3);
00494         // the single internal node of the elements face will be numbered 'face+3'
00495         AddNodeToBoundaryElement(pBoundaryElement, pElement, nodeIndexOppositeToFace+3);
00496     }
00497     else
00498     {
00499         assert(DIM==3);
00500 
00501         unsigned b_elem_n0 = pBoundaryElement->GetNodeGlobalIndex(0);
00502         unsigned b_elem_n1 = pBoundaryElement->GetNodeGlobalIndex(1);
00503 
00504         unsigned offset;
00505         bool reverse;
00506 
00507         if (nodeIndexOppositeToFace==0)
00508         {
00509             // face opposite to node 0 = {1,2,3}, with corresponding internals {9,8,5}
00510             HelperMethod1(b_elem_n0, b_elem_n1, pElement, 1, 2, 3, offset, reverse);
00511             HelperMethod2(pBoundaryElement, pElement, 9, 8, 5, offset, reverse);
00512         }
00513         else if (nodeIndexOppositeToFace==1)
00514         {
00515             // face opposite to node 1 = {2,0,3}, with corresponding internals {7,9,6}
00516             HelperMethod1(b_elem_n0, b_elem_n1, pElement, 2, 0, 3, offset, reverse);
00517             HelperMethod2(pBoundaryElement, pElement, 7, 9, 6, offset, reverse);
00518         }
00519         else if (nodeIndexOppositeToFace==2)
00520         {
00521             // face opposite to node 2 = {0,1,3}, with corresponding internals {8,7,4}
00522             HelperMethod1(b_elem_n0, b_elem_n1, pElement, 0, 1, 3, offset, reverse);
00523             HelperMethod2(pBoundaryElement, pElement, 8, 7, 4, offset, reverse);
00524         }
00525         else
00526         {
00527             assert(nodeIndexOppositeToFace==3);
00528             // face opposite to node 3 = {0,1,2}, with corresponding internals {5,6,4}
00529             HelperMethod1(b_elem_n0, b_elem_n1, pElement, 0, 1, 2, offset, reverse);
00530             HelperMethod2(pBoundaryElement, pElement, 5, 6, 4, offset, reverse);
00531         }
00532     }
00533 }
00534 
00535 template<unsigned DIM>
00536 void QuadraticMesh<DIM>::WriteBoundaryElementFile(std::string directory, std::string fileName)
00537 {
00538     OutputFileHandler handler(directory, false);
00539     out_stream p_file = handler.OpenOutputFile(fileName);
00540 
00541     unsigned expected_num_nodes;
00542     assert(DIM > 1);
00543     if (DIM == 2)
00544     {
00545         expected_num_nodes = 3;
00546     }
00547     else if (DIM == 3)
00548     {
00549         expected_num_nodes = 6;
00550     }
00551 
00552     unsigned num_elements = 0;
00553 
00554     for (typename TetrahedralMesh<DIM,DIM>::BoundaryElementIterator iter
00555           = this->GetBoundaryElementIteratorBegin();
00556           iter != this->GetBoundaryElementIteratorEnd();
00557           ++iter)
00558     {
00559         assert((*iter)->GetNumNodes()==expected_num_nodes);
00560         num_elements++;
00561     }
00562 
00563     *p_file << num_elements << " 0\n";
00564 
00565     unsigned counter = 0;
00566     for (typename TetrahedralMesh<DIM,DIM>::BoundaryElementIterator iter
00567           = this->GetBoundaryElementIteratorBegin();
00568           iter != this->GetBoundaryElementIteratorEnd();
00569           ++iter)
00570     {
00571         *p_file << counter++ << " ";
00572         for (unsigned i=0; i<(*iter)->GetNumNodes(); i++)
00573         {
00574             *p_file << (*iter)->GetNodeGlobalIndex(i) << " ";
00575         }
00576         *p_file << "\n";
00577     }
00578 
00579     p_file->close();
00580 }
00581 
00583 // two unpleasant helper methods for AddExtraBoundaryNodes()
00585 
00586 #define COVERAGE_IGNORE /// \todo These helper methods aren't properly covered
00587 template<unsigned DIM>
00588 void QuadraticMesh<DIM>::HelperMethod1(unsigned boundaryElemNode0, unsigned boundaryElemNode1,
00589                                        Element<DIM,DIM>* pElement,
00590                                        unsigned node0, unsigned node1, unsigned node2,
00591                                        unsigned& rOffset,
00592                                        bool& rReverse)
00593 {
00594     if (pElement->GetNodeGlobalIndex(node0)==boundaryElemNode0)
00595     {
00596         rOffset = 0;
00597         if (pElement->GetNodeGlobalIndex(node1)==boundaryElemNode1)
00598         {
00599             rReverse = false;
00600         }
00601         else
00602         {
00603             assert(pElement->GetNodeGlobalIndex(node2)==boundaryElemNode1);
00604             rReverse = true;
00605         }
00606     }
00607     else if (pElement->GetNodeGlobalIndex(node1)==boundaryElemNode0)
00608     {
00609         rOffset = 1;
00610         if (pElement->GetNodeGlobalIndex(node2)==boundaryElemNode1)
00611         {
00612             rReverse = false;
00613         }
00614         else
00615         {
00616             assert(pElement->GetNodeGlobalIndex(node0)==boundaryElemNode1);
00617             rReverse = true;
00618         }
00619     }
00620     else
00621     {
00622         assert(pElement->GetNodeGlobalIndex(node2)==boundaryElemNode0);
00623         rOffset = 2;
00624         if (pElement->GetNodeGlobalIndex(node0)==boundaryElemNode1)
00625         {
00626             rReverse = false;
00627         }
00628         else
00629         {
00630             assert(pElement->GetNodeGlobalIndex(node1)==boundaryElemNode1);
00631             rReverse = true;
00632         }
00633     }
00634 }
00635 #undef COVERAGE_IGNORE /// \todo These helper methods aren't properly covered
00636 
00637 
00638 #define COVERAGE_IGNORE /// \todo These helper methods aren't properly covered
00639 template<unsigned DIM>
00640 void QuadraticMesh<DIM>::HelperMethod2(BoundaryElement<DIM-1,DIM>* pBoundaryElement,
00641                                        Element<DIM,DIM>* pElement,
00642                                        unsigned internalNode0, unsigned internalNode1, unsigned internalNode2,
00643                                        unsigned offset,
00644                                        bool reverse)
00645 {
00646     if (offset==1)
00647     {
00648         unsigned temp = internalNode0;
00649         internalNode0 = internalNode1;
00650         internalNode1 = internalNode2;
00651         internalNode2 = temp;
00652     }
00653     else if (offset == 2)
00654     {
00655         unsigned temp = internalNode0;
00656         internalNode0 = internalNode2;
00657         internalNode2 = internalNode1;
00658         internalNode1 = temp;
00659     }
00660 
00661     if (reverse)
00662     {
00663         unsigned temp = internalNode1;
00664         internalNode1 = internalNode2;
00665         internalNode2 = temp;
00666     }
00667 
00668     AddNodeToBoundaryElement(pBoundaryElement, pElement, internalNode0);
00669     AddNodeToBoundaryElement(pBoundaryElement, pElement, internalNode1);
00670     AddNodeToBoundaryElement(pBoundaryElement, pElement, internalNode2);
00671 }
00672 #undef COVERAGE_IGNORE /// \todo These helper methods aren't properly covered
00673 
00674 
00676 // Explicit instantiation
00678 
00679 
00680 template class QuadraticMesh<1>;
00681 template class QuadraticMesh<2>;
00682 template class QuadraticMesh<3>;
00683 
00684 
00685 // Serialization for Boost >= 1.36
00686 #include "SerializationExportWrapperForCpp.hpp"
00687 EXPORT_TEMPLATE_CLASS_SAME_DIMS(QuadraticMesh)
Generated on Thu Dec 22 13:00:16 2011 for Chaste by  doxygen 1.6.3