1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkAMRFlashParticlesReader.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 #include "vtkAMRFlashParticlesReader.h"
16 #include "vtkObjectFactory.h"
17 #include "vtkPolyData.h"
18 #include "vtkDataArraySelection.h"
19 #include "vtkIdList.h"
20 #include "vtkCellArray.h"
21 #include "vtkDoubleArray.h"
22 #include "vtkIntArray.h"
23 #include "vtkPointData.h"
24
25 #include "vtkAMRFlashReaderInternal.h"
26
27 #define H5_USE_16_API
28 #include "vtk_hdf5.h" // for the HDF data loading engine
29
30 #include <vector>
31 #include <cassert>
32
33 #define FLASH_READER_MAX_DIMS 3
34 #define FLASH_READER_LEAF_BLOCK 1
35 #define FLASH_READER_FLASH3_FFV8 8
36 #define FLASH_READER_FLASH3_FFV9 9
37
38 //------------------------------------------------------------------------------
39 // Description:
40 // Helper function that reads the particle coordinates
41 // NOTE: it is assumed that H5DOpen has been called on the
42 // internal file index this->FileIndex.
GetParticleCoordinates(hid_t & dataIdx,std::vector<double> & xcoords,std::vector<double> & ycoords,std::vector<double> & zcoords,vtkFlashReaderInternal * iReader,int NumParticles)43 static void GetParticleCoordinates( hid_t &dataIdx,
44 std::vector< double > &xcoords, std::vector< double > &ycoords,
45 std::vector< double > &zcoords,
46 vtkFlashReaderInternal *iReader,
47 int NumParticles )
48 {
49
50 assert( "pre: internal reader should not be nullptr" && (iReader != nullptr) );
51
52 hid_t theTypes[3];
53 theTypes[0] = theTypes[1] = theTypes[2] = H5I_UNINIT;
54 xcoords.resize( NumParticles );
55 ycoords.resize( NumParticles );
56 zcoords.resize( NumParticles );
57
58 if( iReader->FileFormatVersion < FLASH_READER_FLASH3_FFV8 )
59 {
60 theTypes[0] = H5Tcreate( H5T_COMPOUND, sizeof(double) );
61 theTypes[1] = H5Tcreate( H5T_COMPOUND, sizeof(double) );
62 theTypes[2] = H5Tcreate( H5T_COMPOUND, sizeof(double) );
63 H5Tinsert( theTypes[0], "particle_x", 0, H5T_NATIVE_DOUBLE );
64 H5Tinsert( theTypes[1], "particle_y", 0, H5T_NATIVE_DOUBLE );
65 H5Tinsert( theTypes[2], "particle_z", 0, H5T_NATIVE_DOUBLE );
66 }
67
68 // Read the coordinates from the file
69 switch( iReader->NumberOfDimensions )
70 {
71 case 1:
72 if( iReader->FileFormatVersion < FLASH_READER_FLASH3_FFV8 )
73 {
74 H5Dread(dataIdx,theTypes[0],H5S_ALL,H5S_ALL,H5P_DEFAULT,&xcoords[0]);
75 }
76 else
77 {
78 iReader->ReadParticlesComponent(dataIdx,"Particles/posx",&xcoords[0]);
79 }
80 break;
81 case 2:
82 if( iReader->FileFormatVersion < FLASH_READER_FLASH3_FFV8 )
83 {
84 H5Dread(dataIdx,theTypes[0],H5S_ALL,H5S_ALL,H5P_DEFAULT,&xcoords[0]);
85 H5Dread(dataIdx,theTypes[1],H5S_ALL,H5S_ALL,H5P_DEFAULT,&ycoords[0]);
86 }
87 else
88 {
89 iReader->ReadParticlesComponent(dataIdx,"Particles/posx",&xcoords[0]);
90 iReader->ReadParticlesComponent(dataIdx,"Particles/posy",&ycoords[0]);
91 }
92 break;
93 case 3:
94 if( iReader->FileFormatVersion < FLASH_READER_FLASH3_FFV8 )
95 {
96 H5Dread(dataIdx,theTypes[0],H5S_ALL,H5S_ALL,H5P_DEFAULT,&xcoords[0]);
97 H5Dread(dataIdx,theTypes[1],H5S_ALL,H5S_ALL,H5P_DEFAULT,&ycoords[0]);
98 H5Dread(dataIdx,theTypes[2],H5S_ALL,H5S_ALL,H5P_DEFAULT,&zcoords[0]);
99 }
100 else
101 {
102 iReader->ReadParticlesComponent(dataIdx,"Particles/posx",&xcoords[0]);
103 iReader->ReadParticlesComponent(dataIdx,"Particles/posy",&ycoords[0]);
104 iReader->ReadParticlesComponent(dataIdx,"Particles/posz",&zcoords[0]);
105 }
106 break;
107 default:
108 std::cerr << "ERROR: Undefined dimension!\n" << std::endl;
109 std::cerr.flush();
110 return;
111 }
112
113 }
114
115
116 //------------------------------------------------------------------------------
117
118
119 //------------------------------------------------------------------------------
120
121 vtkStandardNewMacro( vtkAMRFlashParticlesReader );
122
vtkAMRFlashParticlesReader()123 vtkAMRFlashParticlesReader::vtkAMRFlashParticlesReader()
124 {
125 this->Internal = new vtkFlashReaderInternal();
126 this->Initialized = false;
127 this->Initialize();
128 }
129
130 //------------------------------------------------------------------------------
~vtkAMRFlashParticlesReader()131 vtkAMRFlashParticlesReader::~vtkAMRFlashParticlesReader()
132 {
133 delete this->Internal;
134 }
135
136 //------------------------------------------------------------------------------
PrintSelf(std::ostream & os,vtkIndent indent)137 void vtkAMRFlashParticlesReader::PrintSelf( std::ostream &os, vtkIndent indent )
138 {
139 this->Superclass::PrintSelf( os, indent );
140 }
141
142 //------------------------------------------------------------------------------
ReadMetaData()143 void vtkAMRFlashParticlesReader::ReadMetaData()
144 {
145 if( this->Initialized )
146 {
147 return;
148 }
149
150 this->Internal->SetFileName( this->FileName );
151 this->Internal->ReadMetaData();
152
153 // In some cases, the FLASH file format may have no blocks but store
154 // just particles in a single block. However, the AMRBaseParticles reader
155 // would expect that in this case, the number of blocks is set to 1. The
156 // following lines of code provide a simple workaround for that.
157 this->NumberOfBlocks = this->Internal->NumberOfBlocks;
158 if( this->NumberOfBlocks == 0 && this->Internal->NumberOfParticles > 0)
159 {
160 this->NumberOfBlocks=1;
161 }
162 this->Initialized = true;
163 this->SetupParticleDataSelections();
164 }
165
166 //------------------------------------------------------------------------------
GetTotalNumberOfParticles()167 int vtkAMRFlashParticlesReader::GetTotalNumberOfParticles()
168 {
169 assert( "Internal reader is null" && (this->Internal!=nullptr) );
170 return( this->Internal->NumberOfParticles );
171 }
172
173 //------------------------------------------------------------------------------
GetParticles(const char * file,const int vtkNotUsed (blkidx))174 vtkPolyData* vtkAMRFlashParticlesReader::GetParticles(
175 const char *file, const int vtkNotUsed(blkidx) )
176 {
177 hid_t dataIdx = H5Dopen( this->Internal->FileIndex, file );
178 if( dataIdx < 0 )
179 {
180 vtkErrorMacro( "Could not open particles file!" );
181 return nullptr;
182 }
183
184 vtkPolyData *particles = vtkPolyData::New();
185 vtkPoints *positions = vtkPoints::New();
186 positions->SetDataTypeToDouble();
187 positions->SetNumberOfPoints( this->Internal->NumberOfParticles );
188
189 vtkPointData *pdata = particles->GetPointData();
190 assert( "pre: PointData is nullptr" && (pdata != nullptr) );
191
192 // Load the particle position arrays by name
193 std::vector< double > xcoords;
194 std::vector< double > ycoords;
195 std::vector< double > zcoords;
196 GetParticleCoordinates(
197 dataIdx, xcoords, ycoords, zcoords,
198 this->Internal, this->Internal->NumberOfParticles );
199
200 // Sub-sample particles
201 int TotalNumberOfParticles = static_cast<int>(xcoords.size());
202 vtkIdList *ids = vtkIdList::New();
203 ids->SetNumberOfIds( TotalNumberOfParticles );
204
205 vtkIdType NumberOfParticlesLoaded = 0;
206 for( int i=0; i < TotalNumberOfParticles; ++i )
207 {
208 if( i%this->Frequency == 0 )
209 {
210 if( this->CheckLocation(xcoords[i],ycoords[i],zcoords[i] ) )
211 {
212 int pidx = NumberOfParticlesLoaded;
213 ids->InsertId( pidx, i );
214 positions->SetPoint( pidx, xcoords[i], ycoords[i], zcoords[i] );
215 ++NumberOfParticlesLoaded;
216 } // END if within requested region
217 } // END if within requested interval
218 } // END for all particles
219
220 xcoords.clear(); ycoords.clear(); zcoords.clear();
221
222 ids->SetNumberOfIds( NumberOfParticlesLoaded );
223 ids->Squeeze();
224
225 positions->SetNumberOfPoints( NumberOfParticlesLoaded );
226 positions->Squeeze();
227
228 particles->SetPoints( positions );
229 positions->Squeeze( );
230
231 // Create CellArray consisting of a single polyvertex
232 vtkCellArray *polyVertex = vtkCellArray::New();
233 polyVertex ->InsertNextCell( NumberOfParticlesLoaded );
234 for( vtkIdType idx=0; idx < NumberOfParticlesLoaded; ++idx )
235 {
236 polyVertex->InsertCellPoint( idx );
237 }
238 particles->SetVerts( polyVertex );
239 polyVertex->Delete();
240
241 // Load particle data arrays
242 int numArrays = this->ParticleDataArraySelection->GetNumberOfArrays();
243 for( int i=0; i < numArrays; ++i )
244 {
245 const char *name = this->ParticleDataArraySelection->GetArrayName( i );
246 if( this->ParticleDataArraySelection->ArrayIsEnabled( name ) )
247 {
248 int attrIdx = this->Internal->ParticleAttributeNamesToIds[ name ];
249 hid_t attrType = this->Internal->ParticleAttributeTypes[ attrIdx ];
250
251 if( attrType == H5T_NATIVE_DOUBLE )
252 {
253 double *data = new double[ this->Internal->NumberOfParticles ];
254 assert( data != nullptr );
255
256 if( this->Internal->FileFormatVersion < FLASH_READER_FLASH3_FFV8 )
257 {
258 hid_t dataType = H5Tcreate( H5T_COMPOUND, sizeof(double) );
259 H5Tinsert( dataType, name, 0, H5T_NATIVE_DOUBLE );
260 H5Dread(dataIdx, dataType, H5S_ALL, H5S_ALL, H5P_DEFAULT,data);
261 H5Tclose( dataType );
262 }
263 else
264 {
265 this->Internal->ReadParticlesComponent( dataIdx, name, data );
266 }
267
268 vtkDataArray *array = vtkDoubleArray::New();
269 array->SetName( name );
270 array->SetNumberOfTuples( ids->GetNumberOfIds() );
271 array->SetNumberOfComponents( 1 );
272
273 vtkIdType numIds = ids->GetNumberOfIds();
274 for( vtkIdType pidx=0; pidx < numIds; ++pidx )
275 {
276 vtkIdType particleIdx = ids->GetId( pidx );
277 array->SetComponent( pidx, 0, data[ particleIdx ] );
278 } // END for all ids of loaded particles
279 pdata->AddArray( array );
280 delete [] data;
281 }
282 else if( attrType == H5T_NATIVE_INT )
283 {
284 hid_t dataType = H5Tcreate( H5T_COMPOUND, sizeof(int) );
285 H5Tinsert( dataType, name, 0, H5T_NATIVE_INT );
286
287 int *data = new int[ this->Internal->NumberOfParticles ];
288 assert( data != nullptr );
289 H5Dread( dataIdx, dataType, H5S_ALL, H5S_ALL, H5P_DEFAULT, data );
290
291 vtkDataArray *array = vtkIntArray::New();
292 array->SetName( name );
293 array->SetNumberOfTuples( ids->GetNumberOfIds() );
294 array->SetNumberOfComponents( 1 );
295
296 vtkIdType numIds = ids->GetNumberOfIds( );
297 for( vtkIdType pidx=0; pidx < numIds; ++pidx )
298 {
299 vtkIdType particleIdx = ids->GetId( pidx );
300 array->SetComponent( pidx, 0, data[ particleIdx ] );
301 } // END for all ids of loaded particles
302 pdata->AddArray( array );
303 delete [] data;
304 }
305 else
306 {
307 vtkErrorMacro( "Unsupported array type in HDF5 file!" );
308 return nullptr;
309 }
310 } // END if the array is supposed to be loaded
311 } // END for all arrays
312
313 H5Dclose(dataIdx);
314
315 return( particles );
316 }
317
318 //------------------------------------------------------------------------------
ReadParticles(const int blkidx)319 vtkPolyData* vtkAMRFlashParticlesReader::ReadParticles( const int blkidx )
320 {
321 assert( "pre: Internal reader is nullptr" && (this->Internal != nullptr) );
322 assert( "pre: Not initialized " && (this->Initialized) );
323
324 int NumberOfParticles = this->Internal->NumberOfParticles;
325 if( NumberOfParticles <= 0 )
326 {
327 vtkPolyData *emptyParticles = vtkPolyData::New();
328 assert( "Cannot create particle dataset" && (emptyParticles != nullptr) );
329 return( emptyParticles );
330 }
331
332 vtkPolyData* particles = this->GetParticles(
333 this->Internal->ParticleName.c_str(), blkidx );
334 assert( "partciles should not be nullptr " && (particles != nullptr) );
335
336 return( particles );
337 }
338
339 //------------------------------------------------------------------------------
SetupParticleDataSelections()340 void vtkAMRFlashParticlesReader::SetupParticleDataSelections()
341 {
342 assert( "pre: Internal reader is nullptr" && (this->Internal != nullptr) );
343
344 unsigned int N =
345 static_cast<unsigned int>(this->Internal->ParticleAttributeNames.size());
346 for( unsigned int i=0; i < N; ++i )
347 {
348 this->ParticleDataArraySelection->AddArray(
349 this->Internal->ParticleAttributeNames[ i ].c_str( ) );
350 } // END for all particles attributes
351
352 this->InitializeParticleDataSelections();
353 }
354