1 /*=========================================================================
2
3 Program: ParaView
4 Module: vtkXMLUniformGridAMRReader.cxx
5
6 Copyright (c) Kitware, Inc.
7 All rights reserved.
8 See Copyright.txt or http://www.paraview.org/HTML/Copyright.html 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 "vtkXMLUniformGridAMRReader.h"
16
17 #include "vtkAMRBox.h"
18 #include "vtkAMRInformation.h"
19 #include "vtkAMRUtilities.h"
20 #include "vtkCompositeDataPipeline.h"
21 #include "vtkDataObjectTypes.h"
22 #include "vtkInformation.h"
23 #include "vtkInformationVector.h"
24 #include "vtkNonOverlappingAMR.h"
25 #include "vtkObjectFactory.h"
26 #include "vtkOverlappingAMR.h"
27 #include "vtkSmartPointer.h"
28 #include "vtkUniformGrid.h"
29 #include "vtkXMLDataElement.h"
30
31 #include <cassert>
32 #include <vector>
33
34 namespace
35 {
36 // Data type used to store a 3-tuple of doubles.
37 template <class T, int N> class vtkTuple
38 {
39 public:
40 T Data[N];
vtkTuple()41 vtkTuple()
42 {
43 for (int cc=0; cc < N; cc++)
44 {
45 this->Data[cc] = 0;
46 }
47 }
operator T*()48 operator T* ()
49 {
50 return this->Data;
51 }
52 };
53
54 typedef vtkTuple<double, 3> vtkSpacingType;
55
56 // Helper routine to parse the XML to collect information about the AMR.
vtkReadMetaData(vtkXMLDataElement * ePrimary,std::vector<unsigned int> & blocks_per_level,std::vector<vtkSpacingType> & level_spacing,std::vector<std::vector<vtkAMRBox>> & amr_boxes)57 bool vtkReadMetaData(
58 vtkXMLDataElement* ePrimary,
59 std::vector<unsigned int> &blocks_per_level,
60 std::vector<vtkSpacingType> &level_spacing,
61 std::vector<std::vector<vtkAMRBox> > &amr_boxes)
62 {
63 unsigned int numElems = ePrimary->GetNumberOfNestedElements();
64 for (unsigned int cc=0; cc < numElems; cc++)
65 {
66 vtkXMLDataElement* blockXML = ePrimary->GetNestedElement(cc);
67 if (!blockXML || !blockXML->GetName() ||
68 strcmp(blockXML->GetName(), "Block") != 0)
69 {
70 continue;
71 }
72
73 int level = 0;
74 if (!blockXML->GetScalarAttribute("level", level))
75 {
76 vtkGenericWarningMacro("Missing 'level' on 'Block' element in XML. Skipping");
77 continue;
78 }
79 if (level < 0)
80 {
81 // sanity check.
82 continue;
83 }
84 if (blocks_per_level.size() <= static_cast<size_t>(level))
85 {
86 blocks_per_level.resize(level+1, 0);
87 level_spacing.resize(level+1);
88 amr_boxes.resize(level+1);
89 }
90
91 double spacing[3];
92 if (blockXML->GetVectorAttribute("spacing", 3, spacing))
93 {
94 level_spacing[level][0] = spacing[0];
95 level_spacing[level][1] = spacing[1];
96 level_spacing[level][2] = spacing[2];
97 }
98
99 // now read the <DataSet/> elements for boxes and counting the number of
100 // nodes per level.
101 int numDatasets = blockXML->GetNumberOfNestedElements();
102 for (int kk=0; kk < numDatasets; kk++)
103 {
104 vtkXMLDataElement* datasetXML = blockXML->GetNestedElement(kk);
105 if (!datasetXML || !datasetXML->GetName() ||
106 strcmp(datasetXML->GetName(), "DataSet") != 0)
107 {
108 continue;
109 }
110
111 int index = 0;
112 if (!datasetXML->GetScalarAttribute("index", index))
113 {
114 vtkGenericWarningMacro("Missing 'index' on 'DataSet' element in XML. Skipping");
115 continue;
116 }
117 if (index >= static_cast<int>(blocks_per_level[level]))
118 {
119 blocks_per_level[level] = index+1;
120 }
121 if (static_cast<size_t>(index) >= amr_boxes[level].size())
122 {
123 amr_boxes[level].resize(index + 1);
124 }
125 int box[6];
126 // note: amr-box is not provided for non-overlapping AMR.
127 if (!datasetXML->GetVectorAttribute("amr_box", 6, box))
128 {
129 continue;
130 }
131 // box is xLo, xHi, yLo, yHi, zLo, zHi.
132 amr_boxes[level][index] = vtkAMRBox(box);
133 }
134 }
135 return true;
136 }
137
vtkReadMetaData(vtkXMLDataElement * ePrimary,std::vector<unsigned int> & blocks_per_level)138 bool vtkReadMetaData(vtkXMLDataElement* ePrimary,
139 std::vector<unsigned int> &blocks_per_level)
140 {
141 std::vector<vtkSpacingType> spacings;
142 std::vector<std::vector<vtkAMRBox> > amr_boxes;
143 return vtkReadMetaData(ePrimary, blocks_per_level, spacings, amr_boxes);
144 }
145 }
146
147 vtkStandardNewMacro(vtkXMLUniformGridAMRReader);
148 //----------------------------------------------------------------------------
vtkXMLUniformGridAMRReader()149 vtkXMLUniformGridAMRReader::vtkXMLUniformGridAMRReader()
150 {
151 this->OutputDataType = NULL;
152 this->MaximumLevelsToReadByDefault = 1;
153 }
154
155 //----------------------------------------------------------------------------
~vtkXMLUniformGridAMRReader()156 vtkXMLUniformGridAMRReader::~vtkXMLUniformGridAMRReader()
157 {
158 this->SetOutputDataType(NULL);
159 }
160
161 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)162 void vtkXMLUniformGridAMRReader::PrintSelf(ostream& os, vtkIndent indent)
163 {
164 this->Superclass::PrintSelf(os, indent);
165 os << indent << "MaximumLevelsToReadByDefault: " <<
166 this->MaximumLevelsToReadByDefault << endl;
167 }
168
169 //----------------------------------------------------------------------------
GetDataSetName()170 const char* vtkXMLUniformGridAMRReader::GetDataSetName()
171 {
172 if (!this->OutputDataType)
173 {
174 vtkWarningMacro("We haven't determine a valid output type yet.");
175 return "vtkUniformGridAMR";
176 }
177
178 return this->OutputDataType;
179 }
180
181 //----------------------------------------------------------------------------
CanReadFileWithDataType(const char * dsname)182 int vtkXMLUniformGridAMRReader::CanReadFileWithDataType(const char* dsname)
183 {
184 return (dsname && (
185 strcmp(dsname, "vtkOverlappingAMR") == 0 ||
186 strcmp(dsname, "vtkNonOverlappingAMR") == 0 ||
187 strcmp(dsname, "vtkHierarchicalBoxDataSet") == 0))? 1 : 0;
188 }
189
190 //----------------------------------------------------------------------------
ReadVTKFile(vtkXMLDataElement * eVTKFile)191 int vtkXMLUniformGridAMRReader::ReadVTKFile(vtkXMLDataElement* eVTKFile)
192 {
193 // this->Superclass::ReadVTKFile(..) calls this->GetDataSetName().
194 // GetDataSetName() needs to know the data type we're reading and hence it's
195 // essential to read the "type" before calling the superclass' method.
196
197 // NOTE: eVTKFile maybe totally invalid, so proceed with caution.
198 const char* type = eVTKFile->GetAttribute("type");
199 if (type == NULL ||
200 (strcmp(type, "vtkHierarchicalBoxDataSet") != 0 &&
201 strcmp(type, "vtkOverlappingAMR") != 0 &&
202 strcmp(type, "vtkNonOverlappingAMR") != 0))
203 {
204 vtkErrorMacro(
205 "Invalid 'type' specified in the file: " << (type? type : "(none)"));
206 return 0;
207 }
208
209 this->SetOutputDataType(type);
210 return this->Superclass::ReadVTKFile(eVTKFile);
211 }
212
213 //----------------------------------------------------------------------------
ReadPrimaryElement(vtkXMLDataElement * ePrimary)214 int vtkXMLUniformGridAMRReader::ReadPrimaryElement(vtkXMLDataElement* ePrimary)
215 {
216 if (!this->Superclass::ReadPrimaryElement(ePrimary))
217 {
218 return 0;
219 }
220
221 if (this->GetFileMajorVersion() != 1 ||
222 this->GetFileMinorVersion() != 1)
223 {
224 // for old files, we don't support providing meta-data for
225 // RequestInformation() pass.
226 this->Metadata = NULL;
227 return 1;
228 }
229
230 if (strcmp(ePrimary->GetName(), "vtkNonOverlappingAMR") == 0)
231 {
232 // this is a non-overlapping AMR. We don't have meta-data for
233 // non-overlapping AMRs.
234 this->Metadata = NULL;
235 return 1;
236 }
237
238 // Read the xml to build the metadata.
239 this->Metadata = vtkSmartPointer<vtkOverlappingAMR>::New();
240
241 // iterate over the XML to fill up the AMRInformation with meta-data.
242 std::vector<unsigned int> blocks_per_level;
243 std::vector<vtkSpacingType> level_spacing;
244 std::vector<std::vector<vtkAMRBox> > amr_boxes;
245 vtkReadMetaData(ePrimary, blocks_per_level, level_spacing, amr_boxes);
246
247 if (blocks_per_level.size() > 0)
248 {
249 // initialize vtkAMRInformation.
250 this->Metadata->Initialize(
251 static_cast<int>(blocks_per_level.size()),
252 reinterpret_cast<int*>(&blocks_per_level[0]));
253
254 double origin[3] = {0, 0, 0};
255 if (!ePrimary->GetVectorAttribute("origin", 3, origin))
256 {
257 vtkWarningMacro("Missing 'origin'. Using (0, 0, 0).");
258 }
259 this->Metadata->SetOrigin(origin);
260
261 const char* grid_description = ePrimary->GetAttribute("grid_description");
262 int iGridDescription = VTK_XYZ_GRID;
263 if (grid_description && strcmp(grid_description, "XY") == 0)
264 {
265 iGridDescription = VTK_XY_PLANE;
266 }
267 else if (grid_description && strcmp(grid_description, "YZ") == 0)
268 {
269 iGridDescription = VTK_YZ_PLANE;
270 }
271 else if (grid_description && strcmp(grid_description, "XZ") == 0)
272 {
273 iGridDescription = VTK_XZ_PLANE;
274 }
275 this->Metadata->SetGridDescription(iGridDescription);
276
277 // pass refinement ratios.
278 for (size_t cc=0; cc < level_spacing.size(); cc++)
279 {
280 this->Metadata->GetAMRInfo()->SetSpacing(
281 static_cast<unsigned int>(cc), level_spacing[cc]);
282 }
283 // pass amr boxes.
284 for (size_t level=0; level < amr_boxes.size(); level++)
285 {
286 for (size_t index=0; index < amr_boxes[level].size(); index++)
287 {
288 const vtkAMRBox& box = amr_boxes[level][index];
289 if (!box.Empty())
290 {
291 this->Metadata->GetAMRInfo()->SetAMRBox(
292 static_cast<unsigned int>(level),
293 static_cast<unsigned int>(index), box);
294 }
295 }
296 }
297 }
298
299 this->Metadata->GenerateParentChildInformation();
300 return 1;
301 }
302
303 //----------------------------------------------------------------------------
RequestDataObject(vtkInformation * vtkNotUsed (request),vtkInformationVector ** vtkNotUsed (inputVector),vtkInformationVector * outputVector)304 int vtkXMLUniformGridAMRReader::RequestDataObject(
305 vtkInformation *vtkNotUsed(request),
306 vtkInformationVector **vtkNotUsed(inputVector),
307 vtkInformationVector *outputVector)
308 {
309 if (!this->ReadXMLInformation())
310 {
311 return 0;
312 }
313
314 vtkDataObject* output = vtkDataObject::GetData(outputVector, 0);
315 if (!output || !output->IsA(this->OutputDataType))
316 {
317 vtkDataObject* newDO = vtkDataObjectTypes::NewDataObject(this->OutputDataType);
318 if (newDO)
319 {
320 outputVector->GetInformationObject(0)->Set(
321 vtkDataObject::DATA_OBJECT(), newDO);
322 newDO->FastDelete();
323 return 1;
324 }
325 }
326
327 return 1;
328 }
329
330 //----------------------------------------------------------------------------
RequestInformation(vtkInformation * request,vtkInformationVector ** inputVector,vtkInformationVector * outputVector)331 int vtkXMLUniformGridAMRReader::RequestInformation(vtkInformation *request,
332 vtkInformationVector **inputVector, vtkInformationVector *outputVector)
333 {
334 if (!this->Superclass::RequestInformation(request, inputVector, outputVector))
335 {
336 return 0;
337 }
338
339 if (this->Metadata)
340 {
341 outputVector->GetInformationObject(0)->Set(
342 vtkCompositeDataPipeline::COMPOSITE_DATA_META_DATA(),
343 this->Metadata);
344 }
345 else
346 {
347 outputVector->GetInformationObject(0)->Remove(
348 vtkCompositeDataPipeline::COMPOSITE_DATA_META_DATA());
349 }
350 return 1;
351 }
352
353 //----------------------------------------------------------------------------
ReadComposite(vtkXMLDataElement * element,vtkCompositeDataSet * composite,const char * filePath,unsigned int & dataSetIndex)354 void vtkXMLUniformGridAMRReader::ReadComposite(vtkXMLDataElement* element,
355 vtkCompositeDataSet* composite, const char* filePath,
356 unsigned int &dataSetIndex)
357 {
358 vtkUniformGridAMR* amr = vtkUniformGridAMR::SafeDownCast(composite);
359 if (!amr)
360 {
361 vtkErrorMacro("Dataset must be a vtkUniformGridAMR.");
362 return;
363 }
364
365 if (this->GetFileMajorVersion() != 1 ||
366 this->GetFileMinorVersion() != 1)
367 {
368 vtkErrorMacro(
369 "Version not supported. Use vtkXMLHierarchicalBoxDataReader instead.");
370 return;
371 }
372
373 vtkInformation* outinfo = this->GetCurrentOutputInformation();
374 bool has_block_requests =
375 outinfo->Has(vtkCompositeDataPipeline::LOAD_REQUESTED_BLOCKS()) != 0;
376
377 vtkOverlappingAMR* oamr = vtkOverlappingAMR::SafeDownCast(amr);
378 vtkNonOverlappingAMR* noamr = vtkNonOverlappingAMR::SafeDownCast(amr);
379 assert(oamr != NULL || noamr != NULL);
380
381 if (oamr)
382 {
383 // we don;t have the parse the structure. Just pass the inform from
384 // this->Metadata.
385 oamr->SetAMRInfo(this->Metadata->GetAMRInfo());
386 }
387 else if (noamr)
388 {
389 // We process the XML to collect information about the structure.
390 std::vector<unsigned int> blocks_per_level;
391 vtkReadMetaData(element, blocks_per_level);
392 noamr->Initialize(
393 static_cast<int>(blocks_per_level.size()),
394 reinterpret_cast<int*>(&blocks_per_level[0]));
395 }
396
397 // Now, simply scan the xml for dataset elements and read them as needed.
398
399 unsigned int numElems = element->GetNumberOfNestedElements();
400 for (unsigned int cc=0; cc < numElems; cc++)
401 {
402 vtkXMLDataElement* blockXML = element->GetNestedElement(cc);
403 if (!blockXML || !blockXML->GetName() ||
404 strcmp(blockXML->GetName(), "Block") != 0)
405 {
406 continue;
407 }
408
409 int level = 0;
410 if (!blockXML->GetScalarAttribute("level", level) || level < 0)
411 {
412 continue;
413 }
414
415 // now read the <DataSet/> elements for boxes and counting the number of
416 // nodes per level.
417 int numDatasets = blockXML->GetNumberOfNestedElements();
418 for (int kk=0; kk < numDatasets; kk++)
419 {
420 vtkXMLDataElement* datasetXML = blockXML->GetNestedElement(kk);
421 if (!datasetXML || !datasetXML->GetName() ||
422 strcmp(datasetXML->GetName(), "DataSet") != 0)
423 {
424 continue;
425 }
426
427 int index = 0;
428 if (!datasetXML->GetScalarAttribute("index", index) || index < 0)
429 {
430 continue;
431 }
432
433 if (this->ShouldReadDataSet(dataSetIndex))
434 {
435 // if has_block_requests==false, then we don't read any blocks greater
436 // than the MaximumLevelsToReadByDefault.
437 if (has_block_requests == false &&
438 this->MaximumLevelsToReadByDefault > 0 &&
439 static_cast<unsigned int>(level) >= this->MaximumLevelsToReadByDefault)
440 {
441 // don't actually read the data.
442 }
443 else
444 {
445 vtkSmartPointer<vtkDataSet> ds;
446 ds.TakeReference(this->ReadDataset(datasetXML, filePath));
447 if (ds && !ds->IsA("vtkUniformGrid"))
448 {
449 vtkErrorMacro("vtkUniformGridAMR can only contain vtkUniformGrids.");
450 }
451 else
452 {
453 amr->SetDataSet(
454 static_cast<unsigned int>(level), static_cast<unsigned int>(index),
455 vtkUniformGrid::SafeDownCast(ds.GetPointer()));
456 }
457 }
458 }
459 dataSetIndex++;
460 }
461 }
462
463 if( (oamr != NULL) && !has_block_requests )
464 {
465 vtkAMRUtilities::BlankCells(oamr);
466 }
467 }
468
469 //----------------------------------------------------------------------------
ReadDataset(vtkXMLDataElement * xmlElem,const char * filePath)470 vtkDataSet* vtkXMLUniformGridAMRReader::ReadDataset(
471 vtkXMLDataElement* xmlElem, const char* filePath)
472 {
473 vtkDataSet* ds = this->Superclass::ReadDataset(xmlElem, filePath);
474 if (ds && ds->IsA("vtkImageData"))
475 {
476 // Convert vtkImageData to vtkUniformGrid as needed by
477 // vtkHierarchicalBoxDataSet.
478 vtkUniformGrid* ug = vtkUniformGrid::New();
479 ug->ShallowCopy(ds);
480 ds->Delete();
481 return ug;
482 }
483 return ds;
484 }
485