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