1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkXMLHyperTreeGridWriter.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 "vtkXMLHyperTreeGridWriter.h"
17 
18 #include "vtkAbstractArray.h"
19 #include "vtkBitArray.h"
20 #include "vtkCellData.h"
21 #include "vtkDoubleArray.h"
22 #include "vtkErrorCode.h"
23 #include "vtkHyperTree.h"
24 #include "vtkHyperTreeGrid.h"
25 #include "vtkHyperTreeGridNonOrientedCursor.h"
26 #include "vtkIdTypeArray.h"
27 #include "vtkInformation.h"
28 #include "vtkObjectFactory.h"
29 #include "vtkTypeInt64Array.h"
30 #include "vtkTypeUInt32Array.h"
31 #include "vtkUnsignedIntArray.h"
32 
33 #define vtkXMLOffsetsManager_DoNotInclude
34 #include "vtkXMLOffsetsManager.h"
35 #undef vtkXMLOffsetsManager_DoNotInclude
36 
37 #include <cassert>
38 
39 vtkStandardNewMacro(vtkXMLHyperTreeGridWriter);
40 
41 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)42 void vtkXMLHyperTreeGridWriter::PrintSelf(ostream& os, vtkIndent indent)
43 {
44   this->Superclass::PrintSelf(os, indent);
45 }
46 
47 //------------------------------------------------------------------------------
GetInput()48 vtkHyperTreeGrid* vtkXMLHyperTreeGridWriter::GetInput()
49 {
50   return static_cast<vtkHyperTreeGrid*>(this->Superclass::GetInput());
51 }
52 
53 //------------------------------------------------------------------------------
GetDefaultFileExtension()54 const char* vtkXMLHyperTreeGridWriter::GetDefaultFileExtension()
55 {
56   return "htg";
57 }
58 
59 //------------------------------------------------------------------------------
GetDataSetName()60 const char* vtkXMLHyperTreeGridWriter::GetDataSetName()
61 {
62   return "HyperTreeGrid";
63 }
64 
65 //------------------------------------------------------------------------------
FillInputPortInformation(int,vtkInformation * info)66 int vtkXMLHyperTreeGridWriter::FillInputPortInformation(int, vtkInformation* info)
67 {
68   info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkHyperTreeGrid");
69   return 1;
70 }
71 
72 //------------------------------------------------------------------------------
WriteData()73 int vtkXMLHyperTreeGridWriter::WriteData()
74 {
75   // write XML header and VTK file header and file attributes
76   if (!this->StartFile())
77   {
78     return 0;
79   }
80 
81   vtkIndent indent = vtkIndent().GetNextIndent();
82 
83   // Header attributes
84   if (!this->StartPrimaryElement(indent))
85   {
86     return 0;
87   }
88 
89   // Coordinates for grid (can be replaced by origin and scale)
90   if (!this->WriteGrid(indent.GetNextIndent()))
91   {
92     return 0;
93   }
94 
95   if (this->GetDataSetMajorVersion() == 0 && !this->WriteTrees_0(indent.GetNextIndent()))
96   {
97     return 0;
98   }
99   else if (this->GetDataSetMajorVersion() == 1 && !this->WriteTrees_1(indent.GetNextIndent()))
100   {
101     return 0;
102   }
103   else if (this->GetDataSetMajorVersion() >= 2 && !this->WriteTrees_2(indent.GetNextIndent()))
104   {
105     return 0;
106   }
107 
108   this->WriteFieldData(indent.GetNextIndent());
109 
110   if (!this->FinishPrimaryElement(indent))
111   {
112     return 0;
113   }
114 
115   // Write all appended data by tree using Helper function
116   if (this->DataMode == vtkXMLWriter::Appended)
117   {
118     vtkHyperTreeGrid* input = this->GetInput();
119     vtkCellData* pd = input->GetCellData();
120     vtkIdType numberOfCellDataArrays = pd->GetNumberOfArrays();
121 
122     this->StartAppendedData();
123 
124     // Write the field data arrays.
125     if (this->FieldDataOM->GetNumberOfElements())
126     {
127       vtkNew<vtkFieldData> fieldDataCopy;
128       this->UpdateFieldData(fieldDataCopy);
129 
130       this->WriteFieldDataAppendedData(fieldDataCopy, this->CurrentTimeIndex, this->FieldDataOM);
131       if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
132       {
133         return 0;
134       }
135     }
136 
137     // Write the Coordinates arrays
138     if (this->CoordsOMG->GetNumberOfElements())
139     {
140       assert(this->CoordsOMG->GetNumberOfElements() == 3);
141       this->WriteAppendedArrayDataHelper(input->GetXCoordinates(), this->CoordsOMG->GetElement(0));
142       this->WriteAppendedArrayDataHelper(input->GetYCoordinates(), this->CoordsOMG->GetElement(1));
143       this->WriteAppendedArrayDataHelper(input->GetZCoordinates(), this->CoordsOMG->GetElement(2));
144     }
145 
146     // Write the data for each tree
147     vtkHyperTreeGrid::vtkHyperTreeGridIterator it;
148     input->InitializeTreeIterator(it);
149     vtkIdType inIndex;
150     int treeIndx = 0;
151 
152     if (this->GetDataSetMajorVersion() == 0)
153     {
154       while (it.GetNextTree(inIndex))
155       {
156         vtkHyperTreeGridNonOrientedCursor* inCursor = input->NewNonOrientedCursor(inIndex);
157         vtkHyperTree* tree = inCursor->GetTree();
158         vtkIdType numberOfVertices = tree->GetNumberOfVertices();
159 
160         // Tree Descriptor
161         this->WriteAppendedArrayDataHelper(
162           this->Descriptors[treeIndx], this->DescriptorOMG->GetElement(treeIndx));
163         if (input->GetMask())
164         {
165           // Tree Mask
166           this->WriteAppendedArrayDataHelper(
167             this->Masks[treeIndx], this->MaskOMG->GetElement(treeIndx));
168         }
169         // Point Data
170         for (int i = 0; i < pd->GetNumberOfArrays(); ++i)
171         {
172           vtkAbstractArray* array = pd->GetAbstractArray(i);
173           vtkIdType pdIndx = treeIndx * numberOfCellDataArrays + i;
174           this->WriteCellDataAppendedArrayDataHelper(
175             array, numberOfVertices, this->CellDataOMG->GetElement(pdIndx), tree);
176         }
177         ++treeIndx;
178         inCursor->Delete();
179       }
180     }
181     else if (this->GetDataSetMajorVersion() == 1)
182     {
183       while (it.GetNextTree(inIndex))
184       {
185         // Tree Descriptor
186         this->WriteAppendedArrayDataHelper(
187           this->Descriptors[treeIndx], this->DescriptorOMG->GetElement(treeIndx));
188         // Tree NbVerticesByLevels
189         this->WriteAppendedArrayDataHelper(
190           this->NbVerticesByLevels[treeIndx], this->NbVerticesByLevelOMG->GetElement(treeIndx));
191         if (input->GetMask())
192         {
193           // Tree Mask
194           this->WriteAppendedArrayDataHelper(
195             this->Masks[treeIndx], this->MaskOMG->GetElement(treeIndx));
196         }
197         // Point Data
198         vtkIdList* ids = this->Ids[treeIndx];
199         vtkIdType numberOfVertices = ids->GetNumberOfIds();
200         for (int i = 0; i < pd->GetNumberOfArrays(); ++i)
201         {
202           vtkAbstractArray* a = pd->GetAbstractArray(i);
203           vtkAbstractArray* b = a->NewInstance();
204           int numberOfComponents = a->GetNumberOfComponents();
205           b->SetNumberOfTuples(numberOfVertices);
206           b->SetNumberOfComponents(numberOfComponents);
207           b->SetNumberOfValues(numberOfComponents * numberOfVertices);
208           // BitArray processed
209           auto* aBit = vtkArrayDownCast<vtkBitArray>(a);
210           if (aBit)
211           {
212             auto* bBit = vtkArrayDownCast<vtkBitArray>(b);
213             aBit->GetTuples(ids, bBit);
214           } // DataArray processed
215           else
216           {
217             a->GetTuples(ids, b);
218           }
219           // Write the data or XML description for appended data
220           vtkIdType pdIndx = treeIndx * numberOfCellDataArrays + i;
221           this->WriteAppendedArrayDataHelper(b, this->CellDataOMG->GetElement(pdIndx));
222           b->Delete();
223         }
224         ++treeIndx;
225       }
226     }
227     else if (this->GetDataSetMajorVersion() == 2)
228     {
229       auto& metaData = this->MetaDataForVersion2;
230       vtkIdType numberOfVertices = metaData.BreadthFirstIdMap->GetNumberOfIds();
231       this->WriteAppendedArrayDataHelper(metaData.Descriptors, this->DescriptorOMG->GetElement(0));
232       this->WriteAppendedArrayDataHelper(
233         metaData.NumberOfVerticesPerDepth, this->NbVerticesByLevelOMG->GetElement(0));
234       this->WriteAppendedArrayDataHelper(metaData.TreeIds, this->TreeIdsOMG->GetElement(0));
235       this->WriteAppendedArrayDataHelper(
236         metaData.DepthPerTree, this->DepthPerTreeOMG->GetElement(0));
237       if (input->GetMask())
238       {
239         vtkBitArray* breadthFirstReorderedMask = input->GetMask()->NewInstance();
240         breadthFirstReorderedMask->SetNumberOfComponents(1);
241         breadthFirstReorderedMask->SetNumberOfValues(numberOfVertices);
242         input->GetMask()->GetTuples(metaData.BreadthFirstIdMap, breadthFirstReorderedMask);
243         this->WriteAppendedArrayDataHelper(breadthFirstReorderedMask, this->MaskOMG->GetElement(0));
244         breadthFirstReorderedMask->Delete();
245       }
246       for (int i = 0; i < pd->GetNumberOfArrays(); ++i)
247       {
248         // We remap the input array to a breadth first ordering
249         vtkAbstractArray* array = pd->GetAbstractArray(i);
250         vtkAbstractArray* breadthFirstReorderedArray = array->NewInstance();
251         int numberOfComponents = array->GetNumberOfComponents();
252         breadthFirstReorderedArray->SetNumberOfComponents(numberOfComponents);
253         breadthFirstReorderedArray->SetNumberOfValues(numberOfVertices * numberOfComponents);
254         array->GetTuples(metaData.BreadthFirstIdMap, breadthFirstReorderedArray);
255         this->WriteAppendedArrayDataHelper(
256           breadthFirstReorderedArray, this->CellDataOMG->GetElement(i));
257         breadthFirstReorderedArray->Delete();
258       }
259     }
260     this->EndAppendedData();
261   }
262   this->Descriptors.clear();
263   this->NbVerticesByLevels.clear();
264   this->Masks.clear();
265   this->Ids.clear();
266   this->MetaDataForVersion2.Initialize();
267   if (!this->EndFile())
268   {
269     return 0;
270   }
271   return 1;
272 }
273 
274 //------------------------------------------------------------------------------
StartPrimaryElement(vtkIndent indent)275 int vtkXMLHyperTreeGridWriter::StartPrimaryElement(vtkIndent indent)
276 {
277   ostream& os = *(this->Stream);
278 
279   return (!this->WritePrimaryElement(os, indent)) ? 0 : 1;
280 }
281 
282 //------------------------------------------------------------------------------
WritePrimaryElementAttributes(ostream & os,vtkIndent indent)283 void vtkXMLHyperTreeGridWriter::WritePrimaryElementAttributes(ostream& os, vtkIndent indent)
284 {
285   this->Superclass::WritePrimaryElementAttributes(os, indent);
286   vtkHyperTreeGrid* input = this->GetInput();
287 
288   int extent[6];
289   input->GetExtent(extent);
290 
291   if (this->GetDataSetMajorVersion() < 1) // Major version < 1
292   {
293     this->WriteScalarAttribute("Dimension", (int)input->GetDimension());
294     this->WriteScalarAttribute("Orientation", (int)input->GetOrientation());
295   }
296 
297   this->WriteScalarAttribute("BranchFactor", (int)input->GetBranchFactor());
298   this->WriteScalarAttribute("TransposedRootIndexing", (bool)input->GetTransposedRootIndexing());
299   this->WriteVectorAttribute(
300     "Dimensions", 3, (int*)const_cast<unsigned int*>(input->GetDimensions()));
301   if (input->GetHasInterface())
302   {
303     this->WriteStringAttribute("InterfaceNormalsName", input->GetInterfaceNormalsName());
304   }
305   if (input->GetHasInterface())
306   {
307     this->WriteStringAttribute("InterfaceInterceptsName", input->GetInterfaceInterceptsName());
308   }
309 
310   if (this->GetDataSetMajorVersion() < 1)
311   {
312     this->WriteScalarAttribute("NumberOfVertices", input->GetNumberOfVertices());
313   }
314 }
315 
316 //------------------------------------------------------------------------------
WriteGrid(vtkIndent indent)317 int vtkXMLHyperTreeGridWriter::WriteGrid(vtkIndent indent)
318 {
319   vtkHyperTreeGrid* input = this->GetInput();
320   ostream& os = *(this->Stream);
321   os << indent << "<Grid>\n";
322 
323   if (this->DataMode == Appended)
324   {
325     // Coordinates of the grid
326     this->CoordsOMG->Allocate(3, this->NumberOfTimeSteps);
327     this->WriteArrayAppended(input->GetXCoordinates(), indent.GetNextIndent(),
328       this->CoordsOMG->GetElement(0), "XCoordinates",
329       input->GetXCoordinates()->GetNumberOfTuples());
330     this->WriteArrayAppended(input->GetYCoordinates(), indent.GetNextIndent(),
331       this->CoordsOMG->GetElement(1), "YCoordinates",
332       input->GetYCoordinates()->GetNumberOfTuples());
333     this->WriteArrayAppended(input->GetZCoordinates(), indent.GetNextIndent(),
334       this->CoordsOMG->GetElement(2), "ZCoordinates",
335       input->GetZCoordinates()->GetNumberOfTuples());
336   }
337   else
338   {
339     // Coordinates of the grid
340     this->WriteArrayInline(input->GetXCoordinates(), indent.GetNextIndent(), "XCoordinates",
341       input->GetXCoordinates()->GetNumberOfValues());
342     this->WriteArrayInline(input->GetYCoordinates(), indent.GetNextIndent(), "YCoordinates",
343       input->GetYCoordinates()->GetNumberOfValues());
344     this->WriteArrayInline(input->GetZCoordinates(), indent.GetNextIndent(), "ZCoordinates",
345       input->GetZCoordinates()->GetNumberOfValues());
346   }
347 
348   os << indent << "</Grid>\n";
349   os.flush();
350   if (os.fail())
351   {
352     this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
353     return 0;
354   }
355   return 1;
356 }
357 
358 //------------------------------------------------------------------------------
vtkXMLHyperTreeGridWriter()359 vtkXMLHyperTreeGridWriter::vtkXMLHyperTreeGridWriter()
360   : CoordsOMG(new OffsetsManagerGroup)
361   , DescriptorOMG(new OffsetsManagerGroup)
362   , NbVerticesByLevelOMG(new OffsetsManagerGroup)
363   , MaskOMG(new OffsetsManagerGroup)
364   , CellDataOMG(new OffsetsManagerGroup)
365   , TreeIdsOMG(new OffsetsManagerGroup)
366   , DepthPerTreeOMG(new OffsetsManagerGroup)
367   , NumberOfTrees(0)
368   , DataSetMajorVersion(2)
369   , DataSetMinorVersion(0)
370 {
371 }
372 
373 //------------------------------------------------------------------------------
~vtkXMLHyperTreeGridWriter()374 vtkXMLHyperTreeGridWriter::~vtkXMLHyperTreeGridWriter()
375 {
376   delete this->CoordsOMG;
377   delete this->DescriptorOMG;
378   delete this->NbVerticesByLevelOMG;
379   delete this->MaskOMG;
380   delete this->CellDataOMG;
381   delete this->TreeIdsOMG;
382   delete this->DepthPerTreeOMG;
383 }
384 
385 //------------------------------------------------------------------------------
386 namespace
387 {
388 //
389 // Depth first recursion to walk the tree in child order
390 // Used to create the breadth first BitArray descriptor appending
391 // node and leaf indicator by level
392 //
BuildDescriptor(vtkHyperTreeGridNonOrientedCursor * inCursor,int level,bool hasMask,unsigned int numChildren,std::vector<std::string> & descriptor,std::vector<std::string> & mask)393 void BuildDescriptor(vtkHyperTreeGridNonOrientedCursor* inCursor, int level, bool hasMask,
394   unsigned int numChildren, std::vector<std::string>& descriptor, std::vector<std::string>& mask)
395 {
396   // Append to mask string
397   if (hasMask)
398   {
399     if (inCursor->IsMasked())
400       mask[level] += '1';
401     else
402       mask[level] += '0';
403   }
404 
405   // Append to descriptor string
406   if (!inCursor->IsLeaf())
407   {
408     descriptor[level] += 'R';
409 
410     // If input cursor is not a leaf, recurse to all children
411     for (unsigned int child = 0; child < numChildren; ++child)
412     {
413       // Move cursor to child
414       inCursor->ToChild(child);
415 
416       // Recurse
417       BuildDescriptor(inCursor, level + 1, hasMask, numChildren, descriptor, mask);
418 
419       // Move cursor back to parent
420       inCursor->ToParent();
421     } // child
422   }
423   else
424   {
425     descriptor[level] += '.';
426   }
427 }
428 }
429 
430 //------------------------------------------------------------------------------
WriteTrees_0(vtkIndent indent)431 int vtkXMLHyperTreeGridWriter::WriteTrees_0(vtkIndent indent)
432 {
433   vtkHyperTreeGrid* input = this->GetInput();
434   vtkIdType maxLevels = input->GetNumberOfLevels();
435   vtkCellData* pd = input->GetCellData();
436   vtkIdType numberOfCellDataArrays = pd->GetNumberOfArrays();
437 
438   // Count the actual number of hypertrees represented in this hypertree grid
439   vtkHyperTreeGrid::vtkHyperTreeGridIterator it;
440   input->InitializeTreeIterator(it);
441   this->NumberOfTrees = 0;
442   vtkIdType inIndex;
443   while (it.GetNextTree(inIndex))
444   {
445     ++this->NumberOfTrees;
446   }
447 
448   // Allocate offsets managers for appended data
449   if (this->DataMode == Appended && this->NumberOfTrees > 0)
450   {
451     this->DescriptorOMG->Allocate(this->NumberOfTrees, this->NumberOfTimeSteps);
452     this->MaskOMG->Allocate(this->NumberOfTrees, this->NumberOfTimeSteps);
453     this->CellDataOMG->Allocate(
454       this->NumberOfTrees * numberOfCellDataArrays, this->NumberOfTimeSteps);
455   }
456 
457   ostream& os = *(this->Stream);
458   os << indent << "<Trees>\n";
459   vtkIndent treeIndent = indent.GetNextIndent();
460 
461   // Collect description by processing depth first and writing breadth first
462   input->InitializeTreeIterator(it);
463   int treeIndx = 0;
464   vtkIdType globalOffset = 0;
465   while (it.GetNextTree(inIndex))
466   {
467     // Initialize new grid cursor at root of current input tree
468     vtkHyperTreeGridNonOrientedCursor* inCursor = input->NewNonOrientedCursor(inIndex);
469     vtkHyperTree* tree = inCursor->GetTree();
470     vtkIdType numberOfVertices = tree->GetNumberOfVertices();
471 
472     os << treeIndent << "<Tree";
473     this->WriteScalarAttribute("Index", inIndex);
474     this->WriteScalarAttribute("GlobalOffset", globalOffset);
475     this->WriteScalarAttribute("NumberOfVertices", numberOfVertices);
476     os << ">\n";
477 
478     // Recursively compute descriptor for this tree, appending any
479     // entries for each of the levels in descByLevel for output.
480     // Collect the masked indicator at the same time
481     std::vector<std::string> descByLevel(maxLevels);
482     std::vector<std::string> maskByLevel(maxLevels);
483     BuildDescriptor(
484       inCursor, 0, input->HasMask(), input->GetNumberOfChildren(), descByLevel, maskByLevel);
485 
486     // Clean up
487     inCursor->Delete();
488 
489     // Descriptor BitArray
490     vtkBitArray* descriptor = vtkBitArray::New();
491     std::string::const_iterator liter;
492     for (int l = 0; l < maxLevels; ++l)
493     {
494       for (liter = descByLevel[l].begin(); liter != descByLevel[l].end(); ++liter)
495       {
496         switch (*liter)
497         {
498           case 'R': //  Refined cell
499             descriptor->InsertNextValue(1);
500             break;
501           case '.': // Leaf cell
502             descriptor->InsertNextValue(0);
503             break;
504           default:
505             vtkErrorMacro(<< "Unrecognized character: " << *liter << " in string "
506                           << descByLevel[l]);
507             return 0;
508         }
509       }
510     }
511     descriptor->Squeeze();
512     this->Descriptors.emplace_back(vtkSmartPointer<vtkBitArray>::Take(descriptor));
513     auto& desc = this->Descriptors.back();
514 
515     // Mask BitAarray
516     vtkBitArray* mask = input->GetMask() ? vtkBitArray::New() : nullptr;
517     if (input->GetMask())
518     {
519       for (int l = 0; l < maxLevels; ++l)
520       {
521         for (liter = maskByLevel[l].begin(); liter != maskByLevel[l].end(); ++liter)
522         {
523           switch (*liter)
524           {
525             case '0': // Not masked
526               mask->InsertNextValue(0);
527               break;
528             case '1': // Masked
529               mask->InsertNextValue(1);
530               break;
531             default:
532               vtkErrorMacro(<< "Unrecognized character: " << *liter << " in string "
533                             << maskByLevel[l]);
534               return 0;
535           }
536         }
537       }
538       mask->Squeeze();
539       this->Masks.emplace_back(vtkSmartPointer<vtkBitArray>::Take(mask));
540     }
541 
542     vtkIndent infoIndent = treeIndent.GetNextIndent();
543 
544     // Write the descriptor and mask BitArrays
545     if (this->DataMode == Appended)
546     {
547       this->WriteArrayAppended(desc, infoIndent, this->DescriptorOMG->GetElement(treeIndx),
548         "Descriptor", desc->GetNumberOfValues());
549       if (input->GetMask())
550       {
551         this->WriteArrayAppended(
552           mask, infoIndent, this->MaskOMG->GetElement(treeIndx), "Mask", mask->GetNumberOfValues());
553       }
554     }
555     else
556     {
557       this->WriteArrayInline(desc, infoIndent, "Descriptor", desc->GetNumberOfValues());
558       if (input->GetMask())
559       {
560         this->WriteArrayInline(mask, infoIndent, "Mask", mask->GetNumberOfValues());
561       }
562     }
563 
564     // Write the point data
565     os << infoIndent << "<CellData>\n";
566     for (int i = 0; i < pd->GetNumberOfArrays(); ++i)
567     {
568       vtkAbstractArray* a = pd->GetAbstractArray(i);
569       vtkAbstractArray* b = a->NewInstance();
570       int numberOfComponents = a->GetNumberOfComponents();
571       b->SetNumberOfTuples(numberOfVertices);
572       b->SetNumberOfComponents(numberOfComponents);
573       for (int e = 0; e < numberOfVertices; ++e)
574       {
575         // note - we unravel the array contents which may be interleaved in input array.
576         // The reader expect that each grid's data will be contiguous and uses "GlobalOffset"
577         // to assemble a big array on the other side.
578         // The in memory order of elements then isn't necessarily the same but HTG handles that.
579         vtkIdType aDataOffset = tree->GetGlobalIndexFromLocal(e) * numberOfComponents;
580         int bDataOffset = e * numberOfComponents;
581         for (int c = 0; c < numberOfComponents; ++c)
582         {
583           b->SetVariantValue(bDataOffset + c, a->GetVariantValue(aDataOffset + c));
584         }
585       }
586 
587       // Write the data or XML description for appended data
588       if (this->DataMode == Appended)
589       {
590         this->WriteArrayAppended(b, infoIndent.GetNextIndent(),
591           this->CellDataOMG->GetElement(treeIndx * numberOfCellDataArrays + i), a->GetName(),
592           numberOfVertices * numberOfComponents);
593       }
594       else
595       {
596         this->WriteArrayInline(
597           b, infoIndent.GetNextIndent(), a->GetName(), numberOfVertices * numberOfComponents);
598       }
599       b->Delete();
600     }
601     ++treeIndx;
602 
603     // Increment to next tree with CellData
604     os << infoIndent << "</CellData>\n";
605     os << treeIndent << "</Tree>\n";
606     globalOffset += numberOfVertices;
607   }
608   os << indent << "</Trees>\n";
609 
610   os.flush();
611   if (os.fail())
612   {
613     this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
614     return 0;
615   }
616   return 1;
617 }
618 
619 //------------------------------------------------------------------------------
WriteTrees_1(vtkIndent indent)620 int vtkXMLHyperTreeGridWriter::WriteTrees_1(vtkIndent indent)
621 {
622   vtkHyperTreeGrid* input = this->GetInput();
623   vtkCellData* pd = input->GetCellData();
624   vtkIdType numberOfCellDataArrays = pd->GetNumberOfArrays();
625 
626   // Count the actual number of hypertrees represented in this hypertree grid
627   vtkHyperTreeGrid::vtkHyperTreeGridIterator it;
628   input->InitializeTreeIterator(it);
629   this->NumberOfTrees = 0;
630   vtkIdType inIndex;
631   while (it.GetNextTree(inIndex))
632   {
633     ++this->NumberOfTrees;
634   }
635 
636   // Allocate offsets managers for appended data
637   if (this->DataMode == Appended && this->NumberOfTrees > 0)
638   {
639     this->DescriptorOMG->Allocate(this->NumberOfTrees, this->NumberOfTimeSteps);
640     this->NbVerticesByLevelOMG->Allocate(this->NumberOfTrees, this->NumberOfTimeSteps);
641     this->MaskOMG->Allocate(this->NumberOfTrees, this->NumberOfTimeSteps);
642     this->CellDataOMG->Allocate(
643       this->NumberOfTrees * numberOfCellDataArrays, this->NumberOfTimeSteps);
644   }
645 
646   ostream& os = *(this->Stream);
647   os << indent << "<Trees>\n";
648   vtkIndent treeIndent = indent.GetNextIndent();
649 
650   // Collect description by processing depth first and writing breadth first
651   input->InitializeTreeIterator(it);
652   int treeIndx = 0;
653   while (it.GetNextTree(inIndex))
654   {
655     os << treeIndent << "<Tree";
656     this->WriteScalarAttribute("Index", inIndex);
657     vtkHyperTree* tree = input->GetTree(inIndex);
658     const int numberOfLevels = static_cast<int>(tree->GetNumberOfLevels());
659     this->WriteScalarAttribute("NumberOfLevels", numberOfLevels);
660 
661     vtkTypeInt64Array* nbVerticesByLevel = vtkTypeInt64Array::New();
662     vtkBitArray* descriptor = vtkBitArray::New();
663     vtkIdList* ids = vtkIdList::New();
664     tree->ComputeBreadthFirstOrderDescriptor(input->GetMask(), nbVerticesByLevel, descriptor, ids);
665 
666     // squeezing last zeros of last row out of descriptor
667     if (vtkIdType lastNonZeroId = descriptor->GetNumberOfValues())
668     {
669       while (lastNonZeroId && !descriptor->GetValue(--lastNonZeroId))
670         ;
671 
672       descriptor->SetNumberOfValues(lastNonZeroId + 1);
673     }
674 
675     if (input->GetMask())
676     {
677       this->Masks.emplace_back(vtkSmartPointer<vtkBitArray>::New());
678       auto& mask = this->Masks.back();
679       mask->SetNumberOfComponents(1);
680       mask->SetNumberOfValues(ids->GetNumberOfIds());
681       input->GetMask()->GetTuples(ids, mask);
682       // squeezing last zeros of last row out of mask
683       if (vtkIdType lastNonZeroId = mask->GetNumberOfValues())
684       {
685         while (lastNonZeroId && !mask->GetValue(--lastNonZeroId))
686           ;
687 
688         mask->SetNumberOfValues(lastNonZeroId + 1);
689       }
690     }
691 
692     this->NbVerticesByLevels.emplace_back(
693       vtkSmartPointer<vtkTypeInt64Array>::Take(nbVerticesByLevel));
694     this->Descriptors.emplace_back(vtkSmartPointer<vtkBitArray>::Take(descriptor));
695     this->Ids.emplace_back(vtkSmartPointer<vtkIdList>::Take(ids));
696 
697     vtkIndent infoIndent = treeIndent.GetNextIndent();
698 
699     const vtkIdType numberOfVertices = ids->GetNumberOfIds();
700     // Because non describe last False values...
701     assert(numberOfVertices >= descriptor->GetNumberOfTuples());
702     this->WriteScalarAttribute("NumberOfVertices", numberOfVertices);
703     os << ">\n";
704 
705     // Write the descriptor and mask BitArrays
706     if (this->DataMode == Appended)
707     {
708       this->WriteArrayAppended(descriptor, infoIndent, this->DescriptorOMG->GetElement(treeIndx),
709         "Descriptor", descriptor->GetNumberOfValues());
710       this->WriteArrayAppended(nbVerticesByLevel, infoIndent,
711         this->NbVerticesByLevelOMG->GetElement(treeIndx), "NbVerticesByLevel",
712         nbVerticesByLevel->GetNumberOfValues());
713       if (input->GetMask())
714       {
715         this->WriteArrayAppended(this->Masks.back(), infoIndent,
716           this->MaskOMG->GetElement(treeIndx), "Mask",
717           input->GetMask() ? this->Masks.back()->GetNumberOfValues() : 0);
718       }
719     }
720     else
721     {
722       this->WriteArrayInline(descriptor, infoIndent, "Descriptor", descriptor->GetNumberOfValues());
723       this->WriteArrayInline(
724         nbVerticesByLevel, infoIndent, "NbVerticesByLevel", nbVerticesByLevel->GetNumberOfValues());
725       if (input->GetMask())
726       {
727         this->WriteArrayInline(
728           this->Masks.back(), infoIndent, "Mask", this->Masks.back()->GetNumberOfValues());
729       }
730     }
731 
732     // Write the point data
733     os << infoIndent << "<CellData>\n";
734 
735     for (int i = 0; i < pd->GetNumberOfArrays(); ++i)
736     {
737       vtkAbstractArray* a = pd->GetAbstractArray(i);
738 
739       // Write the data or XML description for appended data
740       if (this->DataMode == Appended)
741       {
742         this->WriteArrayAppended(a, infoIndent.GetNextIndent(),
743           this->CellDataOMG->GetElement(treeIndx * numberOfCellDataArrays + i), a->GetName(), 0);
744         // Last parameter will eventually become the size of the stored arrays.
745         // When this modification is done, 0 should be replaced by:
746         // numberOfVertices * a->GetNumberOfComponents());
747       }
748       else
749       {
750         vtkAbstractArray* b = a->NewInstance();
751         const int numberOfComponents = a->GetNumberOfComponents();
752         b->SetNumberOfTuples(numberOfVertices);
753         b->SetNumberOfComponents(numberOfComponents);
754         b->SetNumberOfValues(numberOfComponents * numberOfVertices);
755         // BitArray processed
756         auto* aBit = vtkArrayDownCast<vtkBitArray>(a);
757         if (aBit)
758         {
759           auto* bBit = vtkArrayDownCast<vtkBitArray>(b);
760           aBit->GetTuples(ids, bBit);
761         } // DataArray processed
762         else
763         {
764           a->GetTuples(ids, b);
765         }
766         this->WriteArrayInline(
767           b, infoIndent.GetNextIndent(), a->GetName(), b->GetNumberOfTuples() * numberOfComponents);
768         b->Delete();
769       }
770     }
771     ++treeIndx;
772 
773     // Increment to next tree with CellData
774     os << infoIndent << "</CellData>\n";
775     os << treeIndent << "</Tree>\n";
776   }
777   os << indent << "</Trees>\n";
778 
779   os.flush();
780   if (os.fail())
781   {
782     this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
783     return 0;
784   }
785   return 1;
786 }
787 
788 //------------------------------------------------------------------------------
WriteTrees_2(vtkIndent indent)789 int vtkXMLHyperTreeGridWriter::WriteTrees_2(vtkIndent indent)
790 {
791   vtkHyperTreeGrid* input = this->GetInput();
792   vtkCellData* cd = input->GetCellData();
793   vtkIdType numberOfCellDataArrays = cd->GetNumberOfArrays();
794 
795   // Count the actual number of hypertrees represented in this hypertree grid
796   vtkHyperTreeGrid::vtkHyperTreeGridIterator it;
797   input->InitializeTreeIterator(it);
798   this->NumberOfTrees = 0;
799   vtkIdType inIndex;
800   while (it.GetNextTree(inIndex))
801   {
802     ++this->NumberOfTrees;
803   }
804 
805   // Allocate offsets managers for appended data
806   if (this->DataMode == Appended)
807   {
808     this->DescriptorOMG->Allocate(1, this->NumberOfTimeSteps);
809     this->NbVerticesByLevelOMG->Allocate(1, this->NumberOfTimeSteps);
810     this->TreeIdsOMG->Allocate(1, this->NumberOfTimeSteps);
811     this->DepthPerTreeOMG->Allocate(1, this->NumberOfTimeSteps);
812     this->CellDataOMG->Allocate(numberOfCellDataArrays, this->NumberOfTimeSteps);
813     if (input->GetMask())
814     {
815       this->MaskOMG->Allocate(1, this->NumberOfTimeSteps);
816     }
817   }
818 
819   // Collect description by processing depth first and writing breadth first
820   input->InitializeTreeIterator(it);
821 
822   auto& metaData = this->MetaDataForVersion2;
823 
824   metaData.Descriptors = vtkSmartPointer<vtkBitArray>::New();
825   metaData.TreeIds = vtkSmartPointer<vtkTypeInt64Array>::New();
826   metaData.NumberOfVerticesPerDepth = vtkSmartPointer<vtkTypeInt64Array>::New();
827   metaData.DepthPerTree = vtkSmartPointer<vtkTypeUInt32Array>::New();
828   metaData.BreadthFirstIdMap = vtkSmartPointer<vtkIdList>::New();
829 
830   metaData.TreeIds->SetNumberOfValues(input->GetNumberOfNonEmptyTrees());
831   metaData.DepthPerTree->SetNumberOfValues(input->GetNumberOfNonEmptyTrees());
832 
833   vtkIdType currentId = 0;
834 
835   while (it.GetNextTree(inIndex))
836   {
837     vtkHyperTree* tree = input->GetTree(inIndex);
838     metaData.TreeIds->SetValue(currentId, inIndex);
839 
840     vtkIdType previousSize = metaData.NumberOfVerticesPerDepth->GetNumberOfValues();
841     tree->ComputeBreadthFirstOrderDescriptor(input->GetMask(), metaData.NumberOfVerticesPerDepth,
842       metaData.Descriptors, metaData.BreadthFirstIdMap);
843     metaData.DepthPerTree->SetValue(
844       currentId++, metaData.NumberOfVerticesPerDepth->GetNumberOfValues() - previousSize);
845   }
846 
847   ostream& os = *(this->Stream);
848   os << indent << "<Trees>\n";
849   vtkIndent treeIndent = indent.GetNextIndent();
850   vtkIndent infoIndent = treeIndent.GetNextIndent();
851 
852   if (this->DataMode == Appended)
853   {
854     this->WriteArrayAppended(metaData.Descriptors, infoIndent, this->DescriptorOMG->GetElement(0),
855       "Descriptors", metaData.Descriptors->GetNumberOfValues());
856     this->WriteArrayAppended(metaData.NumberOfVerticesPerDepth, infoIndent,
857       this->NbVerticesByLevelOMG->GetElement(0), "NumberOfVerticesPerDepth",
858       metaData.NumberOfVerticesPerDepth->GetNumberOfValues());
859     this->WriteArrayAppended(metaData.TreeIds, infoIndent, this->TreeIdsOMG->GetElement(0),
860       "TreeIds", metaData.TreeIds->GetNumberOfValues());
861     this->WriteArrayAppended(metaData.DepthPerTree, infoIndent,
862       this->DepthPerTreeOMG->GetElement(0), "DepthPerTree",
863       metaData.DepthPerTree->GetNumberOfValues());
864     if (input->GetMask())
865     {
866       this->WriteArrayAppended(input->GetMask(), infoIndent, this->MaskOMG->GetElement(0), "Mask",
867         metaData.BreadthFirstIdMap->GetNumberOfIds());
868     }
869   }
870   else
871   {
872     this->WriteArrayInline(
873       metaData.Descriptors, infoIndent, "Descriptors", metaData.Descriptors->GetNumberOfValues());
874     this->WriteArrayInline(metaData.NumberOfVerticesPerDepth, infoIndent,
875       "NumberOfVerticesPerDepth", metaData.NumberOfVerticesPerDepth->GetNumberOfValues());
876     this->WriteArrayInline(
877       metaData.TreeIds, infoIndent, "TreeIds", metaData.TreeIds->GetNumberOfValues());
878     this->WriteArrayInline(metaData.DepthPerTree, infoIndent, "DepthPerTree",
879       metaData.DepthPerTree->GetNumberOfValues());
880     if (input->GetMask())
881     {
882       vtkBitArray* breadthFirstReorderedMask = input->GetMask()->NewInstance();
883       breadthFirstReorderedMask->SetNumberOfComponents(1);
884       breadthFirstReorderedMask->SetNumberOfValues(metaData.BreadthFirstIdMap->GetNumberOfIds());
885       input->GetMask()->GetTuples(metaData.BreadthFirstIdMap, breadthFirstReorderedMask);
886       this->WriteArrayInline(breadthFirstReorderedMask, infoIndent, "Mask",
887         metaData.BreadthFirstIdMap->GetNumberOfIds());
888       breadthFirstReorderedMask->Delete();
889     }
890   }
891 
892   os << indent << "</Trees>\n";
893 
894   // Write the vertices data
895   os << indent << "<CellData>\n";
896 
897   for (int i = 0; i < cd->GetNumberOfArrays(); ++i)
898   {
899     vtkAbstractArray* array = cd->GetAbstractArray(i);
900 
901     // Write the data or XML description for appended data
902     if (this->DataMode == Appended)
903     {
904       this->WriteArrayAppended(array, infoIndent, this->CellDataOMG->GetElement(0),
905         array->GetName(),
906         metaData.BreadthFirstIdMap->GetNumberOfIds() * array->GetNumberOfComponents());
907     }
908     else
909     {
910       // We remap the input array to a breadth first ordering
911       vtkAbstractArray* breadthFirstReorderedArray = array->NewInstance();
912       int numberOfComponents = array->GetNumberOfComponents();
913       breadthFirstReorderedArray->SetNumberOfComponents(numberOfComponents);
914       breadthFirstReorderedArray->SetNumberOfValues(
915         metaData.BreadthFirstIdMap->GetNumberOfIds() * numberOfComponents);
916       array->GetTuples(metaData.BreadthFirstIdMap, breadthFirstReorderedArray);
917       this->WriteArrayInline(breadthFirstReorderedArray, infoIndent, array->GetName(),
918         breadthFirstReorderedArray->GetNumberOfValues());
919       breadthFirstReorderedArray->Delete();
920     }
921   }
922 
923   // Increment to next tree with CellData
924   os << indent << "</CellData>\n";
925 
926   os.flush();
927   if (os.fail())
928   {
929     this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
930     return 0;
931   }
932   return 1;
933 }
934 
935 //------------------------------------------------------------------------------
FinishPrimaryElement(vtkIndent indent)936 int vtkXMLHyperTreeGridWriter::FinishPrimaryElement(vtkIndent indent)
937 {
938   ostream& os = *(this->Stream);
939 
940   // End the primary element.
941   os << indent << "</" << this->GetDataSetName() << ">\n";
942 
943   os.flush();
944   if (os.fail())
945   {
946     this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
947     return 0;
948   }
949   return 1;
950 }
951 
952 //------------------------------------------------------------------------------
WriteAppendedArrayDataHelper(vtkAbstractArray * array,OffsetsManager & offsets)953 void vtkXMLHyperTreeGridWriter::WriteAppendedArrayDataHelper(
954   vtkAbstractArray* array, OffsetsManager& offsets)
955 {
956   this->WriteArrayAppendedData(array, offsets.GetPosition(this->CurrentTimeIndex),
957     offsets.GetOffsetValue(this->CurrentTimeIndex));
958 
959   auto* dArray = vtkArrayDownCast<vtkDataArray>(array);
960   if (dArray)
961   {
962     double* range = dArray->GetRange(-1);
963     this->ForwardAppendedDataDouble(
964       offsets.GetRangeMinPosition(this->CurrentTimeIndex), range[0], "RangeMin");
965     this->ForwardAppendedDataDouble(
966       offsets.GetRangeMaxPosition(this->CurrentTimeIndex), range[1], "RangeMax");
967   }
968 }
969 
970 //------------------------------------------------------------------------------
WriteCellDataAppendedArrayDataHelper(vtkAbstractArray * a,vtkIdType numberOfVertices,OffsetsManager & offsets,vtkHyperTree * tree)971 void vtkXMLHyperTreeGridWriter::WriteCellDataAppendedArrayDataHelper(
972   vtkAbstractArray* a, vtkIdType numberOfVertices, OffsetsManager& offsets, vtkHyperTree* tree)
973 {
974   vtkAbstractArray* b = a->NewInstance();
975   int numberOfComponents = a->GetNumberOfComponents();
976 
977   b->SetNumberOfComponents(numberOfComponents);
978   b->SetNumberOfTuples(numberOfVertices);
979   for (int e = 0; e < numberOfComponents * numberOfVertices; ++e)
980   {
981     b->SetVariantValue(e, a->GetVariantValue(tree->GetGlobalIndexFromLocal(e)));
982   }
983 
984   this->WriteArrayAppendedData(
985     b, offsets.GetPosition(this->CurrentTimeIndex), offsets.GetOffsetValue(this->CurrentTimeIndex));
986 
987   auto* dArray = vtkArrayDownCast<vtkDataArray>(a);
988   if (dArray)
989   {
990     double* range = dArray->GetRange(-1);
991     this->ForwardAppendedDataDouble(
992       offsets.GetRangeMinPosition(this->CurrentTimeIndex), range[0], "RangeMin");
993     this->ForwardAppendedDataDouble(
994       offsets.GetRangeMaxPosition(this->CurrentTimeIndex), range[1], "RangeMax");
995   }
996   b->Delete();
997 }
998 
999 //------------------------------------------------------------------------------
Initialize()1000 void vtkXMLHyperTreeGridWriter::HyperTreeGridMetaDataForVersion2::Initialize()
1001 {
1002   this->Descriptors = nullptr;
1003   this->TreeIds = nullptr;
1004   this->NumberOfVerticesPerDepth = nullptr;
1005   this->DepthPerTree = nullptr;
1006   this->BreadthFirstIdMap = nullptr;
1007 }
1008