TTK
Loading...
Searching...
No Matches
TopologicalCompression.cpp
Go to the documentation of this file.
2
3// General.
5 this->setDebugMsgPrefix("TopologicalCompression");
6}
7
8// Dependencies.
9
10#ifdef TTK_ENABLE_ZFP
11
12#include <zfp.h>
13
14int ttk::TopologicalCompression::CompressWithZFP(
15 FILE *file,
16 const bool decompress,
17 std::vector<double> &array,
18 const int nx,
19 const int ny,
20 const int nz,
21 const double zfpTolerance) const {
22
23 int n1 = 0, n2 = 0;
24 bool is2D = nx == 1 || ny == 1 || nz == 1;
25 if(is2D) {
26 if(nx + ny == 2 || ny + nz == 2 || nx + nz == 2) {
27 this->printErr("One-dimensional arrays not supported.");
28 return 0;
29 }
30
31 n1 = nx != 1 ? nx : ny;
32 n2 = nx != 1 && ny != 1 ? ny : nz;
33 }
34
35 // array scalar type
36 const auto type = zfp_type_double;
37
38 // array meta data
39 zfp_field *field;
40 if(is2D) {
41 field = zfp_field_2d(array.data(), type, n1, n2);
42 } else {
43 field = zfp_field_3d(array.data(), type, nx, ny, nz);
44 }
45
46 // compressed stream
47 auto *zfp = zfp_stream_open(nullptr);
48
49 // set compression mode and parameters via one of three functions (c.f.
50 // https://zfp.readthedocs.io/en/release0.5.5/modes.html)
51 // use fixed-accuracy mode
52 zfp_stream_set_accuracy(zfp, zfpTolerance);
53
54 // allocate buffer for compressed data
55 const auto bufsize = zfp_stream_maximum_size(zfp, field);
56 std::vector<unsigned char> buffer(bufsize);
57
58 // associate bit stream with allocated buffer
59 auto *stream = stream_open(buffer.data(), bufsize);
60 zfp_stream_set_bit_stream(zfp, stream);
61 zfp_stream_rewind(zfp);
62
63 // return value: 0 = success
64 int status = 0;
65
66 // byte size of compressed stream
67 size_t zfpsize{};
68
69 // compress or decompress entire array
70 if(decompress) {
71 // read compressed stream and decompress array
72 zfpsize += fread(buffer.data(), 1, bufsize, file);
73
74 // read the ZFP header (from v2)
75 const auto res = zfp_read_header(zfp, field, ZFP_HEADER_FULL);
76 if(res == 0) {
77 this->printErr("Could not read ZFP header");
78 status = 1;
79 }
80
81 if(!zfp_decompress(zfp, field)) {
82 this->printErr("Decompression failed");
83 status = 1;
84 }
85 } else {
86 // write the ZFP header
87 const auto res = zfp_write_header(zfp, field, ZFP_HEADER_FULL);
88 if(res == 0) {
89 this->printErr("Could not write ZFP header");
90 status = 1;
91 }
92
93 // compress array and output compressed stream
94 zfpsize += zfp_compress(zfp, field);
95 if(!zfpsize) {
96 this->printErr("Compression failed");
97 status = 1;
98 } else
99 fwrite(buffer.data(), 1, zfpsize, file);
100 }
101
102 // clean up
103 zfp_field_free(field);
104 zfp_stream_close(zfp);
105 stream_close(stream);
106
107 if(status != 0) {
108 this->printErr("Encountered a problem with ZFP.");
109 }
110
111 return (int)zfpsize;
112}
113
114#endif // TTK_ENABLE_ZFP
115
116#ifdef TTK_ENABLE_ZLIB
117
118#include <zlib.h>
119
120unsigned long ttk::TopologicalCompression::GetZlibDestLen(
121 const unsigned long sourceLen) const {
122 return compressBound(sourceLen);
123}
124
125void ttk::TopologicalCompression::CompressWithZlib(
126 bool decompress,
127 unsigned char *dest,
128 unsigned long &destLen,
129 const unsigned char *const source,
130 const unsigned long sourceLen) const {
131
132 if(decompress)
133 uncompress(dest, &destLen, source, sourceLen);
134 else
135 compress(dest, &destLen, source, sourceLen);
136}
137
138#endif // TTK_ENABLE_ZLIB
139
141 if(val == 0)
142 return UINT_MAX;
143 if(val == 1)
144 return 0;
145 unsigned int ret = 0;
146 while(val > 1) {
147 val >>= 1;
148 ret++;
149 }
150 return ret;
151}
152
153// IO.
154
156 FILE *fm,
157 std::vector<int> &segmentation,
158 int &numberOfVertices,
159 int &numberOfSegments) const {
160
161 int numberOfBytesRead = 0;
162
163 numberOfBytesRead += sizeof(int);
164 numberOfVertices = Read<int32_t>(fm);
165
166 numberOfBytesRead += sizeof(int);
167 numberOfSegments = Read<int32_t>(fm);
168
169 unsigned int numberOfBitsPerSegment = log2(numberOfSegments) + 1;
170
171#ifndef TTK_ENABLE_KAMIKAZE
172 // avoid left shift with negative operand
173 if(numberOfBitsPerSegment == 0) {
174 return -2;
175 }
176#endif // TTK_ENABLE_KAMIKAZE
177
178 // [MEDIUM] TODO: support long int
179 if(numberOfBitsPerSegment > 32)
180 return -3;
181
182 // Decode
183 int currentCell = 0;
184 int offset = 0;
185 int maskerRank = 0;
186 int oldCompressedInt = 0;
187
188 while(currentCell < numberOfVertices) {
189
190 int compressedInt;
191 numberOfBytesRead += sizeof(int);
192 compressedInt = Read<int32_t>(fm);
193
194 while(offset + numberOfBitsPerSegment <= 32) {
195
196 // Size of segment < size of compressed int
197 int currentSegment = compressedInt;
198
199 if(maskerRank == 0) {
200 currentSegment <<= (32 - offset - numberOfBitsPerSegment);
201
202 if(currentSegment < 0) {
203 currentSegment &= 2147483647;
204 currentSegment >>= (32 - numberOfBitsPerSegment);
205 currentSegment |= (1 << (numberOfBitsPerSegment - 1));
206 } else {
207 currentSegment >>= (32 - numberOfBitsPerSegment);
208 }
209
210 offset += numberOfBitsPerSegment;
211 }
212
213 // Got overlapping mask.
214 else {
215 currentSegment <<= (32 - offset);
216 if(currentSegment < 0) {
217 currentSegment &= 2147483647;
218 currentSegment >>= (32 - numberOfBitsPerSegment);
219 currentSegment |= (1 << (numberOfBitsPerSegment - 1));
220 } else {
221 currentSegment >>= (32 - numberOfBitsPerSegment);
222 }
223
224 int nextSegment = currentSegment;
225
226 if(oldCompressedInt < 0) {
227 oldCompressedInt &= 2147483647;
228 oldCompressedInt >>= maskerRank;
229 oldCompressedInt |= (1 << (32 - maskerRank - 1));
230 } else {
231 oldCompressedInt >>= maskerRank;
232 }
233
234 currentSegment = nextSegment | oldCompressedInt;
235 maskerRank = 0;
236 }
237
238 segmentation.push_back(currentSegment);
239 currentCell++; // Go to next cell.
240 }
241
242 // Overlapping mask into next container.
243 {
244 oldCompressedInt = compressedInt;
245 if(offset == 32) {
246 maskerRank = 0;
247 } else {
248 maskerRank = offset;
249 offset += numberOfBitsPerSegment;
250 }
251 offset %= 32;
252 }
253 }
254
255 return numberOfBytesRead;
256}
257
258// Returns number of bytes written.
260 FILE *fm,
261 const std::vector<int> &segmentation,
262 int numberOfVertices,
263 int numberOfSegments) const {
264
265 int numberOfBytesWritten = 0;
266
267 // Compute number of bits per segment
268 // (can be deduced at read-time from numberOfSegments)
269 unsigned int numberOfBitsPerSegment = log2(numberOfSegments) + 1;
270
271 // [MEDIUM] TODO: support long int
272 if(numberOfBitsPerSegment > 32)
273 return -3;
274
275 // Encode
276 int currentCell = 0;
277 int offset = 0;
278 int maskerRank = 0;
279 while(currentCell < numberOfVertices) {
280
281 // Create next container.
282 int compressedInt = 0;
283
284 // Write regularly all segments until one overlaps
285 // two containers.
286 while(offset + numberOfBitsPerSegment <= 32) {
287
288 // out-of-bounds here if segmentation.size() == numberOfVertices
289 // (segmentation allocated in compressForPersistenceDiagram)
290 int currentSegment = segmentation[currentCell];
291
292 // If applicable, fill last part of current segment.
293 if(maskerRank != 0) {
294 // Always a positive int.
295 currentSegment = currentSegment >> (numberOfBitsPerSegment - offset);
296 // (numberOfBitsPerSegment - maskerRank - 1);
297 maskerRank = 0;
298 compressedInt |= currentSegment;
299
300 } else {
301 int cursor = (currentSegment << offset); // 0es after <<
302 compressedInt |= cursor;
303 offset += numberOfBitsPerSegment;
304 }
305
306 currentCell++; // Next cell.
307 }
308
309 // Test for overflow filling last part of current container.
310 if(currentCell >= numberOfVertices) {
311 numberOfBytesWritten += sizeof(int);
312 Write<int32_t>(fm, compressedInt);
313 break;
314 }
315
316 // Write current segment into last part of current container,
317 // to be continued into next container.
318 {
319 int currentSegment = segmentation[currentCell];
320
321 if(offset == 32) {
322 // currentCell++;
323 } else {
324 int cursor = (currentSegment << offset);
325 compressedInt = compressedInt | cursor;
326
327 maskerRank = 32 - offset;
328 offset += numberOfBitsPerSegment;
329 }
330
331 offset %= 32;
332 }
333
334 // Dump current container.
335 numberOfBytesWritten += sizeof(int);
336 Write<int32_t>(fm, compressedInt);
337 }
338
339 return numberOfBytesWritten;
340}
341
343 FILE *fm,
344 std::vector<std::tuple<double, int>> &mappings,
345 std::vector<std::tuple<double, int>> &mappingsSortedPerValue,
346 std::vector<std::tuple<int, double, int>> &constraints,
347 double &min,
348 double &max,
349 int &nbConstraints) const {
350
351 int numberOfBytesRead = 0;
352
353 // 1.a. Read mapping.
354 int mappingSize;
355 numberOfBytesRead += sizeof(int);
356 mappingSize = Read<int32_t>(fm);
357
358 for(int i = 0; i < mappingSize; ++i) {
359 int idv;
360 numberOfBytesRead += sizeof(int);
361 idv = Read<int32_t>(fm);
362
363 double value;
364 numberOfBytesRead += sizeof(double);
365 value = Read<double>(fm);
366
367 mappings.emplace_back(value, idv);
368 mappingsSortedPerValue.emplace_back(value, idv);
369 }
370
371 // Sort mapping.
372 std::sort(mappings.begin(), mappings.end(), cmp);
373 std::sort(mappingsSortedPerValue.begin(), mappingsSortedPerValue.end(), cmp2);
374
375 // 1.b. Read constraints.
376 numberOfBytesRead += sizeof(int);
377 nbConstraints = Read<int32_t>(fm);
378
379 for(int i = 0; i < nbConstraints; ++i) {
380 int idVertex;
381 double value;
382 int vertexType;
383
384 numberOfBytesRead += sizeof(int);
385 idVertex = Read<int32_t>(fm);
386
387 numberOfBytesRead += sizeof(double);
388 value = Read<double>(fm);
389
390 numberOfBytesRead += sizeof(int);
391 vertexType = Read<int32_t>(fm);
392
393 if(i == 0) {
394 min = value;
395 max = value;
396 }
397
398 if(value < min)
399 min = value;
400 if(value > max)
401 max = value;
402
403 constraints.emplace_back(idVertex, value, vertexType);
404 }
405
406 return numberOfBytesRead;
407}
408
410 FILE *fm,
411 std::vector<std::tuple<double, int>> &mapping,
412 std::vector<std::tuple<int, double, int>> &constraints) const {
413
414 int numberOfBytesWritten = 0;
415
416 // Size.
417 auto mappingSize = (int)mapping.size();
418 numberOfBytesWritten += sizeof(int);
419 Write<int32_t>(fm, mappingSize);
420
421 // Segmentation values for each particular index.
422 for(int i = 0; i < mappingSize; ++i) {
423 std::tuple<double, int> t = mapping[i];
424 int idv = std::get<1>(t);
425 numberOfBytesWritten += sizeof(int);
426 Write<int32_t>(fm, idv);
427
428 auto value = std::get<0>(t);
429 numberOfBytesWritten += sizeof(double);
430 Write<double>(fm, value);
431 }
432
433 auto nbConstraints = (int)constraints.size();
434 numberOfBytesWritten += sizeof(int);
435 Write<int32_t>(fm, nbConstraints);
436
437 for(int i = 0; i < nbConstraints; ++i) {
438 std::tuple<int, double, int> t = constraints[i];
439 int idVertex = std::get<0>(t);
440 auto value = std::get<1>(t);
441 int vertexType = std::get<2>(t);
442
443 numberOfBytesWritten += sizeof(int);
444 Write<int32_t>(fm, idVertex);
445
446 numberOfBytesWritten += sizeof(double);
447 Write<double>(fm, value);
448
449 numberOfBytesWritten += sizeof(int);
450 Write<int32_t>(fm, vertexType);
451 }
452
453 return numberOfBytesWritten;
454}
455
456int ttk::TopologicalCompression::ComputeTotalSizeForPersistenceDiagram(
457 std::vector<std::tuple<double, int>> &mapping,
458 std::vector<std::tuple<int, double, int>> &criticalConstraints,
459 bool zfpOnly,
460 int nSegments,
461 int nVertices,
462 double zfpTolerance) const {
463
464 int totalSize = 0;
465
466 if(!zfpOnly) {
467 // Topological segments.
468 int numberOfBitsPerSegment = log2(nSegments) + 1;
469 double nbCharPerSegment = (double)numberOfBitsPerSegment / 8.0;
470 totalSize += (sizeof(int) * 2 + std::ceil(nbCharPerSegment * nVertices));
471
472 // Geometrical mapping.
473 auto mappingSize = (int)mapping.size();
474 auto constraintsSize = (int)criticalConstraints.size();
475 totalSize += (mappingSize) * (sizeof(int) + sizeof(double)) + sizeof(int);
476 totalSize
477 += (constraintsSize) * (2 * sizeof(int) + sizeof(double)) + sizeof(int);
478 }
479
480 // conservative estimate of the ZFP buffer (no compression at all...)
481 totalSize += zfpTolerance > 0.0 ? nVertices * sizeof(double) : 0 + 2;
482
483 return totalSize;
484}
485
486int ttk::TopologicalCompression::WritePersistenceTopology(FILE *fm) {
487 int numberOfBytesWritten = 0;
488
489 int numberOfVertices = getNbVertices();
490 int numberOfSegments = getNbSegments();
491
492 // Test arguments.
493 if(numberOfSegments < 1)
494 return -1;
495
496 numberOfBytesWritten += sizeof(int);
497 Write<int32_t>(fm, numberOfVertices);
498
499 numberOfBytesWritten += sizeof(int);
500 Write<int32_t>(fm, numberOfSegments);
501
502 numberOfBytesWritten += WriteCompactSegmentation(
503 fm, getSegmentation(), numberOfVertices, numberOfSegments);
504
505 rawFileLength += numberOfBytesWritten;
506
507 return 0;
508}
509
510int ttk::TopologicalCompression::WritePersistenceGeometry(FILE *fm,
511 int *dataExtent,
512 bool zfpOnly,
513 double zfpTolerance,
514 double *toCompress) {
515 int numberOfBytesWritten = 0;
516
517 if(!zfpOnly) {
518 // 1. Write segmentation map.
519 // 2. Write critical constraints.
520 numberOfBytesWritten
521 += WritePersistenceIndex(fm, mapping_, criticalConstraints_);
522 }
523
524 this->printMsg("Wrote raw geometry.");
525
526 if(zfpTolerance >= 0.0) {
527#ifdef TTK_ENABLE_ZFP
528 // (1. or 3.) Write zfp-compressed array.
529 int nx = 1 + dataExtent[1] - dataExtent[0];
530 int ny = 1 + dataExtent[3] - dataExtent[2];
531 int nz = 1 + dataExtent[5] - dataExtent[4];
532
533 std::vector<double> dataVector(toCompress, toCompress + (nx * ny * nz));
534 numberOfBytesWritten
535 += CompressWithZFP(fm, false, dataVector, nx, ny, nz, zfpTolerance);
536
537#else
538 TTK_FORCE_USE(dataExtent);
539 TTK_FORCE_USE(toCompress);
540
541 this->printErr("Attempted to write with ZFP but ZFP is not installed.");
542 return -5;
543#endif
544 }
545
546 rawFileLength += numberOfBytesWritten;
547
548 return 0;
549}
550
551int ttk::TopologicalCompression::ReadPersistenceTopology(FILE *fm) {
552 int numberOfSegments;
553 int numberOfVertices;
554
555 int numberOfBytesRead = ReadCompactSegmentation(
556 fm, segmentation_, numberOfVertices, numberOfSegments);
557
558 this->rawFileLength += numberOfBytesRead;
559
560 return 0;
561}
562
564// Other compression methods //
566
567int ttk::TopologicalCompression::ComputeTotalSizeForOther() const {
568 // Should return the number of bytes to be written on the output file
569 // sizeof(char) = 1 (byte)
570 // use sizeof(int), sizeof(double) to get the number of bytes of
571 // the matching structures.
572 return 0;
573}
574
576 // Code me
577 return 0;
578}
579
580int ttk::TopologicalCompression::WriteOtherTopology(
581 FILE *ttkNotUsed(fm)) const {
582 this->printWrn("Writing Other index / topology.");
583 // Code me
584 return 0;
585}
586
587int ttk::TopologicalCompression::WriteOtherGeometry(
588 FILE *ttkNotUsed(fm)) const {
589 this->printWrn("Writing Other buffer / geometry.");
590 // Code me
591 return 0;
592}
593
594int ttk::TopologicalCompression::ReadOtherTopology(FILE *ttkNotUsed(fm)) const {
595 this->printWrn("Reading Other index / topology.");
596 // Code me
597 return 0;
598}
599
600int ttk::TopologicalCompression::ReadOtherGeometry(FILE *ttkNotUsed(fm)) const {
601 this->printWrn("Reading Other buffer / geometry.");
602 // Code me
603 return 0;
604}
605
607// Read/Write File methods //
609
611 int compressionType,
612 bool zfpOnly,
613 const char *sqMethod,
614 int dataType,
615 int *dataExtent,
616 double *dataSpacing,
617 double *dataOrigin,
618 double *data,
619 double tolerance,
620 double zfpTolerance,
621 const std::string &dataArrayName) {
622 // [->fp] Write metadata.
623 WriteMetaData(fp, compressionType, zfpOnly, sqMethod, dataType, dataExtent,
624 dataSpacing, dataOrigin, tolerance, zfpTolerance,
625 dataArrayName);
626
627#ifdef TTK_ENABLE_ZLIB
628 Write<uint8_t>(fp, true);
629#else
630 Write<uint8_t>(fp, false);
631#endif
632
633 bool usePersistence
634 = compressionType == (int)ttk::CompressionType::PersistenceDiagram;
635 bool useOther = compressionType == (int)ttk::CompressionType::Other;
636
637 int numberOfVertices = 1;
638 for(int i = 0; i < 3; ++i)
639 numberOfVertices *= (1 + dataExtent[2 * i + 1] - dataExtent[2 * i]);
640 NbVertices = numberOfVertices;
641
642 int totalSize = usePersistence ? ComputeTotalSizeForPersistenceDiagram(
643 getMapping(), getCriticalConstraints(), zfpOnly,
644 getNbSegments(), getNbVertices(), zfpTolerance)
645 : useOther ? ComputeTotalSizeForOther()
646 : 0;
647
648 std::vector<char> bbuf(totalSize);
649 char *buf = bbuf.data();
650 size_t len = (size_t)totalSize;
651
652 // #ifndef _MSC_VER
653 // FILE *fm = fmemopen(buf, len, "r+");
654 // #else
655 const std::string s = fileName + std::string(".temp");
656 const char *ffn = s.c_str();
657 FILE *fm = fopen(ffn, "wb");
658 // #endif
659
660 // [->fm] Encode, lossless compress and write topology.
661 if(!(zfpOnly)) {
662 if(usePersistence)
663 WritePersistenceTopology(fm);
664 else if(useOther)
665 WriteOtherTopology(fm);
666 }
667
668 this->printMsg("Topology successfully written to buffer.");
669
670 int status = 0;
671 // [->fm] Write altered geometry.
672 if(usePersistence)
673 status
674 = WritePersistenceGeometry(fm, dataExtent, zfpOnly, zfpTolerance, data);
675 else if(useOther)
676 status = WriteOtherGeometry(fm);
677
678 fclose(fm); // !Close stream to write changes!
679 // #ifdef _MSC_VER
680 fm = fopen(ffn, "rb");
681 int ret = fread(buf, len, sizeof(char), fm);
682 fclose(fm);
683 remove(ffn);
684 // #endif
685
686 if(status == 0) {
687 this->printMsg("Geometry successfully written to buffer.");
688 } else {
689 this->printErr("Geometry was not successfully written to buffer.");
690 fflush(fp);
691 fclose(fp);
692 return -1;
693 }
694
695 // Check computed size vs read size.
696 if(totalSize < rawFileLength) {
697 this->printErr("Invalid total size (" + std::to_string(totalSize) + " vs "
698 + std::to_string(rawFileLength) + ").");
699 }
700
701#ifdef TTK_ENABLE_ZLIB
702 // [fm->ff] Compress fm.
703 auto sourceLen = static_cast<unsigned long>(rawFileLength);
704 const auto source = reinterpret_cast<unsigned char *>(buf);
705 auto destLen = GetZlibDestLen(sourceLen);
706 std::vector<unsigned char> ddest(destLen);
707 CompressWithZlib(false, ddest.data(), destLen, source, sourceLen);
708 this->printMsg("Data successfully compressed.");
709
710 // [fm->fp] Copy fm to fp.
711 Write<uint64_t>(fp, destLen); // Compressed size...
712 Write<uint64_t>(fp, sourceLen);
713 WriteByteArray(fp, ddest.data(), destLen);
714 this->printMsg("Data successfully written to filesystem.");
715
716#else
717 this->printMsg("ZLIB not found, writing raw file.");
718 unsigned char *source = reinterpret_cast<unsigned char *>(buf);
719 unsigned long sourceLen = (unsigned long)rawFileLength;
720 unsigned long destLen = (unsigned long)rawFileLength;
721
722 Write<uint64_t>(fp, destLen); // Compressed size...
723 Write<uint64_t>(fp, sourceLen);
724 WriteByteArray(fp, source, destLen);
725#endif
726
727 fflush(fp);
728 fclose(fp);
729
730 return ret;
731}
732
734 FILE *fp,
735 int compressionType,
736 bool zfpOnly,
737 const char *sqMethod,
738 int dataType,
739 int *dataExtent,
740 double *dataSpacing,
741 double *dataOrigin,
742 double tolerance,
743 double zfpTolerance,
744 const std::string &dataArrayName) {
745
746 // -4. Magic bytes
747 WriteByteArray(fp, magicBytes_, std::strlen(magicBytes_));
748
749 // -3. File format version
750 Write<uint64_t>(fp, formatVersion_);
751
752 // -2. Persistence, or Other
753 Write<int32_t>(fp, compressionType);
754
755 // -1. zfpOnly
756 Write<uint8_t>(fp, zfpOnly);
757
758 // 0. SQ type
759 const char *sq = sqMethod;
760 int sqType = (strcmp(sq, "") == 0) ? 0
761 : (strcmp(sq, "r") == 0 || strcmp(sq, "R") == 0) ? 1
762 : (strcmp(sq, "d") == 0 || strcmp(sq, "D") == 0) ? 2
763 : 3;
764
765 Write<int32_t>(fp, sqType);
766
767 // 1. DataType
768 Write<int32_t>(fp, dataType);
769
770 // 2. Data extent, spacing, origin
771 for(int i = 0; i < 6; ++i)
772 Write<int32_t>(fp, dataExtent[i]);
773
774 for(int i = 0; i < 3; ++i)
775 Write<double>(fp, dataSpacing[i]);
776
777 for(int i = 0; i < 3; ++i)
778 Write<double>(fp, dataOrigin[i]);
779
780 // 4. Tolerance
781 Write<double>(fp, tolerance);
782
783 // 5. ZFP ratio
784 Write<double>(fp, zfpTolerance);
785
786 // 6. Length of array name
787 // (explicit call to unsigned long variant for MSVC compatibility)
788 Write<uint64_t>(fp, dataArrayName.size());
789
790 // 7. Array name (as unsigned chars)
791 WriteByteArray(fp, dataArrayName.c_str(), dataArrayName.size());
792
793 this->printMsg("Metadata successfully written.");
794
795 return 0;
796}
797
799
800 // -4. Magic bytes
801 const auto magicBytesLen{std::strlen(magicBytes_)};
802 std::vector<char> mBytes(magicBytesLen + 1);
803 mBytes[magicBytesLen] = '\0'; // NULL-termination
804 ReadByteArray(fm, mBytes.data(), magicBytesLen);
805
806 // To deal with pre-v1 file format (without scalar field array name)
807 const bool hasMagicBytes = strcmp(mBytes.data(), magicBytes_) == 0;
808 if(!hasMagicBytes) {
809 this->printErr("Could not find magic bytes in input file!");
810 return 1;
811 }
812
813 // -3. File format version
814 const auto fileVersion = Read<uint64_t>(fm);
815 if(fileVersion < this->formatVersion_) {
816 this->printErr("Old format version detected (" + std::to_string(fileVersion)
817 + " vs. " + std::to_string(this->formatVersion_) + ").");
818 this->printErr("Older formats are not supported!");
819 return 1;
820 } else if(fileVersion > this->formatVersion_) {
821 this->printErr("Newer format version detected ("
822 + std::to_string(fileVersion) + " vs. "
823 + std::to_string(this->formatVersion_) + ").");
824 this->printErr("Cannot read file with current TTK, try with to update.");
825 return 1;
826 }
827
828 // -2. Compression type.
829 compressionType_ = Read<int32_t>(fm);
830
831 // -1. ZFP only type.
832 ZFPOnly = Read<uint8_t>(fm);
833
834 // 0. SQ type
835 SQMethodInt = Read<int32_t>(fm);
836
837 // 1. DataType
838 dataScalarType_ = Read<int32_t>(fm);
839 // DataScalarType = VTK_DOUBLE;
840
841 // 2. Data extent, spacing, origin
842 for(int i = 0; i < 6; ++i)
843 dataExtent_[i] = Read<int32_t>(fm);
844
845 for(int i = 0; i < 3; ++i)
846 dataSpacing_[i] = Read<double>(fm);
847
848 for(int i = 0; i < 3; ++i)
849 dataOrigin_[i] = Read<double>(fm);
850
851 // 4. Error tolerance (relative percentage)
852 Tolerance = Read<double>(fm);
853
854 // 5. Lossy compressor ratio
855 ZFPTolerance = Read<double>(fm);
856
857 // 6. Length of array name
858 size_t dataArrayNameLength = Read<uint64_t>(fm);
859
860 // 7. Array name (as unsigned chars)
861 dataArrayName_.resize(dataArrayNameLength + 1);
862 dataArrayName_[dataArrayNameLength] = '\0'; // NULL-termination
863 ReadByteArray(fm, dataArrayName_.data(), dataArrayNameLength);
864
865 return 0;
866}
#define TTK_FORCE_USE(x)
Force the compiler to use the function/method parameter.
Definition: BaseClass.h:57
#define ttkNotUsed(x)
Mark function/method parameters that are not used in the function body at all.
Definition: BaseClass.h:47
void setDebugMsgPrefix(const std::string &prefix)
Definition: Debug.h:364
int ReadPersistenceIndex(FILE *fm, std::vector< std::tuple< double, int > > &mappings, std::vector< std::tuple< double, int > > &mappingsSortedPerValue, std::vector< std::tuple< int, double, int > > &constraints, double &min, double &max, int &nbConstraints) const
int WriteCompactSegmentation(FILE *fm, const std::vector< int > &segmentation, int numberOfVertices, int numberOfSegments) const
int WritePersistenceIndex(FILE *fm, std::vector< std::tuple< double, int > > &mapping, std::vector< std::tuple< int, double, int > > &constraints) const
int WriteToFile(FILE *fp, int compressionType, bool zfpOnly, const char *sqMethod, int dataType, int *dataExtent, double *dataSpacing, double *dataOrigin, double *data, double tolerance, double zfpTolerance, const std::string &dataArrayName)
int ReadCompactSegmentation(FILE *fm, std::vector< int > &segmentation, int &numberOfVertices, int &numberOfSegments) const
int WriteMetaData(FILE *fp, int compressionType, bool zfpOnly, const char *sqMethod, int dataType, int *dataExtent, double *dataSpacing, double *dataOrigin, double tolerance, double zfpTolerance, const std::string &dataArrayName)
static unsigned int log2(int val)
printMsg(debug::output::GREEN+"                           "+debug::output::ENDCOLOR+debug::output::GREEN+"▒"+debug::output::ENDCOLOR+debug::output::GREEN+"▒▒▒▒▒▒▒▒▒▒▒▒▒░"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)