diff --git a/IO/EnSight/vtkEnSightGoldBinaryReader.cxx b/IO/EnSight/vtkEnSightGoldBinaryReader.cxx index fa28dd5f3973a4266ef46aa7d8660c05411e336a..8da2d00a2977468500993ad61a9a2ce4ff82cacc 100644 --- a/IO/EnSight/vtkEnSightGoldBinaryReader.cxx +++ b/IO/EnSight/vtkEnSightGoldBinaryReader.cxx @@ -31,15 +31,32 @@ #include <sys/stat.h> #include <ctype.h> #include <string> +#include <vector> +#include <map> vtkStandardNewMacro(vtkEnSightGoldBinaryReader); + +class vtkEnSightGoldBinaryReader::FileOffsetMapInternal +{ + typedef std::string MapKey; + typedef std::map<int,long> MapValue; + public: + typedef std::map<MapKey, MapValue>::const_iterator const_iterator; + typedef std::map<MapKey, MapValue>::value_type value_type; + + std::map<MapKey, MapValue> Map; +}; + + // This is half the precision of an int. #define MAXIMUM_PART_ID 65536 //---------------------------------------------------------------------------- vtkEnSightGoldBinaryReader::vtkEnSightGoldBinaryReader() { + this->FileOffsets = new vtkEnSightGoldBinaryReader::FileOffsetMapInternal; + this->IFile = NULL; this->FileSize = 0; this->SizeOfInt = (int)sizeof(int); @@ -51,6 +68,8 @@ vtkEnSightGoldBinaryReader::vtkEnSightGoldBinaryReader() //---------------------------------------------------------------------------- vtkEnSightGoldBinaryReader::~vtkEnSightGoldBinaryReader() { + delete this->FileOffsets; + if (this->IFile) { this->IFile->close(); @@ -252,7 +271,12 @@ int vtkEnSightGoldBinaryReader::ReadGeometryFile(const char* fileName, int timeS { if (numberOfTimeStepsInFile>1) { - for (i = 0; i < timeStep - 1; i++) + this->AddFileIndexToCache(fileName); + + i = this->SeekToCachedTimeStep(fileName, timeStep-1); + // start w/ the number of TS we skipped, not the one we are at + // if we are not at the appropriate time step yet, we keep searching + for (; i < timeStep - 1; i++) { if (!this->SkipTimeStep()) { @@ -268,6 +292,8 @@ int vtkEnSightGoldBinaryReader::ReadGeometryFile(const char* fileName, int timeS this->ReadLine(line); } while ( strncmp(line, "BEGIN TIME STEP", 15) != 0 ); + // found a time step -> cache it + this->AddTimeStepToCache(fileName, timeStep-1, this->IFile->tellg()); } // Skip the 2 description lines. @@ -1151,7 +1177,12 @@ int vtkEnSightGoldBinaryReader::ReadMeasuredGeometryFile(const char* fileName, if (this->UseFileSets) { - for (i = 0; i < timeStep - 1; i++) + this->AddFileIndexToCache(fileName); + + i = this->SeekToCachedTimeStep(fileName, timeStep-1); + // start w/ the number of TS we skipped, not the one we are at + // if we are not at the appropriate time step yet, we keep searching + for (; i < timeStep - 1; i++) { while (strncmp(line, "BEGIN TIME STEP", 15) != 0) { @@ -1181,6 +1212,8 @@ int vtkEnSightGoldBinaryReader::ReadMeasuredGeometryFile(const char* fileName, { this->ReadLine(line); } + // found a time step -> cache it + this->AddTimeStepToCache(fileName, i, this->IFile->tellg()); } // Skip the description line. @@ -1301,13 +1334,21 @@ int vtkEnSightGoldBinaryReader::ReadScalarsPerNode( if (this->UseFileSets) { - for (i = 0; i < timeStep - 1; i++) + this->AddFileIndexToCache(fileName); + + i = this->SeekToCachedTimeStep(fileName, timeStep-1); + // start w/ the number of TS we skipped, not the one we are at + // if we are not at the appropriate time step yet, we keep searching + for (; i < timeStep - 1; i++) { this->ReadLine(line); while (strncmp(line, "BEGIN TIME STEP", 15) != 0) { this->ReadLine(line); } + // found a time step -> cache it + this->AddTimeStepToCache(fileName, i, this->IFile->tellg()); + this->ReadLine(line); // skip the description line if (measured) @@ -1502,13 +1543,21 @@ int vtkEnSightGoldBinaryReader::ReadVectorsPerNode( if (this->UseFileSets) { - for (i = 0; i < timeStep - 1; i++) + this->AddFileIndexToCache(fileName); + + i = this->SeekToCachedTimeStep(fileName, timeStep-1); + // start w/ the number of TS we skipped, not the one we are at + // if we are not at the appropriate time step yet, we keep searching + for (; i < timeStep - 1; i++) { this->ReadLine(line); while (strncmp(line, "BEGIN TIME STEP", 15) != 0) { this->ReadLine(line); } + // found a time step -> cache it + this->AddTimeStepToCache(fileName, i, this->IFile->tellg()); + this->ReadLine(line); // skip the description line if (measured) @@ -1683,13 +1732,21 @@ int vtkEnSightGoldBinaryReader::ReadTensorsPerNode( if (this->UseFileSets) { - for (i = 0; i < timeStep - 1; i++) + this->AddFileIndexToCache(fileName); + + i = this->SeekToCachedTimeStep(fileName, timeStep-1); + // start w/ the number of TS we skipped, not the one we are at + // if we are not at the appropriate time step yet, we keep searching + for (; i < timeStep - 1; i++) { this->ReadLine(line); while (strncmp(line, "BEGIN TIME STEP", 15) != 0) { this->ReadLine(line); } + // found a time step -> cache it + this->AddTimeStepToCache(fileName, i, this->IFile->tellg()); + this->ReadLine(line); // skip the description line while (this->ReadLine(line) && @@ -1828,13 +1885,21 @@ int vtkEnSightGoldBinaryReader::ReadScalarsPerElement( if (this->UseFileSets) { - for (i = 0; i < timeStep - 1; i++) + this->AddFileIndexToCache(fileName); + + i = this->SeekToCachedTimeStep(fileName, timeStep-1); + // start w/ the number of TS we skipped, not the one we are at + // if we are not at the appropriate time step yet, we keep searching + for (; i < timeStep - 1; i++) { this->ReadLine(line); while (strncmp(line, "BEGIN TIME STEP", 15) != 0) { this->ReadLine(line); } + // found a time step -> cache it + this->AddTimeStepToCache(fileName, i, this->IFile->tellg()); + this->ReadLine(line); // skip the description line lineRead = this->ReadLine(line); // "part" @@ -2066,13 +2131,21 @@ int vtkEnSightGoldBinaryReader::ReadVectorsPerElement( if (this->UseFileSets) { - for (i = 0; i < timeStep - 1; i++) + this->AddFileIndexToCache(fileName); + + i = this->SeekToCachedTimeStep(fileName, timeStep-1); + // start w/ the number of TS we skipped, not the one we are at + // if we are not at the appropriate time step yet, we keep searching + for (; i < timeStep - 1; i++) { this->ReadLine(line); while (strncmp(line, "BEGIN TIME STEP", 15) != 0) { this->ReadLine(line); } + // found a time step -> cache it + this->AddTimeStepToCache(fileName, i, this->IFile->tellg()); + this->ReadLine(line); // skip the description line lineRead = this->ReadLine(line); // "part" @@ -2298,13 +2371,21 @@ int vtkEnSightGoldBinaryReader::ReadTensorsPerElement( if (this->UseFileSets) { - for (i = 0; i < timeStep - 1; i++) + this->AddFileIndexToCache(fileName); + + i = this->SeekToCachedTimeStep(fileName, timeStep-1); + // start w/ the number of TS we skipped, not the one we are at + // if we are not at the appropriate time step yet, we keep searching + for (; i < timeStep - 1; i++) { this->ReadLine(line); while (strncmp(line, "BEGIN TIME STEP", 15) != 0) { this->ReadLine(line); } + // found a time step -> cache it + this->AddTimeStepToCache(fileName, i, this->IFile->tellg()); + this->ReadLine(line); // skip the description line lineRead = this->ReadLine(line); // "part" @@ -4069,6 +4150,47 @@ int vtkEnSightGoldBinaryReader::ReadIntArray(int *result, return 1; } +// Internal function to read a single long. +// Returns zero if there was an error. +int vtkEnSightGoldBinaryReader::ReadLong(long *result) +{ + char dummy[4]; + if (this->Fortran) + { + if (!this->IFile->read(dummy, 4)) + { + vtkErrorMacro("Read (fortran) failed."); + return 0; + } + } + + if (!this->IFile->read((char*)result, sizeof(long))) + { + vtkErrorMacro("Read failed"); + return 0; + } + + if (this->ByteOrder == FILE_LITTLE_ENDIAN) + { + vtkByteSwap::Swap8LE(result); + } + else if (this->ByteOrder == FILE_BIG_ENDIAN) + { + vtkByteSwap::Swap8BE(result); + } + + if (this->Fortran) + { + if (!this->IFile->read(dummy, 4)) + { + vtkErrorMacro("Read (fortran) failed."); + return 0; + } + } + + return 1; +} + // Internal function to read a float array. // Returns zero if there was an error. int vtkEnSightGoldBinaryReader::ReadFloatArray(float *result, @@ -4120,3 +4242,92 @@ void vtkEnSightGoldBinaryReader::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } + +// Seeks the IFile to the cached timestep nearest the target timestep. +// Returns the actually seeked to timestep +//---------------------------------------------------------------------------- +int vtkEnSightGoldBinaryReader::SeekToCachedTimeStep(const char* fileName, + int realTimeStep) +{ + typedef vtkEnSightGoldBinaryReader::FileOffsetMapInternal MapType; + typedef MapType::const_iterator MapNameIterator; + typedef MapType::value_type::second_type::const_iterator FileOffsetIterator; + + int j = 0; + + MapNameIterator nameIterator = this->FileOffsets->Map.find(fileName); + if(nameIterator == this->FileOffsets->Map.end()) + { + return j; + } + + // Try to find the nearest time step for which we know the offset + for (int i = realTimeStep; i >= 0; i--) + { + FileOffsetIterator fileOffsetIterator = nameIterator->second.find(i); + if (fileOffsetIterator != nameIterator->second.end()) + { + //we need to account for the last 80 characters as where we need to seek, + //as we need to be at the BEGIN TIMESTEP keyword and not + //the description line + this->IFile->seekg(fileOffsetIterator->second - 80l, ios::beg); + j = i; + break; + } + } + return j; +} + +//---------------------------------------------------------------------------- +// Add a cached file offset +void vtkEnSightGoldBinaryReader::AddTimeStepToCache(const char* fileName, + int realTimeStep, + long address) +{ + if (this->FileOffsets->Map.find(fileName) == this->FileOffsets->Map.end()) + { + std::map<int, long> tsMap; + this->FileOffsets->Map[fileName] = tsMap; + } + this->FileOffsets->Map[fileName][realTimeStep] = address; + return; +} + +//---------------------------------------------------------------------------- +void vtkEnSightGoldBinaryReader::AddFileIndexToCache(const char* fileName) +{ + // only read the file index if we have not searched for the file index before + if (this->FileOffsets->Map.find(fileName) == this->FileOffsets->Map.end()) + { + char line[80]; + long addr; + int numTS; + + // We add an empty map to prevent further attempts at reading the file index + std::map<int, long> tsMap; + this->FileOffsets->Map[fileName] = tsMap; + + // Read the last 80 characters (+ a long) of the file and check for FILE_INDEX + this->IFile->seekg(-80*sizeof(char)-sizeof(long), ios::end); + + // right before the FILE_INDEX entry we might find the address of the index start + this->ReadLong(&addr); + this->ReadLine(line); + + if (strncmp(line, "FILE_INDEX", 10) == 0) + { + // jump to beginning of the index and add all time steps + this->IFile->seekg(addr, ios::beg); + this->ReadInt(&numTS); + + for (int i = 0; i < numTS; ++i) + { + this->ReadLong(&addr); + // The file index points at the description line, while VTK points at BEGIN TIMESTEP + this->FileOffsets->Map[fileName][i] = addr; + } + } + } + this->IFile->seekg(0l, ios::beg); + return; +} diff --git a/IO/EnSight/vtkEnSightGoldBinaryReader.h b/IO/EnSight/vtkEnSightGoldBinaryReader.h index b1659138016deef8a7bf2e43a329d372d3fb3052..34c91e3e3397c76b364f87c82c4a0f2642e850e3 100644 --- a/IO/EnSight/vtkEnSightGoldBinaryReader.h +++ b/IO/EnSight/vtkEnSightGoldBinaryReader.h @@ -40,6 +40,7 @@ #include "vtkIOEnSightModule.h" // For export macro #include "vtkEnSightReader.h" + class vtkMultiBlockDataSet; class VTKIOENSIGHT_EXPORT vtkEnSightGoldBinaryReader : public vtkEnSightReader @@ -78,7 +79,8 @@ protected: // the data array, it is assumed that 0 is the first component added. virtual int ReadScalarsPerNode(const char* fileName, const char* description, int timeStep, vtkMultiBlockDataSet *output, - int measured = 0, int numberOfComponents = 1, + int measured = 0, + int numberOfComponents = 1, int component = 0); // Description: @@ -160,6 +162,11 @@ protected: // Returns zero if there was an error. int ReadIntArray(int *result, int numInts); + // Description: + // Internal function to read in a single long. + // Returns zero if there was an error. + int ReadLong(long *result); + // Description: // Internal function to read in a float array. // Returns zero if there was an error. @@ -180,6 +187,18 @@ protected: int SkipRectilinearGrid(char line[256]); int SkipImageData(char line[256]); + // Description: + // Seeks the IFile to the nearest time step that is <= the target time step + int SeekToCachedTimeStep(const char* fileName, int realTimeStep); + + // Description: + // Add an entry the time step cache + void AddTimeStepToCache(const char* fileName, int realTimeStep, long address); + + // Description: + // Read the file index, if available, and add it to the time step cache + void AddFileIndexToCache(const char* fileName); + int NodeIdsListed; int ElementIdsListed; int Fortran; @@ -188,6 +207,11 @@ protected: // The size of the file could be used to choose byte order. vtkIdType FileSize; + //BTX + class FileOffsetMapInternal; + FileOffsetMapInternal *FileOffsets; + //ETX + private: int SizeOfInt; vtkEnSightGoldBinaryReader(const vtkEnSightGoldBinaryReader&); // Not implemented.