TrianglesMeshReader.cpp

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

Generated by  doxygen 1.6.2