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