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