Chaste Release::3.1
TrianglesMeshReader.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 #include <cassert>
00036 #include <sstream>
00037 #include <iostream>
00038 
00039 #include "TrianglesMeshReader.hpp"
00040 #include "Exception.hpp"
00041 
00042 static const char* NODES_FILE_EXTENSION = ".node";
00043 static const char* ELEMENTS_FILE_EXTENSION = ".ele";
00044 static const char* FACES_FILE_EXTENSION = ".face";
00045 static const char* EDGES_FILE_EXTENSION = ".edge";
00046 static const char* NCL_FILE_EXTENSION = ".ncl";
00047 static const char* CABLE_FILE_EXTENSION = ".cable";
00048 
00050 // Implementation
00052 
00053 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00054 TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::TrianglesMeshReader(std::string pathBaseName,
00055                                                                  unsigned orderOfElements,
00056                                                                  unsigned orderOfBoundaryElements,
00057                                                                  bool readContainingElementForBoundaryElements)
00058     : mFilesBaseName(pathBaseName),
00059       mNodeItemWidth(0),
00060       mElementItemWidth(0),
00061       mFaceItemWidth(0),
00062       mNumNodes(0),
00063       mNumElements(0),
00064       mNumFaces(0),
00065       mNumCableElements(0),
00066       mNodesRead(0),
00067       mElementsRead(0),
00068       mCableElementsRead(0),
00069       mFacesRead(0),
00070       mBoundaryFacesRead(0),
00071       mNumNodeAttributes(0),
00072       mNumElementAttributes(0),
00073       mNumFaceAttributes(0),
00074       mNumCableElementAttributes(0),
00075       mOrderOfElements(orderOfElements),
00076       mOrderOfBoundaryElements(orderOfBoundaryElements),
00077       mEofException(false),
00078       mReadContainingElementOfBoundaryElement(readContainingElementForBoundaryElements),
00079       mFilesAreBinary(false),
00080       mMeshIsHexahedral(false),
00081       mNodeFileReadBuffer(NULL),
00082       mElementFileReadBuffer(NULL),
00083       mFaceFileReadBuffer(NULL),
00084       mNodePermutationDefined(false)
00085 {
00086     // Only linear and quadratic elements
00087     assert(orderOfElements==1 || orderOfElements==2);
00088     if ( mOrderOfBoundaryElements == 2 &&  mReadContainingElementOfBoundaryElement)
00089     {
00090         EXCEPTION("Boundary element file should not have containing element info if it is quadratic");
00091     }
00092     if (mOrderOfElements==1)
00093     {
00094         mNodesPerElement = ELEMENT_DIM+1;
00095     }
00096     else
00097     {
00098         #define COVERAGE_IGNORE
00099         assert(SPACE_DIM==ELEMENT_DIM);
00100         #undef COVERAGE_IGNORE
00101         mNodesPerElement = (ELEMENT_DIM+1)*(ELEMENT_DIM+2)/2;
00102     }
00103 
00104     if (mOrderOfBoundaryElements==1)
00105     {
00106         mNodesPerBoundaryElement = ELEMENT_DIM;
00107     }
00108     else
00109     {
00110         #define COVERAGE_IGNORE
00111         assert(SPACE_DIM==ELEMENT_DIM);
00112         #undef COVERAGE_IGNORE
00113         mNodesPerBoundaryElement = ELEMENT_DIM*(ELEMENT_DIM+1)/2;
00114     }
00115 
00116     mIndexFromZero = false; // Initially assume that nodes are not numbered from zero
00117 
00118     OpenFiles();
00119     ReadHeaders();
00120 }
00121 
00122 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00123 TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::~TrianglesMeshReader()
00124 {
00125     delete[] mNodeFileReadBuffer;
00126     delete[] mElementFileReadBuffer;
00127     delete[] mFaceFileReadBuffer;
00128 }
00129 
00130 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00131 unsigned TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::GetNumElements() const
00132 {
00133     return mNumElements;
00134 }
00135 
00136 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00137 unsigned TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::GetNumNodes() const
00138 {
00139     return mNumNodes;
00140 }
00141 
00142 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00143 unsigned TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::GetNumFaces() const
00144 {
00145     return mNumFaces;
00146 }
00147 
00148 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00149 unsigned TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::GetNumCableElements() const
00150 {
00151     return mNumCableElements;
00152 }
00153 
00154 
00155 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00156 unsigned TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::GetNumElementAttributes() const
00157 {
00158     return mNumElementAttributes;
00159 }
00160 
00161 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00162 unsigned TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::GetNumFaceAttributes() const
00163 {
00164     return mNumFaceAttributes;
00165 }
00166 
00167 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00168 unsigned TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::GetNumCableElementAttributes() const
00169 {
00170     return mNumCableElementAttributes;
00171 }
00172 
00173 
00174 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00175 void TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::Reset()
00176 {
00177     CloseFiles();
00178 
00179     mNodesRead = 0;
00180     mElementsRead = 0;
00181     mFacesRead = 0;
00182     mBoundaryFacesRead = 0;
00183     mCableElementsRead = 0;
00184     mEofException = false;
00185 
00186     OpenFiles();
00187     ReadHeaders();
00188 }
00189 
00190 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00191 std::vector<double> TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::GetNextNode()
00192 {
00193     std::vector<double> ret_coords(SPACE_DIM);
00194 
00195     mNodeAttributes.clear(); // clear attributes for this node
00196     GetNextItemFromStream(mNodesFile, mNodesRead, ret_coords, mNumNodeAttributes, mNodeAttributes);
00197 
00198     mNodesRead++;
00199     return ret_coords;
00200 }
00201 
00202 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00203 ElementData TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::GetNextElementData()
00204 {
00205     ElementData element_data;
00206     element_data.NodeIndices.resize(mNodesPerElement);
00207     element_data.AttributeValue = 0.0; // If an attribute is not read this stays as zero, otherwise overwritten.
00208 
00209     std::vector<unsigned> element_attributes;
00210     GetNextItemFromStream(mElementsFile, mElementsRead, element_data.NodeIndices, mNumElementAttributes, element_attributes);
00211     if (mNumElementAttributes > 0)
00212     {
00213         element_data.AttributeValue = (double) element_attributes[0];
00214     }
00215 
00216     EnsureIndexingFromZero(element_data.NodeIndices);
00217 
00218     mElementsRead++;
00219 
00220     if (mNodePermutationDefined)
00221     {
00222         for (std::vector<unsigned>::iterator node_it = element_data.NodeIndices.begin();
00223              node_it != element_data.NodeIndices.end();
00224              ++ node_it)
00225         {
00226             assert(*node_it < mPermutationVector.size());
00227             *node_it =  mPermutationVector[*node_it];
00228         }
00229     }
00230 
00231     return element_data;
00232 }
00233 
00234 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00235 ElementData TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::GetNextCableElementData()
00236 {
00237     ElementData element_data;
00238     element_data.NodeIndices.resize(2u);
00239     element_data.AttributeValue = 0; // If an attribute is not read this stays as zero, otherwise overwritten.
00240 
00241     std::vector<double> cable_element_attributes;
00242     GetNextItemFromStream(mCableElementsFile, mCableElementsRead, element_data.NodeIndices, mNumCableElementAttributes, cable_element_attributes);
00243     if (mNumCableElementAttributes > 0)
00244     {
00245         element_data.AttributeValue = cable_element_attributes[0];
00246     }
00247 
00248     EnsureIndexingFromZero(element_data.NodeIndices);
00249 
00250     mCableElementsRead++;
00251 
00252     // Node permutation can only be done with binary data...
00253 //    if (mNodePermutationDefined)
00254 //    {
00255 //        for (std::vector<unsigned>::iterator node_it = element_data.NodeIndices.begin();
00256 //             node_it != element_data.NodeIndices.end();
00257 //             ++ node_it)
00258 //        {
00259 //            assert(*node_it < mPermutationVector.size());
00260 //            *node_it =  mPermutationVector[*node_it];
00261 //        }
00262 //    }
00263 
00264     return element_data;
00265 }
00266 
00267 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00268 ElementData TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::GetNextFaceData()
00269 {
00270     ElementData face_data;
00271     std::vector<unsigned> ret_indices;
00272 
00273     // In the first case there's no file, all the nodes are set as faces
00274     if (ELEMENT_DIM == 1)
00275     {
00276         ret_indices.push_back( mOneDimBoundary[mBoundaryFacesRead] );
00277     }
00278     else
00279     {
00280         ret_indices.resize(mNodesPerBoundaryElement);
00281 
00282         assert(ELEMENT_DIM != 0); //Covered in earlier exception, but needed in loop guard here.
00283         do
00284         {
00285             face_data.AttributeValue = 1.0; // If an attribute is not read this stays as one, otherwise overwritten.
00286 
00287             std::vector<unsigned> face_attributes; //will store face attributes, if any
00288             if (mReadContainingElementOfBoundaryElement)
00289             {
00290                 assert(mNumFaceAttributes == 0);
00291                 GetNextItemFromStream(mFacesFile, mFacesRead, ret_indices, 1, face_attributes);
00292 
00293                 if (face_attributes.size() > 0)
00294                 {
00295                     face_data.ContainingElement = face_attributes[0];// only one face attribute registered for the moment
00296                 }
00297 
00298             }
00299             else
00300             {
00301                 GetNextItemFromStream(mFacesFile, mFacesRead, ret_indices, mNumFaceAttributes,
00302                                         face_attributes);
00303 
00304                 if (mNumFaceAttributes > 0)
00305                 {
00306                     face_data.AttributeValue = (double) face_attributes[0]; //only one face attribute registered for the moment
00307                 }
00308             }
00309 
00310             EnsureIndexingFromZero(ret_indices);
00311 
00312             mFacesRead++;
00313         }
00314         while (ELEMENT_DIM==2 && face_data.AttributeValue==0); //In triangles format we ignore internal edges (which are marked with attribute 0)
00315     }
00316 
00317     mBoundaryFacesRead++;
00318 
00319     if (mNodePermutationDefined)
00320     {
00321         for (std::vector<unsigned>::iterator node_it = ret_indices.begin();
00322              node_it != ret_indices.end();
00323              ++ node_it)
00324         {
00325             assert(*node_it < mPermutationVector.size());
00326             *node_it =  mPermutationVector[*node_it];
00327         }
00328     }
00329 
00330     face_data.NodeIndices = ret_indices;
00331 
00332     return face_data;
00333 }
00334 
00335 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00336 std::vector<double> TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::GetNode(unsigned index)
00337 {
00338     if (!mFilesAreBinary)
00339     {
00340         EXCEPTION("Random access is only implemented in mesh readers for binary mesh files.");
00341     }
00342     if (index >= mNumNodes)
00343     {
00344         EXCEPTION("Node does not exist - not enough nodes.");
00345     }
00346 
00347     if (mNodePermutationDefined)
00348     {
00349         assert(index<mInversePermutationVector.size());
00350         index = mInversePermutationVector[index];
00351     }
00352 
00353     // Put the file stream pointer to the right location
00354     mNodesFile.seekg(mNodeFileDataStart + mNodeItemWidth*index, std::ios_base::beg);
00355 
00356     // Read the next item.
00357     return GetNextNode();
00358 }
00359 
00360 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00361 ElementData TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::GetElementData(unsigned index)
00362 {
00363     if (!mFilesAreBinary)
00364     {
00365         EXCEPTION("Random access is only implemented in mesh readers for binary mesh files.");
00366     }
00367     if (index >=mNumElements)
00368     {
00369         EXCEPTION("Element " << index << " does not exist - not enough elements (only " << mNumElements << ").");
00370     }
00371 
00372     // Put the file stream pointer to the right location
00373     mElementsFile.seekg(mElementFileDataStart + mElementItemWidth*index, std::ios_base::beg);
00374 
00375     // Read the next item.
00376     return GetNextElementData();
00377 }
00378 
00379 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00380 ElementData TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::GetFaceData(unsigned index)
00381 {
00382     if (!mFilesAreBinary)
00383     {
00384         EXCEPTION("Random access is only implemented in mesh readers for binary mesh files.");
00385     }
00386     if (index >=mNumFaces)
00387     {
00388         EXCEPTION("Face does not exist - not enough faces.");
00389     }
00390 
00391     // Put the file stream pointer to the right location
00392     mFacesFile.seekg(mFaceFileDataStart + mFaceItemWidth*index, std::ios_base::beg);
00393 
00394     // Read the next item
00395     return GetNextFaceData();
00396 }
00397 
00398 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00399 std::vector<unsigned> TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::GetContainingElementIndices(unsigned index)
00400 {
00401     if (!mFilesAreBinary)
00402     {
00403         EXCEPTION("NCL file functionality is only implemented in mesh readers for binary mesh files.");
00404     }
00405 
00406     if (!mNclFileAvailable)
00407     {
00408         EXCEPTION("No NCL file available for this mesh.");
00409     }
00410     if (index >= mNumNodes)
00411     {
00412         EXCEPTION("Connectivity list does not exist - not enough nodes.");
00413     }
00414 
00415     if (mNodePermutationDefined)
00416     {
00417         assert(index < mInversePermutationVector.size());
00418         index = mInversePermutationVector[index];
00419     }
00420 
00421     // Put the file stream pointer to the right location
00422     mNclFile.seekg(mNclFileDataStart + mNclItemWidth*index, std::ios_base::beg);
00423 
00424     // Read the next item
00425     std::vector<unsigned> containing_element_indices;
00426     containing_element_indices.resize(mMaxContainingElements);
00427 
00428     std::vector<unsigned> dummy; // unused here
00429     GetNextItemFromStream(mNclFile, index, containing_element_indices, 0, dummy);
00430 
00431     EnsureIndexingFromZero(containing_element_indices);
00432 
00433     unsigned num_containing_elements = mMaxContainingElements;
00434     while ( containing_element_indices[num_containing_elements-1] == UINT_MAX )
00435     {
00436         num_containing_elements--;
00437     }
00438 
00439     containing_element_indices.resize(num_containing_elements);
00440 
00441     return containing_element_indices;
00442 }
00443 
00444 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00445 void TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::OpenFiles()
00446 {
00447     OpenNodeFile();
00448     OpenElementsFile();
00449     OpenFacesFile();
00450     OpenNclFile();
00451     OpenCableElementsFile();
00452 }
00453 
00454 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00455 void TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::OpenNodeFile()
00456 {
00457     // Nodes definition
00458     std::string file_name = mFilesBaseName + NODES_FILE_EXTENSION;
00459     mNodesFile.open(file_name.c_str());
00460     if (!mNodesFile.is_open())
00461     {
00462         EXCEPTION("Could not open data file: " + file_name);
00463     }
00464 }
00465 
00466 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00467 void TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::OpenElementsFile()
00468 {
00469     // Elements definition
00470     std::string file_name;
00471     if (ELEMENT_DIM == SPACE_DIM)
00472     {
00473         file_name = mFilesBaseName + ELEMENTS_FILE_EXTENSION;
00474     }
00475     else
00476     {
00477         if (ELEMENT_DIM == 1)
00478         {
00479             file_name = mFilesBaseName + EDGES_FILE_EXTENSION;
00480         }
00481         else if (ELEMENT_DIM == 2)
00482         {
00483             file_name = mFilesBaseName + FACES_FILE_EXTENSION;
00484         }
00485         else
00486         {
00487             EXCEPTION("Can't have a zero-dimensional mesh in a one-dimensional space");
00488         }
00489     }
00490 
00491     mElementsFile.open(file_name.c_str());
00492     if (!mElementsFile.is_open())
00493     {
00494         EXCEPTION("Could not open data file: " + file_name);
00495     }
00496 }
00497 
00498 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00499 void TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::OpenFacesFile()
00500 {
00501     // Faces/edges definition
00502     std::string file_name;
00503     if (ELEMENT_DIM == 3)
00504     {
00505         file_name = mFilesBaseName + FACES_FILE_EXTENSION;
00506     }
00507     else if (ELEMENT_DIM == 2)
00508     {
00509         file_name = mFilesBaseName + EDGES_FILE_EXTENSION;
00510     }
00511     else //if (ELEMENT_DIM == 1)
00512     {
00513         // There is no file, data will be read from the node file (with boundaries marked)
00514         return;
00515     }
00516 
00517     mFacesFile.open(file_name.c_str());
00518     if (!mFacesFile.is_open())
00519     {
00520         EXCEPTION("Could not open data file: " + file_name);
00521     }
00522 }
00523 
00524 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00525 void TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::OpenNclFile()
00526 {
00527     std::string file_name = mFilesBaseName + NCL_FILE_EXTENSION;
00528     mNclFile.open(file_name.c_str());
00529 
00530     mNclFileAvailable = mNclFile.is_open();
00531 }
00532 
00533 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00534 void TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::OpenCableElementsFile()
00535 {
00536     std::string file_name = mFilesBaseName + CABLE_FILE_EXTENSION;
00537     mCableElementsFile.open(file_name.c_str());
00538     if (!mCableElementsFile.is_open())
00539     {
00540         mNumCableElements = 0u;
00541         mNumCableElementAttributes = 0u;
00542     }
00543 }
00544 
00545 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00546 std::vector<double> TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::GetNodeAttributes()
00547 {
00548     return mNodeAttributes;
00549 }
00550 
00551 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00552 void TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::ReadHeaders()
00553 {
00554     /*
00555      * Reading node file header
00556      */
00557     std::string buffer;
00558     GetNextLineFromStream(mNodesFile, buffer);
00559     std::stringstream node_header_line(buffer);
00560     unsigned dimension;
00561     node_header_line >> mNumNodes >> dimension >> mNumNodeAttributes >> mMaxNodeBdyMarker;
00562     if (SPACE_DIM != dimension)
00563     {
00564         EXCEPTION("SPACE_DIM  != dimension read from file ");
00565     }
00566 
00567     // Is there anything else on the header line?
00568     std::string extras;
00569     node_header_line >> extras;
00570     if (extras == "BIN")
00571     {
00572         mFilesAreBinary = true;
00573         mNodeFileDataStart = mNodesFile.tellg(); // Record the position of the first byte after the header.
00574         mNodeItemWidth = SPACE_DIM * sizeof(double);
00575 
00576         // We enforce that all binary files (written by Chaste) are indexed from zero
00577         mIndexFromZero = true;
00578     }
00579     else
00580     {
00581         // #1621 - ncl files are only supported in binary read mode.
00582         assert(!mNclFileAvailable);
00583 
00584         // Get the next line to see if it is indexed from zero or not
00585         GetNextLineFromStream(mNodesFile, buffer);
00586         std::stringstream node_first_line(buffer);
00587         unsigned first_index;
00588         node_first_line >> first_index;
00589         assert(first_index == 0 || first_index == 1);
00590         mIndexFromZero = (first_index == 0);
00591 
00592         // Close, reopen, skip header
00593         mNodesFile.close();
00594         OpenNodeFile();
00595         GetNextLineFromStream(mNodesFile, buffer);
00596     }
00597 
00598     /*
00599      * Reading element file header
00600      */
00601     GetNextLineFromStream(mElementsFile, buffer);
00602     std::stringstream element_header_line(buffer);
00603 
00604     unsigned extra_attributes = 0;
00605 
00606     if (ELEMENT_DIM == SPACE_DIM)
00607     {
00608         element_header_line >> mNumElements >> mNumElementNodes >> mNumElementAttributes;
00609 
00610         extra_attributes = mNumElementAttributes;
00611 
00612         // Is there anything else on the header line?
00613         std::string element_extras;
00614         element_header_line >> element_extras;
00615         if (element_extras == "BIN")
00616         {
00617             // Double check for binaryness
00618             assert (mFilesAreBinary);
00619         }
00620         else if (element_extras == "HEX")
00621         {
00622             mMeshIsHexahedral = true;
00623             if ( ELEMENT_DIM == 2 )
00624             {
00625                 mNodesPerElement = 4;
00626                 mNodesPerBoundaryElement = 2;
00627             }
00628             if ( ELEMENT_DIM == 3 )
00629             {
00630                 mNodesPerElement = 8;
00631                 mNodesPerBoundaryElement = 4;
00632             }
00633         }
00634         else
00635         {
00636             assert (element_extras == "");
00637         }
00638 
00639         // The condition below allows the writer to cope with a NodesOnlyMesh
00640         if (mNumElements != 0)
00641         {
00642             if (mNumElementNodes != mNodesPerElement)
00643             {
00644                 EXCEPTION("Number of nodes per elem, " << mNumElementNodes << ", does not match "
00645                       << "expected number, " << mNodesPerElement << " (which is calculated given "
00646                       << "the order of elements chosen, " << mOrderOfElements << " (1=linear, 2=quadratics)");
00647             }
00648         }
00649     }
00650     else
00651     {
00652         element_header_line >> mNumElements >> mNumFaceAttributes;
00653 
00654         extra_attributes = mNumFaceAttributes;
00655 
00656         // Is there anything else on the header line?
00657         std::string element_extras;
00658         element_header_line >> element_extras;
00659         if (element_extras == "BIN")
00660         {
00661             // Double check for binaryness
00662             assert (mFilesAreBinary);
00663         }
00664 
00665         mNodesPerElement = ELEMENT_DIM+1;
00666     }
00667 
00668 
00669     if (mFilesAreBinary)
00670     {
00671         mElementFileDataStart = mElementsFile.tellg(); // Record the position of the first byte after the header.
00672         mElementItemWidth = (mNodesPerElement + extra_attributes) * sizeof(unsigned);
00673     }
00674 
00675     /*
00676      * Reading face/edge file header.
00677      * The condition below allows the writer to cope with a NodesOnlyMesh.
00678      */
00679     if (mNumElements != 0)
00680     {
00681         if (ELEMENT_DIM == 1)
00682         {
00683            GetOneDimBoundary();
00684            mNumFaces = mOneDimBoundary.size();
00685         }
00686         else
00687         {
00688             GetNextLineFromStream(mFacesFile, buffer);
00689             std::stringstream face_header_line(buffer);
00690 
00691             face_header_line >> mNumFaces >> mNumFaceAttributes;
00692             assert(mNumFaceAttributes==0 || mNumFaceAttributes==1);
00693 
00694             /*
00695              * If mNumFaceAttributes=1 then loop over and set mNumFaces to be
00696              * the number of faces which are marked as boundary faces.
00697              * Double check for binaryness.
00698              */
00699             std::string face_extras;
00700             face_header_line >> face_extras;
00701             assert (mFilesAreBinary == (face_extras == "BIN"));
00702             if ((mNumFaceAttributes==1))
00703             {
00704                 unsigned num_boundary_faces = 0;
00705                 bool end_of_file=false;
00706                 while (!end_of_file)
00707                 {
00708                     try
00709                     {
00710                         GetNextFaceData();
00711                         num_boundary_faces++;
00712                     }
00713                     catch(Exception& e)
00714                     {
00715                         if (mEofException)
00716                         {
00717                             end_of_file = true;
00718                         }
00719                         else
00720                         {
00721                             throw e;
00722                         }
00723                     }
00724                 }
00725                 mNumFaces = num_boundary_faces;
00726 
00729     //            if (mNumFaces==0)
00730     //            {
00731     //                EXCEPTION("No boundary elements found. NOTE: elements in face/edge file with an attribute value of 0 are considered to be internal (non-boundary) elements");
00732     //            }
00733 
00734                 // close the file, reopen, and skip the header again
00735                 mFacesFile.close();
00736                 mFacesFile.clear(); // Older versions of gcc don't explicitly reset "fail" and "eof" flags in std::ifstream after calling close()
00737                 OpenFacesFile();
00738                 GetNextLineFromStream(mFacesFile, buffer);
00739                 mFacesRead = 0;
00740                 mBoundaryFacesRead = 0;
00741             }
00742         }
00743     }
00744 
00745     if (mFilesAreBinary)
00746     {
00747         mFaceFileDataStart = mFacesFile.tellg(); // Record the position of the first byte after the header.
00748         mFaceItemWidth = (ELEMENT_DIM + mNumFaceAttributes) * sizeof(unsigned);
00749     }
00750 
00751     /*
00752      * Read NCL file (if one is available)
00753      */
00754     if (mNclFileAvailable)
00755     {
00756         GetNextLineFromStream(mNclFile, buffer);
00757         std::stringstream ncl_header_line(buffer);
00758         unsigned num_nodes_in_file;
00759         ncl_header_line >> num_nodes_in_file >> mMaxContainingElements;
00760 
00761         if ( mNumNodes != num_nodes_in_file )
00762         {
00763             EXCEPTION("NCL file does not contain the correct number of nodes for mesh");
00764         }
00765 
00766         mNclFileDataStart = mNclFile.tellg(); // Record the position of the first byte after the header
00767         mNclItemWidth = mMaxContainingElements * sizeof(unsigned);
00768     }
00769 
00770     /*
00771      * Read cable file (if one is available)
00772      */
00773     if (mCableElementsFile.is_open())
00774     {
00775         GetNextLineFromStream(mCableElementsFile, buffer);
00776         std::stringstream cable_header_line(buffer);
00777         unsigned num_nodes_per_cable_element;
00778         cable_header_line >> mNumCableElements >> num_nodes_per_cable_element >> mNumCableElementAttributes;
00779         assert(num_nodes_per_cable_element == 2u);
00780         mCableElementsRead = 0u;
00781     }
00782 }
00783 
00784 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00785 void TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::CloseFiles()
00786 {
00787     mNodesFile.close();
00788     mElementsFile.close();
00789     mFacesFile.close();
00790     mNclFile.close();
00791     mCableElementsFile.close();
00792 }
00793 
00794 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00795 void TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::GetNextLineFromStream(std::ifstream& rFileStream, std::string& rRawLine)
00796 {
00797     bool line_is_blank;
00798     mEofException = false;
00799     do
00800     {
00801         getline(rFileStream, rRawLine);
00802         if (rFileStream.eof())
00803         {
00804             mEofException = true;
00805             EXCEPTION("File contains incomplete data: unexpected end of file.");
00806         }
00807 
00808         // Get rid of any comment
00809         rRawLine = rRawLine.substr(0, rRawLine.find('#',0));
00810 
00811         line_is_blank = (rRawLine.find_first_not_of(" \t",0) == std::string::npos);
00812     }
00813     while (line_is_blank);
00814 }
00815 
00816 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00817 template<class T_DATA, class T_ATTR>
00818 void TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::GetNextItemFromStream(std::ifstream& rFileStream, unsigned expectedItemNumber,
00819                                std::vector<T_DATA>& rDataPacket, const unsigned& rNumAttributes, std::vector<T_ATTR>& rAttributes)
00820 {
00821     if (mFilesAreBinary)
00822     {
00823         rFileStream.read((char*)&rDataPacket[0], rDataPacket.size()*sizeof(T_DATA));
00824         if (rNumAttributes > 0)
00825         {
00826             for (unsigned i = 0; i < rNumAttributes; i++)
00827             {
00828                 T_ATTR attribute;
00829                 rFileStream.read((char*) &attribute, sizeof(T_ATTR));
00830                 rAttributes.push_back(attribute);
00831             }
00832         }
00833     }
00834     else
00835     {
00836         std::string buffer;
00837         GetNextLineFromStream(rFileStream,buffer);
00838         std::stringstream buffer_stream(buffer);
00839 
00840         unsigned item_index;
00841         buffer_stream >> item_index;
00842 
00843         // If we are indexing from zero our expected item number is one larger
00844         expectedItemNumber += mIndexFromZero ? 0 : 1;
00845 
00846         if (item_index != expectedItemNumber)
00847         {
00848             if (!mIndexFromZero)
00849             {
00850                 // To fix the exception message to agree with file format
00851                 expectedItemNumber--;
00852             }
00853             EXCEPTION("Data for item " << expectedItemNumber << " missing");
00854         }
00855 
00856         for (unsigned i=0; i<rDataPacket.size(); i++)
00857         {
00858             buffer_stream >> rDataPacket[i];
00859         }
00860 
00861         if (rNumAttributes > 0)
00862         {
00863             for (unsigned i = 0; i < rNumAttributes; i++)
00864             {
00865                 T_ATTR attribute;
00866                 buffer_stream >> attribute;
00867                 if (buffer_stream.fail())
00868                 {
00869                     EXCEPTION("Error in reading attribute index " << i << " (out of " << rNumAttributes << ") in one of the files in " << mFilesBaseName);
00870                 }
00871                 rAttributes.push_back(attribute);
00872             }
00873         }
00874     }
00875 }
00876 
00877 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00878 std::string TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::GetMeshFileBaseName()
00879 {
00880     return mFilesBaseName;
00881 }
00882 
00883 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00884 void TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::GetOneDimBoundary()
00885 {
00886     assert(ELEMENT_DIM == 1);
00887     mNumFaceAttributes = 0;
00888     if (!mOneDimBoundary.empty())
00889     {
00890         // We have already read this and have reset the reader (probably from the mesh class)
00891         return;
00892     }
00893     std::vector<unsigned> node_indices(2);
00894     std::vector<unsigned>  dummy_attribute; // unused
00895 
00896     // Count how many times we see each node
00897     std::vector<unsigned> node_count(mNumNodes); // Covers the case if it's indexed from 1
00898     for (unsigned element_index=0; element_index<mNumElements;element_index++)
00899     {
00900         GetNextItemFromStream(mElementsFile, element_index, node_indices, mNumElementAttributes, dummy_attribute);
00901         if (!mIndexFromZero)
00902         {
00903             // Adjust so we are indexing from zero
00904             node_indices[0]--;
00905             node_indices[1]--;
00906         }
00907         node_count[node_indices[0]]++;
00908         node_count[node_indices[1]]++;
00909     }
00910 
00911     // Find the ones which are terminals (only one mention)
00912     for (unsigned node_index=0; node_index<mNumNodes;node_index++)
00913     {
00914         if (node_count[node_index] == 1u)
00915         {
00916             mOneDimBoundary.push_back(node_index);
00917         }
00918     }
00919 
00920     // Close the file, reopen, and skip the header again
00921     mElementsFile.close();
00922     mElementsFile.clear(); // Older versions of gcc don't explicitly reset "fail" and "eof" flags in std::ifstream after calling close()
00923     OpenElementsFile();
00924     std::string buffer;
00925     GetNextLineFromStream(mElementsFile, buffer);
00926 }
00927 
00928 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00929 void TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::EnsureIndexingFromZero(std::vector<unsigned>& rNodeIndices)
00930 {
00931     if (!mIndexFromZero) // If node indices do not start at zero move them all down one so they do
00932     {
00933         for (unsigned i=0; i<rNodeIndices.size(); i++)
00934         {
00935             rNodeIndices[i]--;
00936         }
00937     }
00938 }
00939 
00940 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00941 bool TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::IsFileFormatBinary()
00942 {
00943     return mFilesAreBinary;
00944 }
00945 
00946 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00947 bool TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::HasNclFile()
00948 {
00949     return mNclFileAvailable;
00950 }
00951 
00952 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00953 void TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::SetReadBufferSize(unsigned bufferSize)
00954 {
00955     mNodeFileReadBuffer = new char[bufferSize];
00956     mElementFileReadBuffer = new char[bufferSize];
00957     mFaceFileReadBuffer = new char[bufferSize];
00958 
00959     mNodesFile.rdbuf()->pubsetbuf(mNodeFileReadBuffer, bufferSize);
00960     mElementsFile.rdbuf()->pubsetbuf(mElementFileReadBuffer, bufferSize);
00961     mFacesFile.rdbuf()->pubsetbuf(mFaceFileReadBuffer, bufferSize);
00962 }
00963 
00964 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00965 void TrianglesMeshReader<ELEMENT_DIM, SPACE_DIM>::SetNodePermutation(std::vector<unsigned>& rPermutationVector)
00966 {
00967     if ( !mFilesAreBinary )
00968     {
00969         // It would be too inefficient otherwise...
00970         EXCEPTION("Permuted read can only be used with binary files since it requires random access to the node file.");
00971     }
00972 
00973     mNodePermutationDefined = true;
00974     mPermutationVector = rPermutationVector;
00975     mInversePermutationVector.resize(mPermutationVector.size());
00976     for (unsigned index=0; index<mPermutationVector.size(); index++)
00977     {
00978         mInversePermutationVector[mPermutationVector[index]]=index;
00979     }
00980 }
00981 
00983 // Explicit instantiation
00985 
00986 template class TrianglesMeshReader<0,1>;
00987 template class TrianglesMeshReader<1,1>;
00988 template class TrianglesMeshReader<1,2>;
00989 template class TrianglesMeshReader<1,3>;
00990 template class TrianglesMeshReader<2,2>;
00991 template class TrianglesMeshReader<2,3>;
00992 template class TrianglesMeshReader<3,3>;
00993 
00998 template void TrianglesMeshReader<0,1>::GetNextItemFromStream(std::ifstream&, unsigned, std::vector<unsigned>&, const unsigned&, std::vector<unsigned>&);
00999 template void TrianglesMeshReader<0,1>::GetNextItemFromStream(std::ifstream&, unsigned, std::vector<double>  &, const unsigned&, std::vector<double>&);
01000 template void TrianglesMeshReader<1,1>::GetNextItemFromStream(std::ifstream&, unsigned, std::vector<unsigned>&, const unsigned&, std::vector<unsigned>&);
01001 template void TrianglesMeshReader<1,1>::GetNextItemFromStream(std::ifstream&, unsigned, std::vector<double>  &, const unsigned&, std::vector<double>&);
01002 template void TrianglesMeshReader<1,2>::GetNextItemFromStream(std::ifstream&, unsigned, std::vector<unsigned>&, const unsigned&, std::vector<unsigned>&);
01003 template void TrianglesMeshReader<1,2>::GetNextItemFromStream(std::ifstream&, unsigned, std::vector<double>  &, const unsigned&, std::vector<double>&);
01004 template void TrianglesMeshReader<1,3>::GetNextItemFromStream(std::ifstream&, unsigned, std::vector<unsigned>&, const unsigned&, std::vector<unsigned>&);
01005 template void TrianglesMeshReader<1,3>::GetNextItemFromStream(std::ifstream&, unsigned, std::vector<double>  &, const unsigned&, std::vector<double>&);
01006 template void TrianglesMeshReader<2,2>::GetNextItemFromStream(std::ifstream&, unsigned, std::vector<unsigned>&, const unsigned&, std::vector<unsigned>&);
01007 template void TrianglesMeshReader<2,2>::GetNextItemFromStream(std::ifstream&, unsigned, std::vector<double>  &, const unsigned&, std::vector<double>&);
01008 template void TrianglesMeshReader<2,3>::GetNextItemFromStream(std::ifstream&, unsigned, std::vector<unsigned>&, const unsigned&, std::vector<unsigned>&);
01009 template void TrianglesMeshReader<2,3>::GetNextItemFromStream(std::ifstream&, unsigned, std::vector<double>  &, const unsigned&, std::vector<double>&);
01010 template void TrianglesMeshReader<3,3>::GetNextItemFromStream(std::ifstream&, unsigned, std::vector<unsigned>&, const unsigned&, std::vector<unsigned>&);
01011 template void TrianglesMeshReader<3,3>::GetNextItemFromStream(std::ifstream&, unsigned, std::vector<double>  &, const unsigned&, std::vector<double>&);