TrianglesMeshReader.cpp

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