/*========================================================================= Program: Visualization Toolkit Module: vtkAMREnzoReader.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtkAMREnzoReader.h" #include "vtkObjectFactory.h" #include "vtkOverlappingAMR.h" #include "vtkUniformGrid.h" #include "vtkDataArraySelection.h" #include "vtkDataArray.h" #include "vtkPolyData.h" #include "vtkIndent.h" #include "vtkInformation.h" #include "vtksys/SystemTools.hxx" #include "vtkDataSet.h" #include "vtkCellData.h" #include "vtkIntArray.h" #include "vtkLongArray.h" #include "vtkShortArray.h" #include "vtkFloatArray.h" #include "vtkDoubleArray.h" #include "vtkLongLongArray.h" #include "vtkUnsignedIntArray.h" #include "vtkUnsignedCharArray.h" #include "vtkUnsignedShortArray.h" #define H5_USE_16_API #include "vtk_hdf5.h" #include #include #include #include #include "vtkAMREnzoReaderInternal.h" vtkStandardNewMacro(vtkAMREnzoReader); #include "vtkAMRInformation.h" #include void vtkAMREnzoReader::ComputeStats(vtkEnzoReaderInternal* internal, std::vector& numBlocks, double min[3]) { min[0] = min[1] = min[2] = std::numeric_limits::max(); numBlocks.resize( this->Internal->NumberOfLevels, 0 ); for( int i=0; i < internal->NumberOfBlocks; ++i ) { vtkEnzoReaderBlock &theBlock = internal->Blocks[ i+1 ]; double* gridMin = theBlock.MinBounds; if( gridMin[0] < min[0] ) { min[0] = gridMin[0]; } if( gridMin[1] < min[1] ) { min[1] = gridMin[1]; } if( gridMin[2] < min[2] ) { min[2] = gridMin[2]; } numBlocks[theBlock.Level]++; } } //----------------------------------------------------------------------------- vtkAMREnzoReader::vtkAMREnzoReader() { this->Internal = new vtkEnzoReaderInternal(); this->IsReady = false; this->Initialize(); this->ConvertToCGS = 1; } //----------------------------------------------------------------------------- vtkAMREnzoReader::~vtkAMREnzoReader() { delete this->Internal; this->Internal=nullptr; this->BlockMap.clear(); delete [] this->FileName; this->FileName = nullptr; } //----------------------------------------------------------------------------- void vtkAMREnzoReader::PrintSelf( std::ostream &os, vtkIndent indent ) { this->Superclass::PrintSelf( os, indent ); } //----------------------------------------------------------------------------- int vtkAMREnzoReader::GetIndexFromArrayName( std::string arrayName ) { char stringIdx[2]; stringIdx[0] = arrayName.at( arrayName.size()-2 ); stringIdx[1] = '\0'; return( atoi( stringIdx ) ); } //----------------------------------------------------------------------------- double vtkAMREnzoReader::GetConversionFactor( const std::string &name ) { if( this->label2idx.find( name ) != this->label2idx.end() ) { int idx = this->label2idx[ name ]; if( this->conversionFactors.find( idx ) != this->conversionFactors.end() ) { return( this->conversionFactors[ idx ] ); } else { return( 1.0 ); } } return( 1.0 ); } //----------------------------------------------------------------------------- void vtkAMREnzoReader::ParseLabel( const std::string &labelString, int &idx, std::string &label) { std::vector< std::string > strings; std::istringstream iss( labelString ); std::string word; while ( iss >> word ) { if( !vtksys::SystemTools::StringStartsWith( word.c_str(), "=") ) { strings.push_back( word ); } } idx = this->GetIndexFromArrayName( strings[0] ); label = strings[ strings.size()-1 ]; } //----------------------------------------------------------------------------- void vtkAMREnzoReader::ParseCFactor( const std::string &labelString, int &idx, double &factor ) { std::vector< std::string > strings; std::istringstream iss( labelString ); std::string word; while( iss >> word ) { if( ! vtksys::SystemTools::StringStartsWith( word.c_str(), "=") ) { strings.push_back( word ); } } idx = this->GetIndexFromArrayName( strings[0] ); factor = atof( strings[ strings.size()-1 ].c_str() ); } //----------------------------------------------------------------------------- void vtkAMREnzoReader::ParseConversionFactors( ) { assert( "pre: FileName should not be nullptr" && (this->FileName != nullptr) ); // STEP 0: Extract the parameters file from the user-supplied filename std::string baseDir = vtksys::SystemTools::GetFilenamePath( std::string( this->FileName ) ); std::string paramsFile = baseDir + "/" + vtksys::SystemTools::GetFilenameWithoutExtension( std::string( this->FileName ) ); // STEP 1: Open Parameters file std::ifstream ifs; ifs.open( paramsFile.c_str() ); if( !ifs.is_open( ) ) { vtkWarningMacro( "Cannot open ENZO parameters file!\n" ); return; } // STEP 2: Parsing parameters file std::string line; // temp string to store a line read from the params file std::string label; // stores the attribute name double cf; // stores the conversion factor int idx; // stores the attribute label index while( getline(ifs, line) ) { if( vtksys::SystemTools::StringStartsWith( line.c_str(), "DataLabel" ) ) { this->ParseLabel( line, idx, label ); this->label2idx[ label ] = idx; } else if( vtksys::SystemTools::StringStartsWith( line.c_str(), "#DataCGSConversionFactor" ) ) { this->ParseCFactor( line, idx, cf ); this->conversionFactors[ idx ] = cf; } } // STEP 3: Close parameters file ifs.close(); } //----------------------------------------------------------------------------- void vtkAMREnzoReader::SetFileName( const char* fileName ) { assert("pre: Internal Enzo AMR Reader is nullptr" && (this->Internal != nullptr )); if( fileName && strcmp( fileName, "" ) && ( (this->FileName==nullptr) || (strcmp(fileName,this->FileName ) ) ) ) { std::string tempName( fileName ); std::string bExtName( ".boundary" ); std::string hExtName( ".hierarchy" ); if( tempName.length() > hExtName.length() && tempName.substr(tempName.length()-hExtName.length() )== hExtName ) { this->Internal->MajorFileName = tempName.substr( 0, tempName.length() - hExtName.length() ); this->Internal->HierarchyFileName = tempName; this->Internal->BoundaryFileName = this->Internal->MajorFileName+bExtName; } else if( tempName.length() > bExtName.length() && tempName.substr( tempName.length() - bExtName.length() )==bExtName ) { this->Internal->MajorFileName = tempName.substr( 0, tempName.length() - bExtName.length() ); this->Internal->BoundaryFileName = tempName; this->Internal->HierarchyFileName = this->Internal->MajorFileName+hExtName; } else { vtkErrorMacro( "Enzo file has invalid extension!"); return; } this->IsReady = true; this->Internal->DirectoryName = GetEnzoDirectory(this->Internal->MajorFileName.c_str()); } if( this->IsReady ) { this->BlockMap.clear(); this->Internal->Blocks.clear(); this->Internal->NumberOfBlocks = 0; this->LoadedMetaData = false; if ( this->FileName != nullptr) { delete [] this->FileName; this->FileName = nullptr; this->Internal->SetFileName( nullptr ); } this->FileName = new char[ strlen( fileName ) + 1 ]; strcpy( this->FileName, fileName ); this->FileName[ strlen( fileName ) ] = '\0'; this->Internal->SetFileName( this->FileName ); this->ParseConversionFactors( ); this->Internal->ReadMetaData(); this->SetUpDataArraySelections(); this->InitializeArraySelections(); } this->Modified(); } //----------------------------------------------------------------------------- void vtkAMREnzoReader::ReadMetaData() { assert( "pre: Internal Enzo Reader is nullptr" && (this->Internal != nullptr) ); if( !this->IsReady ) { return; } this->Internal->ReadMetaData(); } //----------------------------------------------------------------------------- int vtkAMREnzoReader::GetBlockLevel( const int blockIdx ) { assert( "pre: Internal Enzo Reader is nullptr" && (this->Internal != nullptr) ); if( !this->IsReady ) { return( -1 ); } this->Internal->ReadMetaData(); if( blockIdx < 0 || blockIdx >= this->Internal->NumberOfBlocks ) { vtkErrorMacro( "Block Index (" << blockIdx << ") is out-of-bounds!" ); return( -1 ); } return( this->Internal->Blocks[ blockIdx+1 ].Level ); } //----------------------------------------------------------------------------- int vtkAMREnzoReader::GetNumberOfBlocks() { assert( "pre: Internal Enzo Reader is nullptr" && (this->Internal != nullptr) ); if( !this->IsReady ) { return 0; } this->Internal->ReadMetaData(); return( this->Internal->NumberOfBlocks ); } //----------------------------------------------------------------------------- int vtkAMREnzoReader::GetNumberOfLevels() { assert( "pre: Internal Enzo Reader is nullptr" && (this->Internal != nullptr) ); if( !this->IsReady ) { return 0; } this->Internal->ReadMetaData(); return( this->Internal->NumberOfLevels ); } //----------------------------------------------------------------------------- int vtkAMREnzoReader::FillMetaData( ) { assert( "pre: Internal Enzo Reader is nullptr" && (this->Internal != nullptr) ); assert( "pre: metadata object is nullptr" && (this->Metadata != nullptr) ); if( !this->IsReady ) { return 0; } this->Internal->ReadMetaData(); double origin[3]; std::vector blocksPerLevel; this->ComputeStats(this->Internal, blocksPerLevel, origin); this->Metadata->Initialize( static_cast(blocksPerLevel.size()), &blocksPerLevel[0]); this->Metadata->SetGridDescription(VTK_XYZ_GRID); this->Metadata->SetOrigin(origin); std::vector< int > b2level( this->Internal->NumberOfLevels+1, 0 ); for( int block=0; block < this->Internal->NumberOfBlocks; ++block ) { vtkEnzoReaderBlock &theBlock = this->Internal->Blocks[ block+1 ]; int level = theBlock.Level; int internalIdx = block; int id = b2level[ level ]; //compute spacing double spacing[3]; for(int d=0; d<3; ++d) { spacing[d] = (theBlock.BlockNodeDimensions[d] > 1)? (theBlock.MaxBounds[d]-theBlock.MinBounds[d])/(theBlock.BlockNodeDimensions[d]-1.0):1.0; } //compute AMRBox vtkAMRBox box(theBlock.MinBounds, theBlock.BlockNodeDimensions, spacing, origin, VTK_XYZ_GRID); //set meta data this->Metadata->SetSpacing(level,spacing); this->Metadata->SetAMRBox(level, id, box); this->Metadata->SetAMRBlockSourceIndex(level,id, internalIdx); b2level[ level ]++; } this->Metadata->GenerateParentChildInformation(); this->Metadata->GetInformation()->Set(vtkDataObject::DATA_TIME_STEP(),this->Internal->DataTime); return( 1 ); } //----------------------------------------------------------------------------- vtkUniformGrid* vtkAMREnzoReader::GetAMRGrid( const int blockIdx ) { assert( "pre: Internal Enzo Reader is nullptr" && (this->Internal != nullptr) ); if( !this->IsReady ) { return nullptr; } this->Internal->ReadMetaData(); // this->Internal->Blocks includes a pseudo block --- the root as block #0 vtkEnzoReaderBlock &theBlock = this->Internal->Blocks[ blockIdx+1 ]; double blockMin[3]; double blockMax[3]; double spacings[3]; for( int i=0; i < 3; ++i ) { blockMin[ i ] = theBlock.MinBounds[ i ]; blockMax[ i ] = theBlock.MaxBounds[ i ]; spacings[ i ] = (theBlock.BlockNodeDimensions[i] > 1)? (blockMax[i]-blockMin[i])/(theBlock.BlockNodeDimensions[i]-1.0) : 1.0; } vtkUniformGrid *ug = vtkUniformGrid::New(); ug->SetDimensions( theBlock.BlockNodeDimensions ); ug->SetOrigin( blockMin[0], blockMin[1], blockMin[2] ); ug->SetSpacing( spacings[0], spacings[1], spacings[2] ); return( ug ); } //----------------------------------------------------------------------------- void vtkAMREnzoReader::GetAMRGridData( const int blockIdx, vtkUniformGrid *block, const char *field) { assert( "pre: AMR block is nullptr" && (block != nullptr)); this->Internal->GetBlockAttribute( field, blockIdx, block ); if( this->ConvertToCGS == 1 ) { double conversionFactor = this->GetConversionFactor(field); if( conversionFactor != 1.0 ) { vtkDataArray *data = block->GetCellData()->GetArray( field ); assert( "pre: data array is nullptr!" && (data != nullptr) ); vtkIdType numTuples = data->GetNumberOfTuples(); for( vtkIdType t=0; t < numTuples; ++t ) { int numComp = data->GetNumberOfComponents(); for( int c=0; c < numComp; ++c ) { double f = data->GetComponent( t, c ); data->SetComponent( t, c, f*conversionFactor ); } // END for all components } // END for all tuples } // END if the conversion factor is not 1.0 } // END if conversion to CGS units is requested } //----------------------------------------------------------------------------- void vtkAMREnzoReader::SetUpDataArraySelections() { assert( "pre: Internal Enzo Reader is nullptr" && (this->Internal != nullptr) ); this->Internal->ReadMetaData(); this->Internal->GetAttributeNames(); int numAttrs = static_cast< int >(this->Internal->BlockAttributeNames.size()); for( int i=0; i < numAttrs; i++ ) { this->CellDataArraySelection->AddArray( this->Internal->BlockAttributeNames[i].c_str() ); } // END for all attributes }