QuadraticMesh.cpp

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

Generated by  doxygen 1.6.2