1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    TestXMLWriteRead.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 "vtkArrayDispatch.h"
17 #include "vtkFloatArray.h"
18 #include "vtkHDFReader.h"
19 #include "vtkImageData.h"
20 #include "vtkMathUtilities.h"
21 #include "vtkNew.h"
22 #include "vtkPointData.h"
23 #include "vtkTesting.h"
24 #include "vtkUnstructuredGrid.h"
25 #include "vtkXMLImageDataReader.h"
26 #include "vtkXMLPUnstructuredGridReader.h"
27 #include "vtkXMLUnstructuredGridReader.h"
28 
29 #include <iterator>
30 #include <string>
31 
32 struct CompareVectorWorker
33 {
CompareVectorWorkerCompareVectorWorker34   CompareVectorWorker()
35     : ExitValue(EXIT_SUCCESS)
36   {
37   }
38   template <typename ArrayT, typename ExpectedArrayT>
operator ()CompareVectorWorker39   void operator()(ArrayT* array, ExpectedArrayT* expectedArray)
40   {
41     const auto range = vtk::DataArrayTupleRange(array);
42     const auto expectedRange = vtk::DataArrayTupleRange(expectedArray);
43 
44     const vtk::TupleIdType numTuples = range.size();
45     const vtk::ComponentIdType numComps = range.GetTupleSize();
46 
47     std::cout << "Compare " << array->GetName() << std::endl;
48     this->ExitValue = EXIT_SUCCESS;
49     for (vtk::TupleIdType tupleId = 0; tupleId < numTuples; ++tupleId)
50     {
51       const auto tuple = range[tupleId];
52       auto expectedTuple = expectedRange[tupleId];
53 
54       for (vtk::ComponentIdType compId = 0; compId < numComps; ++compId)
55       {
56         if (tuple[compId] != expectedTuple[compId])
57         {
58           std::cerr << "Expecting " << expectedTuple[compId] << " for tuple/component: " << tupleId
59                     << "/" << compId << " but got: " << tuple[compId] << std::endl;
60           this->ExitValue = EXIT_FAILURE;
61           break;
62         }
63       }
64     }
65   }
66   int ExitValue;
67 };
68 
CompareVectors(vtkDataArray * array,vtkDataArray * expectedArray)69 int CompareVectors(vtkDataArray* array, vtkDataArray* expectedArray)
70 {
71   using Dispatcher = vtkArrayDispatch::Dispatch2BySameValueType<vtkArrayDispatch::AllTypes>;
72 
73   // Create the functor:
74   CompareVectorWorker worker;
75 
76   if (!Dispatcher::Execute(array, expectedArray, worker))
77   {
78     // If Execute(...) fails, the arrays don't match the constraints.
79     // Run the algorithm using the slower vtkDataArray double API instead:
80     worker(array, expectedArray);
81   }
82   return worker.ExitValue;
83 }
84 
ReadImageData(const std::string & fileName)85 vtkSmartPointer<vtkImageData> ReadImageData(const std::string& fileName)
86 {
87   vtkNew<vtkXMLImageDataReader> reader;
88   reader->SetFileName(fileName.c_str());
89   reader->Update();
90   vtkSmartPointer<vtkImageData> data = vtkImageData::SafeDownCast(reader->GetOutput());
91   return data;
92 }
93 
TestDataSet(vtkDataSet * data,vtkDataSet * expectedData)94 int TestDataSet(vtkDataSet* data, vtkDataSet* expectedData)
95 {
96   if (data == nullptr || expectedData == nullptr)
97   {
98     std::cerr << "Error: Data not in the format expected." << std::endl;
99     return EXIT_FAILURE;
100   }
101 
102   if (data->GetNumberOfPoints() != expectedData->GetNumberOfPoints())
103   {
104     std::cerr << "Expecting " << expectedData->GetNumberOfPoints()
105               << " points but got: " << data->GetNumberOfPoints() << std::endl;
106     return EXIT_FAILURE;
107   }
108 
109   if (data->GetNumberOfCells() != expectedData->GetNumberOfCells())
110   {
111     std::cerr << "Expecting " << expectedData->GetNumberOfCells()
112               << " cells but got: " << data->GetNumberOfCells() << std::endl;
113     return EXIT_FAILURE;
114   }
115   for (int attributeType = 0; attributeType < vtkDataObject::FIELD; ++attributeType)
116   {
117     int numberRead = data->GetAttributesAsFieldData(attributeType)->GetNumberOfArrays();
118     int numberExpected = expectedData->GetAttributesAsFieldData(attributeType)->GetNumberOfArrays();
119     if (numberRead != numberExpected)
120     {
121       std::cerr << "Expecting " << numberExpected << " arrays of type " << attributeType
122                 << " but got " << numberRead << std::endl;
123       return EXIT_FAILURE;
124     }
125     vtkFieldData* fieldData = data->GetAttributesAsFieldData(attributeType);
126     vtkFieldData* expectedFieldData = expectedData->GetAttributesAsFieldData(attributeType);
127     for (int i = 0; i < numberRead; ++i)
128     {
129       // the arrays are not in the same order because listing arrays in creation
130       // order fails. See vtkHDFReader::Implementation::GetArrayNames
131       vtkAbstractArray* expectedArray = expectedFieldData->GetAbstractArray(i);
132       vtkAbstractArray* array = fieldData->GetAbstractArray(expectedArray->GetName());
133       if (std::string(expectedArray->GetClassName()) != array->GetClassName() &&
134         // long long == long
135         !(std::string(expectedArray->GetClassName()) == "vtkLongLongArray" &&
136           std::string(array->GetClassName()) == "vtkLongArray" &&
137           sizeof(long long) == sizeof(long)) &&
138         // unsigned long long == unsigned long
139         !(std::string(expectedArray->GetClassName()) == "vtkUnsignedLongLongArray" &&
140           std::string(array->GetClassName()) == "vtkUnsignedLongArray" &&
141           sizeof(unsigned long long) == sizeof(unsigned long)) &&
142         // vtkIdType == long
143         !(std::string(expectedArray->GetClassName()) == "vtkIdTypeArray" &&
144           std::string(array->GetClassName()) == "vtkLongArray" &&
145           sizeof(vtkIdType) == sizeof(long)) &&
146         // vtkIdType == long long
147         !(std::string(expectedArray->GetClassName()) == "vtkIdTypeArray" &&
148           std::string(array->GetClassName()) == "vtkLongLongArray" &&
149           sizeof(vtkIdType) == sizeof(long long)))
150       {
151         std::cerr << "Different array type: " << array->GetClassName() << " from expected "
152                   << expectedArray->GetClassName() << " for array: " << expectedArray->GetName()
153                   << std::endl
154                   << "sizeof(long long): " << sizeof(long long) << std::endl
155                   << "sizeof(long): " << sizeof(long) << std::endl;
156         return EXIT_FAILURE;
157       }
158 
159       if (array->GetNumberOfTuples() != expectedArray->GetNumberOfTuples() ||
160         array->GetNumberOfComponents() != expectedArray->GetNumberOfComponents())
161       {
162         std::cerr << "Array " << array->GetName() << " has a different number of "
163                   << "tuples/components: " << array->GetNumberOfTuples() << "/"
164                   << array->GetNumberOfComponents()
165                   << " than expected: " << expectedArray->GetNumberOfTuples() << "/"
166                   << expectedArray->GetNumberOfComponents() << std::endl;
167         return EXIT_FAILURE;
168       }
169       vtkDataArray* a = vtkDataArray::SafeDownCast(array);
170       vtkDataArray* ea = vtkDataArray::SafeDownCast(expectedArray);
171       if (a)
172       {
173         if (CompareVectors(a, ea))
174         {
175           return EXIT_FAILURE;
176         }
177       }
178     };
179   }
180   return EXIT_SUCCESS;
181 }
182 
TestImageData(const std::string & dataRoot)183 int TestImageData(const std::string& dataRoot)
184 {
185   // ImageData file
186   // ------------------------------------------------------------
187   std::string fileName = dataRoot + "/Data/mandelbrot-vti.hdf";
188   std::cout << "Testing: " << fileName << std::endl;
189   vtkNew<vtkHDFReader> reader;
190   if (!reader->CanReadFile(fileName.c_str()))
191   {
192     return EXIT_FAILURE;
193   }
194   reader->SetFileName(fileName.c_str());
195   reader->Update();
196   vtkImageData* data = vtkImageData::SafeDownCast(reader->GetOutput());
197   vtkSmartPointer<vtkImageData> expectedData = ReadImageData(dataRoot + "/Data/mandelbrot.vti");
198 
199   int* dims = data->GetDimensions();
200   int* edims = expectedData->GetDimensions();
201   if (dims[0] != edims[0] || dims[1] != edims[1] || dims[2] != edims[2])
202   {
203     std::cerr << "Error: vtkImageData with wrong dimensions: "
204               << "expecting "
205               << "[" << edims[0] << ", " << edims[1] << ", " << edims[2] << "]"
206               << " got "
207               << "[" << dims[0] << ", " << dims[1] << ", " << dims[2] << "]" << std::endl;
208     return EXIT_FAILURE;
209   }
210 
211   return TestDataSet(data, expectedData);
212 }
213 
214 template <bool parallel>
TestUnstructuredGrid(const std::string & dataRoot)215 int TestUnstructuredGrid(const std::string& dataRoot)
216 {
217   std::string fileName, expectedName;
218   vtkNew<vtkHDFReader> reader;
219   vtkNew<vtkXMLUnstructuredGridReader> expectedReader;
220   vtkNew<vtkXMLPUnstructuredGridReader> expectedPReader;
221   vtkXMLReader* oreader;
222   if (parallel)
223   {
224     fileName = dataRoot + "/Data/can-pvtu.hdf";
225     expectedName = dataRoot + "/Data/can.pvtu";
226     oreader = expectedPReader;
227   }
228   else
229   {
230     fileName = dataRoot + "/Data/can-vtu.hdf";
231     expectedName = dataRoot + "/Data/can.vtu";
232     oreader = expectedReader;
233   }
234   std::cout << "Testing: " << fileName << std::endl;
235   if (!reader->CanReadFile(fileName.c_str()))
236   {
237     return EXIT_FAILURE;
238   }
239   reader->SetFileName(fileName.c_str());
240   reader->Update();
241   vtkUnstructuredGrid* data = vtkUnstructuredGrid::SafeDownCast(reader->GetOutputAsDataSet());
242 
243   oreader->SetFileName(expectedName.c_str());
244   oreader->Update();
245   vtkUnstructuredGrid* expectedData =
246     vtkUnstructuredGrid::SafeDownCast(oreader->GetOutputAsDataSet());
247   return TestDataSet(data, expectedData);
248 }
249 
TestHDFReader(int argc,char * argv[])250 int TestHDFReader(int argc, char* argv[])
251 {
252   vtkNew<vtkTesting> testHelper;
253   testHelper->AddArguments(argc, argv);
254   if (!testHelper->IsFlagSpecified("-D"))
255   {
256     std::cerr << "Error: -D /path/to/data was not specified.";
257     return EXIT_FAILURE;
258   }
259 
260   std::string dataRoot = testHelper->GetDataRoot();
261   if (TestImageData(dataRoot))
262   {
263     return EXIT_FAILURE;
264   }
265 
266   if (TestUnstructuredGrid<false /*parallel*/>(dataRoot))
267   {
268     return EXIT_FAILURE;
269   }
270   if (TestUnstructuredGrid<true /*parallel*/>(dataRoot))
271   {
272     return EXIT_FAILURE;
273   }
274   return EXIT_SUCCESS;
275 }
276