TrianglesMeshReader.cpp

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

Generated by  doxygen 1.6.2