1 /*=========================================================================
2 
3  Program:   Visualization Toolkit
4  Module:    vtkAMREnzoReader.cxx
5 
6  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7  All rights reserved.
8  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10  This software is distributed WITHOUT ANY WARRANTY; without even
11  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12  PURPOSE.  See the above copyright notice for more information.
13 
14  =========================================================================*/
15 
16 #include "vtkAMREnzoReader.h"
17 #include "vtkObjectFactory.h"
18 #include "vtkOverlappingAMR.h"
19 #include "vtkUniformGrid.h"
20 #include "vtkDataArraySelection.h"
21 #include "vtkDataArray.h"
22 #include "vtkPolyData.h"
23 #include "vtkIndent.h"
24 #include "vtkInformation.h"
25 #include "vtksys/SystemTools.hxx"
26 
27 #include "vtkDataSet.h"
28 #include "vtkCellData.h"
29 #include "vtkIntArray.h"
30 #include "vtkLongArray.h"
31 #include "vtkShortArray.h"
32 #include "vtkFloatArray.h"
33 #include "vtkDoubleArray.h"
34 #include "vtkLongLongArray.h"
35 #include "vtkUnsignedIntArray.h"
36 #include "vtkUnsignedCharArray.h"
37 #include "vtkUnsignedShortArray.h"
38 
39 #define H5_USE_16_API
40 #include "vtk_hdf5.h"
41 
42 #include <sstream>
43 #include <vector>
44 #include <string>
45 #include <cassert>
46 
47 #include "vtkAMREnzoReaderInternal.h"
48 
49 vtkStandardNewMacro(vtkAMREnzoReader);
50 
51 #include "vtkAMRInformation.h"
52 #include <limits>
53 
ComputeStats(vtkEnzoReaderInternal * internal,std::vector<int> & numBlocks,double min[3])54 void vtkAMREnzoReader::ComputeStats(vtkEnzoReaderInternal* internal, std::vector<int>& numBlocks, double min[3])
55 {
56   min[0] = min[1] = min[2] = std::numeric_limits<double>::max();
57   numBlocks.resize( this->Internal->NumberOfLevels, 0 );
58 
59   for( int i=0; i < internal->NumberOfBlocks; ++i )
60   {
61     vtkEnzoReaderBlock &theBlock = internal->Blocks[ i+1 ];
62     double* gridMin = theBlock.MinBounds;
63     if( gridMin[0] < min[0] )
64     {
65       min[0] = gridMin[0];
66     }
67     if( gridMin[1] < min[1] )
68     {
69       min[1] = gridMin[1];
70     }
71     if( gridMin[2] < min[2] )
72     {
73       min[2] = gridMin[2];
74     }
75     numBlocks[theBlock.Level]++;
76   }
77 }
78 
79 //-----------------------------------------------------------------------------
vtkAMREnzoReader()80 vtkAMREnzoReader::vtkAMREnzoReader()
81 {
82   this->Internal = new vtkEnzoReaderInternal();
83   this->IsReady  = false;
84   this->Initialize();
85   this->ConvertToCGS = 1;
86 }
87 
88 //-----------------------------------------------------------------------------
~vtkAMREnzoReader()89 vtkAMREnzoReader::~vtkAMREnzoReader()
90 {
91   delete this->Internal;
92   this->Internal=nullptr;
93 
94   this->BlockMap.clear();
95 
96   delete [] this->FileName;
97   this->FileName = nullptr;
98 }
99 
100 //-----------------------------------------------------------------------------
PrintSelf(std::ostream & os,vtkIndent indent)101 void vtkAMREnzoReader::PrintSelf( std::ostream &os, vtkIndent indent )
102 {
103   this->Superclass::PrintSelf( os, indent );
104 }
105 
106 //-----------------------------------------------------------------------------
GetIndexFromArrayName(std::string arrayName)107 int vtkAMREnzoReader::GetIndexFromArrayName( std::string arrayName )
108 {
109   char stringIdx[2];
110   stringIdx[0] = arrayName.at( arrayName.size()-2 );
111   stringIdx[1] = '\0';
112   return( atoi( stringIdx ) );
113 }
114 
115 //-----------------------------------------------------------------------------
GetConversionFactor(const std::string & name)116 double vtkAMREnzoReader::GetConversionFactor( const std::string &name )
117 {
118   if( this->label2idx.find( name ) != this->label2idx.end() )
119   {
120     int idx = this->label2idx[ name ];
121     if( this->conversionFactors.find( idx ) != this->conversionFactors.end() )
122     {
123       return( this->conversionFactors[ idx ] );
124     }
125     else
126     {
127       return( 1.0 );
128     }
129   }
130   return( 1.0 );
131 }
132 
133 //-----------------------------------------------------------------------------
ParseLabel(const std::string & labelString,int & idx,std::string & label)134 void vtkAMREnzoReader::ParseLabel(
135     const std::string &labelString, int &idx, std::string &label)
136 {
137 
138   std::vector< std::string > strings;
139 
140   std::istringstream iss( labelString );
141   std::string word;
142   while ( iss >> word )
143   {
144     if( !vtksys::SystemTools::StringStartsWith( word.c_str(), "=") )
145     {
146       strings.push_back( word );
147     }
148   }
149 
150   idx   = this->GetIndexFromArrayName( strings[0] );
151   label = strings[ strings.size()-1 ];
152 }
153 
154 //-----------------------------------------------------------------------------
ParseCFactor(const std::string & labelString,int & idx,double & factor)155 void vtkAMREnzoReader::ParseCFactor(
156     const std::string &labelString, int &idx, double &factor )
157 {
158   std::vector< std::string > strings;
159 
160   std::istringstream iss( labelString );
161   std::string word;
162   while( iss >> word )
163   {
164     if( ! vtksys::SystemTools::StringStartsWith( word.c_str(), "=") )
165     {
166       strings.push_back( word );
167     }
168   }
169 
170   idx    = this->GetIndexFromArrayName( strings[0] );
171   factor = atof( strings[ strings.size()-1 ].c_str() );
172 
173 }
174 
175 //-----------------------------------------------------------------------------
ParseConversionFactors()176 void vtkAMREnzoReader::ParseConversionFactors( )
177 {
178   assert( "pre: FileName should not be nullptr" && (this->FileName != nullptr) );
179 
180   // STEP 0: Extract the parameters file from the user-supplied filename
181   std::string baseDir =
182       vtksys::SystemTools::GetFilenamePath( std::string( this->FileName ) );
183 
184   std::string paramsFile = baseDir + "/" +
185    vtksys::SystemTools::GetFilenameWithoutExtension(
186     std::string( this->FileName ) );
187 
188   // STEP 1: Open Parameters file
189   std::ifstream ifs;
190   ifs.open( paramsFile.c_str() );
191   if( !ifs.is_open( ) )
192   {
193     vtkWarningMacro( "Cannot open ENZO parameters file!\n" );
194     return;
195   }
196 
197   // STEP 2: Parsing parameters file
198   std::string line;  // temp string to store a line read from the params file
199   std::string label; // stores the attribute name
200   double cf;         // stores the conversion factor
201   int    idx;        // stores the attribute label index
202   while( getline(ifs, line) )
203   {
204     if( vtksys::SystemTools::StringStartsWith(
205         line.c_str(), "DataLabel" ) )
206     {
207       this->ParseLabel( line, idx, label );
208       this->label2idx[ label ] = idx;
209     }
210     else if( vtksys::SystemTools::StringStartsWith(
211              line.c_str(), "#DataCGSConversionFactor" ) )
212     {
213       this->ParseCFactor( line, idx, cf );
214       this->conversionFactors[ idx ] = cf;
215     }
216   }
217 
218   // STEP 3: Close parameters file
219   ifs.close();
220 }
221 
222 //-----------------------------------------------------------------------------
SetFileName(const char * fileName)223 void vtkAMREnzoReader::SetFileName( const char* fileName )
224 {
225   assert("pre: Internal Enzo AMR Reader is nullptr" && (this->Internal != nullptr ));
226 
227   if( fileName && strcmp( fileName, "" ) &&
228     ( (this->FileName==nullptr) || (strcmp(fileName,this->FileName ) ) ) )
229   {
230     std::string  tempName( fileName );
231     std::string  bExtName( ".boundary" );
232     std::string  hExtName( ".hierarchy" );
233 
234     if( tempName.length() > hExtName.length() &&
235         tempName.substr(tempName.length()-hExtName.length() )== hExtName )
236     {
237       this->Internal->MajorFileName =
238           tempName.substr( 0, tempName.length() - hExtName.length() );
239       this->Internal->HierarchyFileName = tempName;
240       this->Internal->BoundaryFileName  = this->Internal->MajorFileName+bExtName;
241     }
242     else if( tempName.length() > bExtName.length() &&
243              tempName.substr( tempName.length() - bExtName.length() )==bExtName )
244     {
245       this->Internal->MajorFileName =
246          tempName.substr( 0, tempName.length() - bExtName.length() );
247       this->Internal->BoundaryFileName  = tempName;
248       this->Internal->HierarchyFileName = this->Internal->MajorFileName+hExtName;
249     }
250     else
251     {
252       vtkErrorMacro( "Enzo file has invalid extension!");
253       return;
254     }
255 
256     this->IsReady = true;
257     this->Internal->DirectoryName =
258         GetEnzoDirectory(this->Internal->MajorFileName.c_str());
259   }
260 
261   if( this->IsReady )
262   {
263     this->BlockMap.clear();
264     this->Internal->Blocks.clear();
265     this->Internal->NumberOfBlocks = 0;
266     this->LoadedMetaData = false;
267 
268     if ( this->FileName != nullptr)
269     {
270     delete [] this->FileName;
271     this->FileName = nullptr;
272     this->Internal->SetFileName( nullptr );
273     }
274     this->FileName = new char[  strlen( fileName ) + 1  ];
275     strcpy( this->FileName, fileName );
276     this->FileName[ strlen( fileName ) ] = '\0';
277     this->Internal->SetFileName( this->FileName );
278     this->ParseConversionFactors( );
279 
280     this->Internal->ReadMetaData();
281     this->SetUpDataArraySelections();
282     this->InitializeArraySelections();
283   }
284 
285 
286   this->Modified();
287 }
288 
289 //-----------------------------------------------------------------------------
ReadMetaData()290 void vtkAMREnzoReader::ReadMetaData()
291 {
292   assert( "pre: Internal Enzo Reader is nullptr" && (this->Internal != nullptr) );
293 
294   if( !this->IsReady )
295   {
296     return;
297   }
298 
299   this->Internal->ReadMetaData();
300 }
301 
302 
303 //-----------------------------------------------------------------------------
GetBlockLevel(const int blockIdx)304 int vtkAMREnzoReader::GetBlockLevel( const int blockIdx )
305 {
306   assert( "pre: Internal Enzo Reader is nullptr" && (this->Internal != nullptr) );
307 
308   if( !this->IsReady )
309   {
310     return( -1 );
311   }
312 
313   this->Internal->ReadMetaData();
314 
315   if( blockIdx < 0 || blockIdx >= this->Internal->NumberOfBlocks )
316   {
317     vtkErrorMacro( "Block Index (" << blockIdx << ") is out-of-bounds!" );
318     return( -1 );
319   }
320   return( this->Internal->Blocks[ blockIdx+1 ].Level );
321 }
322 
323 //-----------------------------------------------------------------------------
GetNumberOfBlocks()324 int vtkAMREnzoReader::GetNumberOfBlocks()
325 {
326   assert( "pre: Internal Enzo Reader is nullptr" && (this->Internal != nullptr) );
327   if( !this->IsReady )
328   {
329     return 0;
330   }
331 
332   this->Internal->ReadMetaData();
333   return( this->Internal->NumberOfBlocks );
334 }
335 
336 //-----------------------------------------------------------------------------
GetNumberOfLevels()337 int vtkAMREnzoReader::GetNumberOfLevels()
338 {
339   assert( "pre: Internal Enzo Reader is nullptr" && (this->Internal != nullptr) );
340   if( !this->IsReady )
341   {
342     return 0;
343   }
344 
345   this->Internal->ReadMetaData();
346   return( this->Internal->NumberOfLevels );
347 }
348 
349 //-----------------------------------------------------------------------------
FillMetaData()350 int vtkAMREnzoReader::FillMetaData( )
351 {
352   assert( "pre: Internal Enzo Reader is nullptr" && (this->Internal != nullptr) );
353   assert( "pre: metadata object is nullptr" && (this->Metadata != nullptr) );
354   if( !this->IsReady )
355   {
356     return 0;
357   }
358 
359   this->Internal->ReadMetaData();
360 
361   double origin[3];
362   std::vector<int> blocksPerLevel;
363   this->ComputeStats(this->Internal, blocksPerLevel, origin);
364 
365   this->Metadata->Initialize( static_cast<int>(blocksPerLevel.size()), &blocksPerLevel[0]);
366   this->Metadata->SetGridDescription(VTK_XYZ_GRID);
367   this->Metadata->SetOrigin(origin);
368 
369   std::vector< int > b2level( this->Internal->NumberOfLevels+1, 0 );
370   for( int block=0; block < this->Internal->NumberOfBlocks; ++block )
371   {
372     vtkEnzoReaderBlock &theBlock = this->Internal->Blocks[ block+1 ];
373     int level                    = theBlock.Level;
374     int internalIdx              = block;
375     int id                       = b2level[ level ];
376 
377     //compute spacing
378     double spacing[3];
379     for(int d=0; d<3; ++d)
380     {
381       spacing[d] = (theBlock.BlockNodeDimensions[d] > 1)?
382         (theBlock.MaxBounds[d]-theBlock.MinBounds[d])/(theBlock.BlockNodeDimensions[d]-1.0):1.0;
383     }
384     //compute AMRBox
385     vtkAMRBox box(theBlock.MinBounds, theBlock.BlockNodeDimensions, spacing, origin, VTK_XYZ_GRID);
386 
387     //set meta data
388     this->Metadata->SetSpacing(level,spacing);
389     this->Metadata->SetAMRBox(level, id, box);
390     this->Metadata->SetAMRBlockSourceIndex(level,id, internalIdx);
391     b2level[ level ]++;
392   }
393   this->Metadata->GenerateParentChildInformation();
394   this->Metadata->GetInformation()->Set(vtkDataObject::DATA_TIME_STEP(),this->Internal->DataTime);
395   return( 1 );
396 }
397 
398 //-----------------------------------------------------------------------------
GetAMRGrid(const int blockIdx)399 vtkUniformGrid* vtkAMREnzoReader::GetAMRGrid( const int blockIdx )
400 {
401   assert( "pre: Internal Enzo Reader is nullptr" && (this->Internal != nullptr) );
402 
403   if( !this->IsReady )
404   {
405     return nullptr;
406   }
407 
408   this->Internal->ReadMetaData();
409 
410   // this->Internal->Blocks includes a pseudo block --- the root as block #0
411   vtkEnzoReaderBlock &theBlock = this->Internal->Blocks[ blockIdx+1 ];
412   double blockMin[3];
413   double blockMax[3];
414   double spacings[3];
415 
416   for( int i=0; i < 3; ++i )
417   {
418     blockMin[ i ] = theBlock.MinBounds[ i ];
419     blockMax[ i ] = theBlock.MaxBounds[ i ];
420     spacings[ i ] = (theBlock.BlockNodeDimensions[i] > 1)?
421         (blockMax[i]-blockMin[i])/(theBlock.BlockNodeDimensions[i]-1.0) : 1.0;
422   }
423 
424   vtkUniformGrid *ug = vtkUniformGrid::New();
425   ug->SetDimensions( theBlock.BlockNodeDimensions );
426   ug->SetOrigin( blockMin[0], blockMin[1], blockMin[2] );
427   ug->SetSpacing( spacings[0], spacings[1], spacings[2] );
428   return( ug );
429 }
430 
431 //-----------------------------------------------------------------------------
GetAMRGridData(const int blockIdx,vtkUniformGrid * block,const char * field)432 void vtkAMREnzoReader::GetAMRGridData(
433     const int blockIdx, vtkUniformGrid *block, const char *field)
434 {
435   assert( "pre: AMR block is nullptr" && (block != nullptr));
436 
437   this->Internal->GetBlockAttribute( field, blockIdx, block );
438   if( this->ConvertToCGS == 1 )
439   {
440     double conversionFactor = this->GetConversionFactor(field);
441     if( conversionFactor != 1.0 )
442     {
443       vtkDataArray *data = block->GetCellData()->GetArray( field );
444       assert( "pre: data array is nullptr!" && (data != nullptr) );
445 
446       vtkIdType numTuples = data->GetNumberOfTuples();
447       for( vtkIdType t=0; t < numTuples; ++t )
448       {
449         int numComp = data->GetNumberOfComponents();
450         for( int c=0; c < numComp; ++c )
451         {
452          double f = data->GetComponent( t, c );
453          data->SetComponent( t, c, f*conversionFactor );
454         } // END for all components
455       } // END for all tuples
456     } // END if the conversion factor is not 1.0
457   } // END if conversion to CGS units is requested
458 }
459 
460 
461 //-----------------------------------------------------------------------------
SetUpDataArraySelections()462 void vtkAMREnzoReader::SetUpDataArraySelections()
463 {
464   assert( "pre: Internal Enzo Reader is nullptr" && (this->Internal != nullptr) );
465   this->Internal->ReadMetaData();
466   this->Internal->GetAttributeNames();
467 
468   int numAttrs = static_cast< int >(this->Internal->BlockAttributeNames.size());
469   for( int i=0; i < numAttrs; i++ )
470   {
471     this->CellDataArraySelection->AddArray(
472         this->Internal->BlockAttributeNames[i].c_str() );
473   } // END for all attributes
474 
475 }
476