QuadraticMesh.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2009
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 
00033 //Jonathan Shewchuk's triangle
00034 #define REAL double
00035 #define VOID void
00036 #include "triangle.h"
00037 #undef REAL
00038 #undef VOID
00039 
00040 template<unsigned DIM>
00041 QuadraticMesh<DIM>::QuadraticMesh(const std::string& rFileName, bool boundaryElemFileIsQuadratic)
00042 {
00043     LoadFromFile(rFileName, boundaryElemFileIsQuadratic);
00044 
00045     // Check each boundary element has a quadratic number of nodes    
00046 #ifndef NDEBUG
00047     unsigned expected_num_nodes = DIM*(DIM+1)/2;
00048     for (typename TetrahedralMesh<DIM,DIM>::BoundaryElementIterator iter
00049           = this->GetBoundaryElementIteratorBegin();
00050           iter != this->GetBoundaryElementIteratorEnd();
00051           ++iter)
00052     {
00053         assert((*iter)->GetNumNodes()==expected_num_nodes);
00054     }
00055 #endif
00056 }
00057 
00058 
00059 template<unsigned DIM>
00060 QuadraticMesh<DIM>::QuadraticMesh(double xEnd, double yEnd, unsigned numElemX, unsigned numElemY)
00061 {
00062     assert(DIM==2);
00063 
00064     assert(xEnd>0);
00065     assert(yEnd>0);
00066     assert(numElemX>0);
00067     assert(numElemY>0);
00068  
00069     unsigned num_nodes=(numElemX+1)*(numElemY+1);
00070     struct triangulateio triangle_input;
00071     triangle_input.pointlist = (double *) malloc( num_nodes * 2 * sizeof(double));
00072     triangle_input.numberofpoints = num_nodes;
00073     triangle_input.numberofpointattributes = 0;
00074     triangle_input.pointmarkerlist = NULL;
00075     triangle_input.numberofsegments = 0;
00076     triangle_input.numberofholes = 0;
00077     triangle_input.numberofregions = 0;
00078 
00079     unsigned new_index = 0;
00080     for (unsigned j=0; j<=numElemY; j++)
00081     {
00082         double y = yEnd*j/numElemY;
00083         for (unsigned i=0; i<=numElemX; i++)
00084         {
00085             double x = xEnd*i/numElemX;
00086 
00087             triangle_input.pointlist[2*new_index] = x;
00088             triangle_input.pointlist[2*new_index + 1] = y;
00089             new_index++;
00090         }
00091     }
00092 
00093     // Make structure for output
00094     struct triangulateio triangle_output;
00095     triangle_output.pointlist = NULL;
00096     triangle_output.pointattributelist = (double *) NULL;
00097     triangle_output.pointmarkerlist = (int *) NULL;
00098     triangle_output.trianglelist = (int *) NULL;
00099     triangle_output.triangleattributelist = (double *) NULL;
00100     triangle_output.edgelist = (int *) NULL;
00101     triangle_output.edgemarkerlist = (int *) NULL;
00102 
00103     // Library call
00104     triangulate((char*)"Qzeo2", &triangle_input, &triangle_output, NULL);
00105 
00106     assert(triangle_output.numberofcorners == 6);//Nodes per triangle
00107 
00108     // Construct the nodes
00109     for (unsigned node_index=0; node_index<(unsigned)triangle_output.numberofpoints; node_index++)
00110     {
00111         if (triangle_output.pointmarkerlist[node_index] == 1)
00112         {
00113             // Boundary node
00114             Node<DIM> *p_node = new Node<DIM>(node_index, true,
00115               triangle_output.pointlist[node_index * 2],
00116               triangle_output.pointlist[node_index * 2+1]);
00117             this->mNodes.push_back(p_node);
00118             this->mBoundaryNodes.push_back(p_node);
00119         }
00120         else
00121         {
00122             this->mNodes.push_back(new Node<DIM>(node_index, false,
00123               triangle_output.pointlist[node_index * 2],
00124               triangle_output.pointlist[node_index * 2+1]));
00125         }
00126     }
00127 
00128     mIsInternalNode.resize(this->GetNumNodes(), true);
00129     
00130     // Construct the elements
00131     this->mElements.reserve(triangle_output.numberoftriangles);
00132     for (unsigned element_index=0; element_index<(unsigned)triangle_output.numberoftriangles; element_index++)
00133     {
00134         std::vector<Node<DIM>*> nodes;
00135         //First 3 are the vertices
00136         for (unsigned j=0; j<3; j++)
00137         {
00138             unsigned global_node_index = triangle_output.trianglelist[element_index*6 + j];
00139             assert(global_node_index < this->mNodes.size());
00140             nodes.push_back(this->mNodes[global_node_index]);
00141             mIsInternalNode[global_node_index]=false;
00142         }
00143         //Construct with just the vertices
00144         this->mElements.push_back(new Element<DIM, DIM>(element_index, nodes));
00145         //Add the internals
00146         for (unsigned j=3; j<6; j++)
00147         {
00148             unsigned global_node_index = triangle_output.trianglelist[element_index*6 + j];
00149             assert(global_node_index < this->mNodes.size());
00150             this->mElements[element_index]->AddNode( this->mNodes[global_node_index] );
00151             this->mNodes[j]->AddElement(element_index);
00152         }
00153     }
00154     bool vertices_mode = true;
00155     mNumVertices = 0u;
00156     for (unsigned i=0; i<this->GetNumNodes(); i++)
00157     {
00158         if (mIsInternalNode[i]==false)
00159         {
00160             mNumVertices++;
00161             assert(vertices_mode);//If this trips, then the nodes were not in the expected order -- investigate the library call to triangle
00162         }
00163         if ( (vertices_mode == true)  && (mIsInternalNode[i]==true) )
00164         {
00165             vertices_mode = false;
00166         }
00167     }
00168     unsigned next_boundary_element_index = 0;
00169     for (unsigned boundary_element_index=0; boundary_element_index<(unsigned)triangle_output.numberofedges; boundary_element_index++)
00170     {
00171         if (triangle_output.edgemarkerlist[boundary_element_index] == 1)
00172         {
00173             std::vector<Node<DIM>*> nodes;
00174             for (unsigned j=0; j<2; j++)
00175             {
00176                 unsigned global_node_index=triangle_output.edgelist[boundary_element_index*2 + j];
00177                 assert(global_node_index < this->mNodes.size());
00178                 nodes.push_back(this->mNodes[global_node_index]);
00179             }
00180             this->mBoundaryElements.push_back(new BoundaryElement<DIM-1, DIM>(next_boundary_element_index++, nodes));
00181         }
00182     }
00183     
00184     this->RefreshJacobianCachedData();
00185     
00186     AddNodesToBoundaryElements();
00187     
00188     free(triangle_input.pointlist);
00189 
00190     free(triangle_output.pointlist);
00191     free(triangle_output.pointattributelist);
00192     free(triangle_output.pointmarkerlist);
00193     free(triangle_output.trianglelist);
00194     free(triangle_output.triangleattributelist);
00195     free(triangle_output.edgelist);
00196     free(triangle_output.edgemarkerlist);
00197 }
00198 
00199 
00200 template<unsigned DIM>
00201 QuadraticMesh<DIM>::QuadraticMesh(double xEnd, double yEnd, double zEnd,
00202                                   unsigned numElemX, unsigned numElemY, unsigned numElemZ)
00203 {
00204     assert(DIM==3);
00205 
00206     assert(xEnd>0);
00207     assert(yEnd>0);
00208     assert(zEnd>0);
00209     assert(numElemX>0);
00210     assert(numElemY>0);
00211     assert(numElemZ>0);
00212 
00213     std::string tempfile_name_stem = "temp_quadmesh3d";
00214 
00216     // write the node file (vertices only)
00218     OutputFileHandler handler("");
00219     out_stream p_file = handler.OpenOutputFile(tempfile_name_stem+".node");
00220 
00221     *p_file << (numElemX+1)*(numElemY+1)*(numElemZ+1) << " 3 0 0\n";
00222     unsigned node_index = 0;
00223     for (unsigned k=0; k<=numElemZ; k++)
00224     {
00225         for (unsigned j=0; j<=numElemY; j++)
00226         {
00227             for (unsigned i=0; i<=numElemX; i++)
00228             {
00229                 double x = xEnd*i/numElemX;
00230                 double y = yEnd*j/numElemY;
00231                 double z = zEnd*k/numElemZ; //Not yEnd!
00232 
00233                 //bool on_boundary = ( (i==0) || (i==numElemX) || (j==0) || (j==numElemY) || (k==0) || (k==numElemZ) );
00234                 *p_file << node_index++ << " " << x << " " << y << " " << z << "\n"; // << (on_boundary?1:0) << "\n";
00235             }
00236         }
00237     }
00238     p_file->close();
00239 
00241     // create the quadratic mesh files using triangle and load
00243 
00244 
00245     RunMesherAndReadMesh("tetgen", handler.GetOutputDirectoryFullPath(), tempfile_name_stem);
00246 }
00247 
00248 
00249 template<unsigned DIM>
00250 unsigned QuadraticMesh<DIM>::GetNumVertices()
00251 {
00252     return mNumVertices;
00253 }
00254 
00255 
00256 template<unsigned DIM>
00257 void QuadraticMesh<DIM>::RunMesherAndReadMesh(std::string binary,
00258                                               std::string outputDir,
00259                                               std::string fileStem)
00260 {
00261     
00262     assert(DIM == 3);
00263     std::string args = "-Qo2";
00264     
00265 
00266     std::string command =  binary + " " + args + " " + outputDir
00267                            + "/" + fileStem + ".node" + " > /dev/null";
00268 
00269     int return_value = system(command.c_str());
00270 
00271     if (return_value != 0)
00272     {
00273         #define COVERAGE_IGNORE
00274         EXCEPTION("Remeshing (by calling " + binary + ") failed.  Do you have it in your path?\n"+
00275         "The quadratic mesh relies on functionality from tetgen (http://tetgen.berlios.de/).");
00276         #undef COVERAGE_IGNORE
00277     }
00278 
00279     // move the output files to the chaste directory
00280     command =   "mv " + outputDir + "/"
00281               + fileStem + ".1.* .";
00282 
00283     // NOTE: we don't check whether the return value here is zero, because if CHASTE_TESTOUTPUT
00284     // is "." (ie if it hasn't been exported), then the mv will fail (source and destination files
00285     // are the same), but this isn't a problem.
00286     return_value = system(command.c_str());
00287 
00288     // load
00289     LoadFromFile( fileStem + ".1", false); // false as tetgen/triangle has been used and therefore boundary elems will be linear
00290 
00291     // delete the temporary files
00292     command = "rm -f " + outputDir + "/" + fileStem + ".node";
00293     EXPECT0(system, command);
00294     EXPECT0(system, "rm -f " + fileStem + ".1.node");
00295     EXPECT0(system, "rm -f " + fileStem + ".1.ele");
00296     EXPECT0(system, "rm -f " + fileStem + ".1.face");
00297 }
00298 
00299 
00300 template<unsigned DIM>
00301 void QuadraticMesh<DIM>::LoadFromFile(const std::string& rFileName, bool boundaryElemFileIsQuadratic)
00302 {
00303     unsigned order_of_boundary_elements = boundaryElemFileIsQuadratic ? 2 : 1;
00304     
00305     TrianglesMeshReader<DIM,DIM> mesh_reader(rFileName, 2, order_of_boundary_elements); // 2=quadratic mesh
00306 
00307     ConstructFromMeshReader(mesh_reader);
00308 
00309     // set up the information on whether a node is an internal node or not (if not,
00310     // it'll be a vertex)
00311     mIsInternalNode.resize(this->GetNumNodes(), true);
00312     for (unsigned elem_index=0; elem_index<this->GetNumElements(); elem_index++)
00313     {
00314         for (unsigned i=0; i<DIM+1 /*num vertices*/; i++)
00315         {
00316             unsigned node_index = this->GetElement(elem_index)->GetNodeGlobalIndex(i);
00317             mIsInternalNode[ node_index ] = false;
00318         }
00319     }
00320 
00321     // count the number of vertices, and also check all vertices come before the
00322     // rest of the nodes (as this is assumed in other parts of the code)
00323     mNumVertices = 0;
00324     bool vertices_mode = true;
00325     for (unsigned i=0; i<this->GetNumNodes(); i++)
00326     {
00327         if (mIsInternalNode[i]==false)
00328         {
00329             mNumVertices++;
00330         }
00331         if ((vertices_mode == false)  && (mIsInternalNode[i]==false ) )
00332         {
00333             //Covered in the 1D case by special mesh file data
00334             EXCEPTION("The quadratic mesh doesn't appear to have all vertices before the rest of the nodes");
00335         }
00336         if ( (vertices_mode == true)  && (mIsInternalNode[i]==true) )
00337         {
00338             vertices_mode = false;
00339         }
00340     }
00341 
00342     mesh_reader.Reset();
00343 
00344     // add the extra nodes (1 extra node in 1D, 3 in 2D, 6 in 3D) to the element
00345     // data.
00346     for (unsigned i=0; i<this->GetNumElements(); i++)
00347     {
00348         std::vector<unsigned> nodes = mesh_reader.GetNextElementData().NodeIndices;
00349         assert(nodes.size()==(DIM+1)*(DIM+2)/2);
00350         assert(this->GetElement(i)->GetNumNodes()==DIM+1); // element is initially linear
00351         // add extra nodes to make it a quad element
00352         for (unsigned j=DIM+1; j<(DIM+1)*(DIM+2)/2; j++)
00353         {
00354             this->GetElement(i)->AddNode( this->GetNode(nodes[j]) );
00355             this->GetNode(nodes[j])->AddElement(this->GetElement(i)->GetIndex());
00356         }
00357     }
00358 
00359     if (DIM > 1)
00360     {
00361         // if boundaryElemFileIsQuadratic can read in the extra nodes for each boundary element, other have to compute them.
00362         if (boundaryElemFileIsQuadratic)
00363         {
00364             mesh_reader.Reset();
00365             for (typename TetrahedralMesh<DIM,DIM>::BoundaryElementIterator iter
00366                   = this->GetBoundaryElementIteratorBegin();
00367                  iter != this->GetBoundaryElementIteratorEnd();
00368                  ++iter)
00369             {
00370                 std::vector<unsigned> nodes = mesh_reader.GetNextFaceData().NodeIndices;
00371     
00372                 assert((*iter)->GetNumNodes()==DIM); // so far just the vertices 
00373                 assert(nodes.size()==DIM*(DIM+1)/2); // the reader should have got 6 nodes (3d) for each face
00374                 
00375                 for (unsigned j=DIM; j<DIM*(DIM+1)/2; j++)
00376                 {
00377                     (*iter)->AddNode( this->GetNode(nodes[j]) );
00378                 } 
00379             }
00380         }
00381         else
00382         {
00383             AddNodesToBoundaryElements();
00384         }
00385     }
00386 }
00387  
00388 template<unsigned DIM>
00389 void QuadraticMesh<DIM>::AddNodesToBoundaryElements()
00390  {
00391     // Loop over all boundary elements, find the equivalent face from all
00392     // the elements, and add the extra nodes to the boundary element
00393     if (DIM>1)
00394     {
00395 //        unsigned total = 0;
00396 //        for (typename TetrahedralMesh<DIM,DIM>::BoundaryElementIterator iter
00397 //              = this->GetBoundaryElementIteratorBegin();
00398 //            iter != this->GetBoundaryElementIteratorEnd();
00399 //            ++iter)
00400 //        {
00401 //            total++;
00402 //        }
00403 //        
00404 //        unsigned counter = 0;
00405 
00406         for (typename TetrahedralMesh<DIM,DIM>::BoundaryElementIterator iter
00407               = this->GetBoundaryElementIteratorBegin();
00408             iter != this->GetBoundaryElementIteratorEnd();
00409             ++iter)
00410         {
00411 //            std::cout << "\rAddNodesToBoundaryElements: " << counter++ << " of " << total << std::flush;
00412             
00413             // collect the nodes of this boundary element in a set
00414             std::set<unsigned> boundary_element_node_indices;
00415             for (unsigned i=0; i<DIM; i++)
00416             {
00417                 boundary_element_node_indices.insert( (*iter)->GetNodeGlobalIndex(i) );
00418             }
00419 
00420             bool found_this_boundary_element = false;
00421 
00422             // loop over elements
00423             for (unsigned i=0; i<this->GetNumElements(); i++)
00424             {
00425                 Element<DIM,DIM> *p_element = this->GetElement(i);
00426 
00427                 // for each element, loop over faces (the opposites to a node)
00428                 for (unsigned face=0; face<DIM+1; face++)
00429                 {
00430                     // collect the node indices for this face
00431                     std::set<unsigned> node_indices;
00432                     for (unsigned local_node_index=0; local_node_index<DIM+1; local_node_index++)
00433                     {
00434                         if (local_node_index!=face)
00435                         {
00436                             node_indices.insert( p_element->GetNodeGlobalIndex(local_node_index) );
00437                         }
00438                     }
00439 
00440                     assert(node_indices.size()==DIM);
00441 
00442                     // see if this face matches the boundary element,
00443                     // and call AddExtraBoundaryNodes() if so
00444                     if (node_indices==boundary_element_node_indices)
00445                     {
00446                         AddExtraBoundaryNodes(*iter, p_element, face);
00447 
00448                         found_this_boundary_element = true;
00449                         break;
00450                     }
00451                 }
00452 
00453                 if (found_this_boundary_element)
00454                 {
00455                     break;
00456                 }
00457             }
00458 
00459             if (!found_this_boundary_element)
00460             {
00461                 #define COVERAGE_IGNORE
00462                 EXCEPTION("Unable to find a face of an element which matches one of the boundary elements");
00463                 #undef COVERAGE_IGNORE
00464             }
00465         }
00466     }
00467 }
00468 
00469 
00470 template<unsigned DIM>
00471 void QuadraticMesh<DIM>::AddNodeToBoundaryElement(BoundaryElement<DIM-1,DIM>* pBoundaryElement,
00472                                                   Element<DIM,DIM>* pElement,
00473                                                   unsigned internalNode)
00474 {
00475     assert(DIM>1);
00476     assert(internalNode >= DIM+1);
00477     assert(internalNode < (DIM+1)*(DIM+2)/2);
00478     Node<DIM> *p_internal_node = pElement->GetNode(internalNode);
00479 
00480     // add node to the boundary node list
00481     if (!p_internal_node->IsBoundaryNode())
00482     {
00483         p_internal_node->SetAsBoundaryNode();
00484         this->mBoundaryNodes.push_back(p_internal_node);
00485     }
00486 
00487     pBoundaryElement->AddNode( p_internal_node );
00488 }
00489 
00490 
00491 template<unsigned DIM>
00492 void QuadraticMesh<DIM>::AddExtraBoundaryNodes(BoundaryElement<DIM-1,DIM>* pBoundaryElement,
00493                                                Element<DIM,DIM>* pElement,
00494                                                unsigned nodeIndexOppositeToFace)
00495 {
00496     assert(DIM!=1);
00497     if (DIM==2)
00498     {
00499         assert(nodeIndexOppositeToFace<3);
00500         // the single internal node of the elements face will be numbered 'face+3'
00501         AddNodeToBoundaryElement(pBoundaryElement, pElement, nodeIndexOppositeToFace+3);
00502     }
00503     else
00504     {
00505         assert(DIM==3);
00506 
00507         unsigned b_elem_n0 = pBoundaryElement->GetNodeGlobalIndex(0);
00508         unsigned b_elem_n1 = pBoundaryElement->GetNodeGlobalIndex(1);
00509 
00510         unsigned offset;
00511         bool reverse;
00512 
00513         if (nodeIndexOppositeToFace==0)
00514         {
00515             // face opposite to node 0 = {1,2,3}, with corresponding internals {9,8,5}
00516             HelperMethod1(b_elem_n0, b_elem_n1, pElement, 1, 2, 3, offset, reverse);
00517             HelperMethod2(pBoundaryElement, pElement, 9, 8, 5, offset, reverse);
00518         }
00519         else if (nodeIndexOppositeToFace==1)
00520         {
00521             // face opposite to node 1 = {2,0,3}, with corresponding internals {7,9,6}
00522             HelperMethod1(b_elem_n0, b_elem_n1, pElement, 2, 0, 3, offset, reverse);
00523             HelperMethod2(pBoundaryElement, pElement, 7, 9, 6, offset, reverse);
00524         }
00525         else if (nodeIndexOppositeToFace==2)
00526         {
00527             // face opposite to node 2 = {0,1,3}, with corresponding internals {8,7,4}
00528             HelperMethod1(b_elem_n0, b_elem_n1, pElement, 0, 1, 3, offset, reverse);
00529             HelperMethod2(pBoundaryElement, pElement, 8, 7, 4, offset, reverse);
00530         }
00531         else
00532         {
00533             assert(nodeIndexOppositeToFace==3);
00534             // face opposite to node 3 = {0,1,2}, with corresponding internals {5,6,4}
00535             HelperMethod1(b_elem_n0, b_elem_n1, pElement, 0, 1, 2, offset, reverse);
00536             HelperMethod2(pBoundaryElement, pElement, 5, 6, 4, offset, reverse);
00537         }
00538     }
00539 }
00540 
00541 template<unsigned DIM>
00542 void QuadraticMesh<DIM>::WriteBoundaryElementFile(std::string directory, std::string fileName)
00543 {
00544     OutputFileHandler handler(directory, false);
00545     out_stream p_file = handler.OpenOutputFile(fileName);
00546 
00547     unsigned expected_num_nodes;
00548     assert(DIM > 1);
00549     if (DIM == 2)
00550     {
00551         expected_num_nodes = 3;
00552     }
00553     else if (DIM == 3)
00554     {
00555         expected_num_nodes = 6;
00556     }
00557 
00558     unsigned num_elements = 0; 
00559 
00560     for (typename TetrahedralMesh<DIM,DIM>::BoundaryElementIterator iter
00561           = this->GetBoundaryElementIteratorBegin();
00562           iter != this->GetBoundaryElementIteratorEnd();
00563           ++iter)
00564     {
00565         assert((*iter)->GetNumNodes()==expected_num_nodes);
00566         num_elements++;
00567     }
00568 
00569     *p_file << num_elements << " 0\n";
00570 
00571     unsigned counter = 0;
00572     for (typename TetrahedralMesh<DIM,DIM>::BoundaryElementIterator iter
00573           = this->GetBoundaryElementIteratorBegin();
00574           iter != this->GetBoundaryElementIteratorEnd();
00575           ++iter)
00576     {
00577         *p_file << counter++ << " ";
00578         for (unsigned i=0; i<(*iter)->GetNumNodes(); i++)
00579         {
00580             *p_file << (*iter)->GetNodeGlobalIndex(i) << " ";
00581         }
00582         *p_file << "\n";
00583     }
00584 
00585     p_file->close();
00586 }
00587 
00589 // two unpleasant helper methods for AddExtraBoundaryNodes()
00591 
00592 #define COVERAGE_IGNORE 
00593 template<unsigned DIM>
00594 void QuadraticMesh<DIM>::HelperMethod1(unsigned boundaryElemNode0, unsigned boundaryElemNode1,
00595                                        Element<DIM,DIM>* pElement,
00596                                        unsigned node0, unsigned node1, unsigned node2,
00597                                        unsigned& rOffset,
00598                                        bool& rReverse)
00599 {
00600     if (pElement->GetNodeGlobalIndex(node0)==boundaryElemNode0)
00601     {
00602         rOffset = 0;
00603         if (pElement->GetNodeGlobalIndex(node1)==boundaryElemNode1)
00604         {
00605             rReverse = false;
00606         }
00607         else
00608         {
00609             assert(pElement->GetNodeGlobalIndex(node2)==boundaryElemNode1);
00610             rReverse = true;
00611         }
00612     }
00613     else if (pElement->GetNodeGlobalIndex(node1)==boundaryElemNode0)
00614     {
00615         rOffset = 1;
00616         if (pElement->GetNodeGlobalIndex(node2)==boundaryElemNode1)
00617         {
00618             rReverse = false;
00619         }
00620         else
00621         {
00622             assert(pElement->GetNodeGlobalIndex(node0)==boundaryElemNode1);
00623             rReverse = true;
00624         }
00625     }
00626     else
00627     {
00628         assert(pElement->GetNodeGlobalIndex(node2)==boundaryElemNode0);
00629         rOffset = 2;
00630         if (pElement->GetNodeGlobalIndex(node0)==boundaryElemNode1)
00631         {
00632             rReverse = false;
00633         }
00634         else
00635         {
00636             assert(pElement->GetNodeGlobalIndex(node1)==boundaryElemNode1);
00637             rReverse = true;
00638         }
00639     }
00640 }
00641 #undef COVERAGE_IGNORE 
00642 
00643 
00644 #define COVERAGE_IGNORE 
00645 template<unsigned DIM>
00646 void QuadraticMesh<DIM>::HelperMethod2(BoundaryElement<DIM-1,DIM>* pBoundaryElement,
00647                                        Element<DIM,DIM>* pElement,
00648                                        unsigned internalNode0, unsigned internalNode1, unsigned internalNode2,
00649                                        unsigned offset,
00650                                        bool reverse)
00651 {
00652     if (offset==1)
00653     {
00654         unsigned temp = internalNode0;
00655         internalNode0 = internalNode1;
00656         internalNode1 = internalNode2;
00657         internalNode2 = temp;
00658     }
00659     else if (offset == 2)
00660     {
00661         unsigned temp = internalNode0;
00662         internalNode0 = internalNode2;
00663         internalNode2 = internalNode1;
00664         internalNode1 = temp;
00665     }
00666 
00667     if (reverse)
00668     {
00669         unsigned temp = internalNode1;
00670         internalNode1 = internalNode2;
00671         internalNode2 = temp;
00672     }
00673 
00674     AddNodeToBoundaryElement(pBoundaryElement, pElement, internalNode0);
00675     AddNodeToBoundaryElement(pBoundaryElement, pElement, internalNode1);
00676     AddNodeToBoundaryElement(pBoundaryElement, pElement, internalNode2);
00677 }
00678 #undef COVERAGE_IGNORE 
00679 
00680 
00682 // Explicit instantiation
00684 
00685 
00686 template class QuadraticMesh<1>;
00687 template class QuadraticMesh<2>;
00688 template class QuadraticMesh<3>;

Generated on Tue Aug 4 16:10:22 2009 for Chaste by  doxygen 1.5.5