FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
voxel_map.hpp
1// FEAT3: Finite Element Analysis Toolbox, Version 3
2// Copyright (C) 2010 by Stefan Turek & the FEAT group
3// FEAT3 is released under the GNU General Public License version 3,
4// see the file 'copyright.txt' in the top level directory for details.
5
6#pragma once
7
8// includes, FEAT
11#include <kernel/util/dist.hpp>
12#include <kernel/util/dist_file_io.hpp>
13#include <kernel/geometry/cgal.hpp>
14#include <kernel/geometry/atlas/chart.hpp>
15
16// includes, system
17#include <array>
18#include <vector>
19#include <iostream>
20#include <cstdint>
21#include <cstring>
22
23// includes, thirdparty
24#ifdef FEAT_HAVE_FPARSER
25#include <fparser.hh>
26#endif // FEAT_HAVE_FPARSER
27
28namespace FEAT
29{
30 namespace Geometry
31 {
36 public FileError
37 {
38 public:
39 explicit VoxelMapFileError(const String& filename, const String& msg) :
40 FileError(filename.empty() ? msg : (filename + ": " + msg))
41 {
42 }
43 }; // class VoxelMapFileError
44
49 public ParseError
50 {
51 public:
52 explicit VoxelMapFormulaParseError(const String& msg) :
53 ParseError(msg)
54 {
55 }
56 }; // class VoxelMapFormulaParseError
57
69 template<typename CoordType_, int dim_>
71 {
72 public:
74 typedef CoordType_ CoordType;
77
79 virtual ~VoxelMasker()
80 {
81 }
82
101 static CoordType x_coord(const CoordType x_min, const CoordType x_max, const std::size_t i, const std::size_t n)
102 {
103 return x_min + (x_max - x_min) * CoordType(i) / CoordType(n - 1u);
104 }
105
130 virtual void mask_line(std::vector<int>& mask, const CoordType x_min, const CoordType x_max, const PointType& point) = 0;
131 }; // class VoxelMasker<...>
132
133#if defined(FEAT_HAVE_CGAL) || defined(DOXYGEN)
141 template<typename CoordType_>
143 public VoxelMasker<CoordType_, 3>
144 {
145 public:
147 using typename BaseClass::CoordType;
148 using typename BaseClass::PointType;
149
150 private:
153 const bool _invert;
154
155 public:
165 explicit VoxelCGALMasker(const Geometry::CGALWrapper<CoordType_>& cgal_wrapper, bool invert) :
166 _cgal_wrapper(cgal_wrapper),
167 _invert(invert)
168 {
169 }
170
171 virtual void mask_line(std::vector<int>& mask, const CoordType x_min, const CoordType x_max, const PointType& point) override
172 {
173 if(mask.empty())
174 return;
175
176 const std::size_t nv = mask.size();
177 for(std::size_t i(0); i < nv; ++i)
178 {
179 mask[i] = (this->_cgal_wrapper.point_inside(BaseClass::x_coord(x_min, x_max, i, nv),
180 point[1], point[2]) ? int(!_invert) : int(_invert));
181 }
182 }
183 }; // class VoxelCGALMasker<...>
184#endif // FEAT_HAVE_CGAL || DOXYGEN
185
193 template<typename MeshType>
195 public VoxelMasker<typename MeshType::CoordType, MeshType::shape_dim>
196 {
197 public:
199 using typename BaseClass::CoordType;
200 using typename BaseClass::PointType;
201
202 private:
204 const bool _invert;
205
206 public:
216 explicit VoxelChartMasker(const Geometry::Atlas::ChartBase<MeshType>& chart, bool invert) :
217 _chart(chart),
218 _invert(invert)
219 {
220 }
221
222 virtual void mask_line(std::vector<int>& mask, const CoordType x_min, const CoordType x_max, const PointType& point) override
223 {
224 if(mask.empty())
225 return;
226
227 PointType pt(point);
228
229 const std::size_t nv = mask.size();
230 for(std::size_t i(0); i < nv; ++i)
231 {
232 pt[0] = BaseClass::x_coord(x_min, x_max, i, nv);
233 mask[i] = (_chart.signed_dist(pt) <= CoordType(0) ? int(!_invert) : int(_invert));
234 }
235 }
236 }; // class VoxelChartMasker<...>
237
247 template<typename Lambda_, typename CoordType_, int dim_>
249 public VoxelMasker<CoordType_, dim_>
250 {
251 public:
253 using typename BaseClass::CoordType;
254 using typename BaseClass::PointType;
255
256 public:
258 Lambda_ _lambda;
259
268 explicit VoxelLambdaMasker(Lambda_&& lambda) :
269 _lambda(std::forward<Lambda_>(lambda))
270 {
271 }
272
273 virtual void mask_line(std::vector<int>& mask, const CoordType x_min, const CoordType x_max, const PointType& point) override
274 {
275 if(mask.empty())
276 return;
277
278 PointType pt(point);
279 // define a const reference to ensure that the lambda expression does not modify the point
280 const PointType& cpt(pt);
281
282 const std::size_t nv = mask.size();
283 for(std::size_t i(0); i < nv; ++i)
284 {
285 pt[0] = BaseClass::x_coord(x_min, x_max, i, nv);
286 mask[i] = (_lambda(cpt) ? 1 : 0);
287 }
288 }
289 }; // class VoxelLambdaMasker<...>
290
291#if defined(FEAT_HAVE_FPARSER) || defined(DOXYGEN)
301 template<int dim_>
303 public VoxelMasker<double, dim_>
304 {
305 public:
307 using typename BaseClass::CoordType;
308 using typename BaseClass::PointType;
309
310 public:
314 ::FunctionParser _parser;
315
324 explicit VoxelFormulaMasker(const String& formula) :
325 _formula(formula),
326 _parser()
327 {
328 _parser.AddConstant("pi", Math::pi<double>());
329 _parser.AddConstant("eps", Math::eps<double>());
330
331 String vars("x");
332 if(dim_ > 1) vars += ",y";
333 if(dim_ > 2) vars += ",z";
334
335 // try to parse the function
336 const int ret = _parser.Parse(_formula.c_str(), vars.c_str());
337 if(ret >= 0)
338 {
339 String msg(_parser.ErrorMsg());
340 msg.append("\n>>> '");
341 msg.append(_formula);
342 msg.append("'");
343 throw VoxelMapFormulaParseError(msg);
344 }
345
346 // optimize the parsed function
347 _parser.Optimize();
348 }
349
350 virtual void mask_line(std::vector<int>& mask, const CoordType x_min, const CoordType x_max, const PointType& point) override
351 {
352 if(mask.empty())
353 return;
354
355 PointType pt(point);
356
357 const std::size_t nv = mask.size();
358 for(std::size_t i(0); i < nv; ++i)
359 {
360 pt[0] = BaseClass::x_coord(x_min, x_max, i, nv);
361 mask[i] = (_parser.Eval(pt.v) > 0.0 ? 1 : 0);
362 }
363 }
364 }; // class VoxelFormulaMasker<...>
365#endif // FEAT_HAVE_FPARSER || DOXYGEN
366
405 {
406 public:
408 typedef std::int64_t i64;
409
411 typedef std::uint64_t u64;
412
414 static constexpr u64 magic_number = 0x70614D6C65786F56ull; // "VoxelMap"
415
417 static constexpr u64 header_size = 136ull;
418
420 static constexpr i64 unit_size = 1'000'000'000;
421
424 {
425 u64 magic_number; //< "VoxelMap" = 0x70614D6C65786F56ll
426 u64 header_size; //< 136 bytes
427 i64 min_x; //< minimum X-coordinate in nanometer
428 i64 max_x; //< maximum X-coordinate in nanometer
429 u64 num_x; //< number of points in X dimension
430 u64 stride_line; //< number of bytes for a single uncompressed X-line; a multiple of 16; usually stride_line = (((num_x + 7ull)/8ull + 15ull) & ~15ull)
431 i64 min_y; //< minimum Y-coordinate in nanometer
432 i64 max_y; //< maximum Y-coordinate in nanometer
433 u64 num_y; //< number of points in Y dimension
434 u64 stride_plane; //< number of bytes for a single uncompressed XY-plane; a multiple of 16; usually stride_plane = stride_line * num_y
435 i64 min_z; //< minimum Z-coordinate in nanometer
436 i64 max_z; //< maximum Z-coordinate in nanometer
437 u64 num_z; //< number of points in Z dimension
438 u64 stride_volume; //< number of bytes for a single uncompressed XYZ-volume; a multiple of 16; usually stride_volume = stride_plane * num_z
439 u64 coverage; //< coverage of domain in voxel map, relative to unit size
440 u64 planes_per_block; //< number of planes per compression block (0 if uncompressed)
441 u64 num_blocks; //< total number of compression blocks (0 if uncompressed)
442 }; // struct FileHeader: 136 bytes
443
445 static_assert(sizeof(FileHeader) == header_size, "invalid FileHeader size");
446
449 {
450 // compute number of bytes by rounding to next multiple of 8 then dividing by 8,
451 // afterwards round up to next multiple of 16
452 return (((num_x + 7ull)/8ull + 15ull) & ~15ull);
453 }
454
462 {
463 public:
464 u64 filesize; //< total size of written file in bytes
465 u64 compress_block_size; //< chosen maximum compression block size in MB
466 u64 compress_level; //< chosen compression level
467 u64 num_compress; //< number of compression blocks
468 u64 compressed_size; //< total compressed buffer size in bytes
469
470 WriteResult() :
471 filesize(0u),
472 compress_block_size(0u),
473 compress_level(0u),
474 num_compress(0u),
475 compressed_size(0u)
476 {
477 }
478
479 explicit WriteResult(u64 fs, u64 cbs = 0u, u64 cl = 0u, u64 nc = 0u, u64 cs = 0u) :
480 filesize(fs),
481 compress_block_size(cbs),
482 compress_level(cl),
483 num_compress(nc),
484 compressed_size(cs)
485 {
486 }
487
489 operator bool() const
490 {
491 return filesize > u64(0);
492 }
493 }; // class WriteResult
494
502 {
503 public:
504 u64 filesize; //< total size of read file in bytes
505 u64 num_compress; //< number of compression blocks
506 u64 compressed_size; //< total compressed buffer size in bytes
507
508 ReadResult() :
509 filesize(0u),
510 num_compress(0u),
511 compressed_size(0u)
512 {
513 }
514
515 explicit ReadResult(u64 fs, u64 nc = 0u, u64 cs = 0u) :
516 filesize(fs),
517 num_compress(nc),
518 compressed_size(cs)
519 {
520 }
521
523 operator bool() const
524 {
525 return filesize > u64(0);
526 }
527 }; // class ReadResult
528
529 protected:
533 std::array<i64, 3u> _bbox_min, _bbox_max;
535 std::array<u64, 3u> _num_points;
545 std::vector<char> _voxel_map;
550
551 public:
553 VoxelMap();
554
556 VoxelMap(const VoxelMap&) = delete;
557 VoxelMap& operator=(const VoxelMap&) = delete;
558
561
563 VoxelMap& operator=(VoxelMap&& other);
564
566 virtual ~VoxelMap();
567
577 void set_bounding_box_2d(Real x_min, Real x_max, Real y_min, Real y_max);
578
591 void set_bounding_box_3d(Real x_min, Real x_max, Real y_min, Real y_max, Real z_min, Real z_max);
592
595 {
596 XASSERT((dim >= 0) && (dim < 3));
597 return Real(this->_bbox_min[std::size_t(dim)]) / Real(unit_size);
598 }
599
602 {
603 XASSERT((dim >= 0) && (dim < 3));
604 return Real(this->_bbox_max[std::size_t(dim)]) / Real(unit_size);
605 }
606
609
622 {
623 this->_out_of_bounds_value = value;
624 }
625
628 {
629 return this->_out_of_bounds_value;
630 }
631
638 void set_num_points(Index num_x, Index num_y, Index num_z = 0u);
639
641 Index get_num_points(int dim) const
642 {
643 return Index(this->_num_points.at(Index(dim)));
644 }
645
655 void set_resolution(Real max_res);
656
659 {
660 return Index(this->_num_points[0] * this->_num_points[1] * this->_num_points[2]);
661 }
662
665 {
666 return this->_stride_line;
667 }
668
671 {
672 return this->_stride_plane;
673 }
674
677 {
678 return u64(this->_voxel_map.size());
679 }
680
682 const std::vector<char>& get_map() const
683 {
684 return this->_voxel_map;
685 }
686
696 {
697 // we store the coverage relative to unit size
698 return Real(this->_coverage) / Real(unit_size);
699 }
700
703 {
705 }
706
728 template<typename Coord_, int dim_>
729 void compute_map(const Dist::Comm& comm, VoxelMasker<Coord_, dim_>& masker, bool gather_to_all = true)
730 {
731 XASSERT(!_voxel_map.empty());
732 this->_compute_voxel_map(comm, masker, gather_to_all);
733 }
734
759 template<typename MeshType_>
760 void compute_map_from_chart(const Dist::Comm& comm, const Geometry::Atlas::ChartBase<MeshType_>& chart, bool invert, bool gather_to_all = true)
761 {
762 XASSERT(!_voxel_map.empty());
763 VoxelChartMasker<MeshType_> masker(chart, invert);
764 this->_compute_voxel_map(comm, masker, gather_to_all);
765 }
766
790 template<typename Lambda_>
791 void compute_map_from_lambda_2d(const Dist::Comm& comm, Lambda_&& lambda, bool gather_to_all = true)
792 {
793 VoxelLambdaMasker<Lambda_, Real, 2> masker(std::forward<Lambda_>(lambda));
794 this->_compute_voxel_map(comm, masker, gather_to_all);
795 }
796
820 template<typename Lambda_>
821 void compute_map_from_lambda_3d(const Dist::Comm& comm, Lambda_&& lambda, bool gather_to_all = true)
822 {
823 VoxelLambdaMasker<Lambda_, Real, 3> masker(std::forward<Lambda_>(lambda));
824 this->_compute_voxel_map(comm, masker, gather_to_all);
825 }
826
849 void compute_map_from_formula_2d(const Dist::Comm& comm, const String& formula, bool gather_to_all = true);
850
873 void compute_map_from_formula_3d(const Dist::Comm& comm, const String& formula, bool gather_to_all = true);
874
900 void compute_map_from_off_3d(const Dist::Comm& comm, const String& filename, bool invert, bool gather_to_all = true);
901
927 void compute_map_from_off_3d(const Dist::Comm& comm, std::istream& is, bool invert, bool gather_to_all = true);
928
948 WriteResult write(const String& filename, const u64 compress_block_size = 128u, const int compress_level = 9) const;
949
969 WriteResult write(std::ostream& os, const u64 compress_block_size = 128u, const int compress_level = 9) const;
970
984 ReadResult read(const Dist::Comm& comm, const String& filename);
985
995 ReadResult read(std::istream& is, const String& filename = "");
996
1006 bool check_point(u64 ix, u64 iy = 0u, u64 iz = 0u) const
1007 {
1008 ASSERT((ix < this->_num_points[0]) || ((this->_num_points[0] == 0u) && (ix == 0u)));
1009 ASSERT((iy < this->_num_points[1]) || ((this->_num_points[1] == 0u) && (iy == 0u)));
1010 ASSERT((iz < this->_num_points[2]) || ((this->_num_points[2] == 0u) && (iz == 0u)));
1011 return this->_check_point(i64(ix), i64(iy), i64(iz));
1012 }
1013
1024 template<typename Coord_, int dim_>
1026 {
1027 // convert point to internal units
1028 std::array<i64, dim_> ipt;
1029 for(int i(0); i < dim_; ++i)
1030 ipt[std::size_t(i)] = i64(point[i] * Coord_(unit_size));
1031 return this->_check_point_nearest(ipt);
1032 }
1033
1043 template<typename Coord_, int dim_>
1045 {
1046 // convert point to internal units
1047 std::array<i64, dim_> ipt;
1048 for(int i(0); i < dim_; ++i)
1049 ipt[std::size_t(i)] = i64(point[i] * Coord_(unit_size));
1050 return this->_sample_point(ipt);
1051 }
1052
1069 template<typename Coord_, int dim_>
1070 bool check_box(const Tiny::Vector<Coord_, dim_>& box_min, const Tiny::Vector<Coord_, dim_>& box_max) const
1071 {
1072 // convert coordinates to map indices
1073 std::array<u64, dim_> ibox_min, ibox_max;
1074 for(std::size_t i(0); i < std::size_t(dim_); ++i)
1075 {
1076 // make sure the map indices do not exceed the bounding box of the voxel map
1077 i64 imin = _map_coord_idx_lower(i64(box_min[int(i)] * Coord_(unit_size)), i);
1078 if(imin < i64(0))
1079 {
1080 if(this->_out_of_bounds_value)
1081 return true;
1082 ibox_min[i] = u64(0);
1083 }
1084 else
1085 ibox_min[i] = u64(imin);
1086
1087 i64 imax = _map_coord_idx_upper(i64(box_max[int(i)] * Coord_(unit_size)), i);
1088 if(i64(this->_num_points[i]) < imax + 1)
1089 {
1090 if(this->_out_of_bounds_value)
1091 return true;
1092 ibox_max[i] = i64(this->_num_points[i]) - 1;
1093 }
1094 else
1095 ibox_max[i] = u64(imax);
1096 }
1097
1098 return this->_check_box(ibox_min, ibox_max);
1099 }
1100
1121 template<typename Coord_, int dim_>
1123 {
1124 std::array<i64, dim_> ibox_min, ibox_max;
1125 for(std::size_t i(0); i < std::size_t(dim_); ++i)
1126 {
1127 ibox_min[i] = i64(box_min[int(i)] * Coord_(unit_size));
1128 ibox_max[i] = i64(box_max[int(i)] * Coord_(unit_size));
1129 }
1130 return this->_sample_box(ibox_min, ibox_max);
1131 }
1132
1147 void export_to_bmp(const String& filename_prefix) const;
1148
1165 void export_plane_to_bmp(const String& filename, Real z_coord) const;
1166
1183 void export_plane_to_bmp(std::ostream& os, Real z_coord) const;
1184
1204 void render_to_bmp(const String& filename_prefix, Index width, Index height, Index depth) const;
1205
1225 void render_plane_to_bmp(const String& filename, Index width, Index height, Real z_min, Real z_max) const;
1226
1246 void render_plane_to_bmp(std::ostream& os, Index width, Index height, Real z_min, Real z_max) const;
1247
1248 protected:
1262 u64 _map_coord_idx_nearest(i64 xyz, std::size_t sdim) const;
1263
1281 i64 _map_coord_idx_lower(i64 xyz, std::size_t sdim) const;
1282
1300 i64 _map_coord_idx_upper(i64 xyz, std::size_t sdim) const;
1301
1320 Real _calc_sample_rate(i64 xyz, i64 idx, std::size_t sdim) const;
1321
1323 bool _check_point(i64 xidx, i64 yidx, i64 zidx) const;
1324
1335 bool _check_point_nearest(const std::array<i64, 1>& p) const;
1336
1347 bool _check_point_nearest(const std::array<i64, 2>& p) const;
1348
1359 bool _check_point_nearest(const std::array<i64, 3>& p) const;
1360
1369 bool _check_box(const std::array<u64, 1>& box_min, const std::array<u64, 1>& box_max) const;
1370
1379 bool _check_box(const std::array<u64, 2>& box_min, const std::array<u64, 2>& box_max) const;
1380
1389 bool _check_box(const std::array<u64, 3>& box_min, const std::array<u64, 3>& box_max) const;
1390
1392 Real _sample_point_1d_x(i64 px, i64 xidx, i64 yidx = i64(0), i64 zidx = i64(0)) const;
1393
1395 Real _sample_point_1d_y(i64 py, i64 xidx, i64 yidx, i64 zidx = i64(0)) const;
1396
1398 Real _sample_point_1d_z(i64 pz, i64 xidx, i64 yidx, i64 zidx) const;
1399
1401 Real _sample_point_2d(i64 px, i64 py, i64 xidx, i64 yidx, i64 zidx = i64(0)) const;
1402
1404 Real _sample_point_3d(i64 px, i64 py, i64 pz, i64 xidx, i64 yidx, i64 zidx) const;
1405
1415 Real _sample_point(const std::array<i64, 1>& p) const;
1416
1426 Real _sample_point(const std::array<i64, 2>& p) const;
1427
1437 Real _sample_point(const std::array<i64, 3>& p) const;
1438
1440 Real _sample_box_1d(i64 px0, i64 px1, i64 xidx0, i64 xidx1, i64 yidx = i64(0), i64 zidx = i64(0)) const;
1441
1443 Real _sample_box_2d(i64 px0, i64 px1, i64 py0, i64 py1, i64 xidx0, i64 xidx1, i64 yidx0, i64 yidx1, i64 zidx = i64(0)) const;
1444
1446 Real _sample_box_3d(i64 px0, i64 px1, i64 py0, i64 py1, i64 pz0, i64 pz1, i64 xidx0, i64 xidx1, i64 yidx0, i64 yidx1, i64 zidx0, i64 zidx1) const;
1447
1456 Real _sample_box(const std::array<i64, 1>& box_min, const std::array<i64, 1>& box_max) const;
1457
1466 Real _sample_box(const std::array<i64, 2>& box_min, const std::array<i64, 2>& box_max) const;
1467
1476 Real _sample_box(const std::array<i64, 3>& box_min, const std::array<i64, 3>& box_max) const;
1477
1482
1492 void _compress_voxel_map_line(const std::vector<int>& mask, const u64 line);
1493
1509 template<typename CoordType_>
1510 void _compute_voxel_map_lines(VoxelMasker<CoordType_, 1>& masker, u64 DOXY(beg), u64 DOXY(end), u64 DOXY(offset))
1511 {
1512 XASSERTM(_num_points[1] == 1ull, "cannot use a 1D VoxelMasker to create a 2D/3D voxel mask");
1513 XASSERTM(_num_points[2] == 1ull, "cannot use a 1D VoxelMasker to create a 2D/3D voxel mask");
1514 const CoordType_ x_min = CoordType_(_bbox_min[0]) / CoordType_(unit_size);
1515 const CoordType_ x_max = CoordType_(_bbox_max[0]) / CoordType_(unit_size);
1516 std::vector<int> line_mask(this->_num_points[0], 0);
1518 masker.mask_line(line_mask, x_min, x_max, coords);
1519 this->_compress_voxel_map_line(line_mask, 0);
1520 }
1521
1539 template<typename CoordType_>
1541 {
1542 XASSERTM(_num_points[2] == 1ull, "cannot use a 2D VoxelMasker to create a 3D voxel mask");
1543 const CoordType_ x_min = CoordType_(_bbox_min[0]) / CoordType_(unit_size);
1544 const CoordType_ x_max = CoordType_(_bbox_max[0]) / CoordType_(unit_size);
1545 const CoordType_ y_min = CoordType_(_bbox_min[1]) / CoordType_(unit_size);
1546 const CoordType_ y_max = CoordType_(_bbox_max[1]) / CoordType_(unit_size);
1547 std::vector<int> line_mask(this->_num_points[0], 0);
1549
1550 for(u64 i = beg; i < end; ++i)
1551 {
1552 coords[1] = y_min + (y_max - y_min) * CoordType_(i % this->_num_points[1]) / CoordType_(this->_num_points[1] - 1u);
1553 masker.mask_line(line_mask, x_min, x_max, coords);
1554 this->_compress_voxel_map_line(line_mask, i - offset);
1555 }
1556 }
1557
1575 template<typename CoordType_>
1577 {
1578 const CoordType_ x_min = CoordType_(_bbox_min[0]) / CoordType_(unit_size);
1579 const CoordType_ x_max = CoordType_(_bbox_max[0]) / CoordType_(unit_size);
1580 const CoordType_ y_min = CoordType_(_bbox_min[1]) / CoordType_(unit_size);
1581 const CoordType_ y_max = CoordType_(_bbox_max[1]) / CoordType_(unit_size);
1582 const CoordType_ z_min = CoordType_(_bbox_min[2]) / CoordType_(unit_size);
1583 const CoordType_ z_max = CoordType_(_bbox_max[2]) / CoordType_(unit_size);
1584
1585 FEAT_PRAGMA_OMP(parallel)
1586 {
1587 std::vector<int> line_mask(this->_num_points[0], 0);
1589
1590 FEAT_PRAGMA_OMP(for schedule(dynamic, 16))
1591 for(u64 i = beg; i < end; ++i)
1592 {
1593 // line = iz * this->_num_points[1] + iy
1594 coords[1] = y_min + (y_max - y_min) * CoordType_(i % this->_num_points[1]) / CoordType_(this->_num_points[1] - 1u);
1595 coords[2] = z_min + (z_max - z_min) * CoordType_(i / this->_num_points[1]) / CoordType_(this->_num_points[2] - 1u);
1596 masker.mask_line(line_mask, x_min, x_max, coords);
1597 this->_compress_voxel_map_line(line_mask, i - offset);
1598 }
1599 }
1600 }
1601
1622 template<typename CoordType, int dim_>
1623 void _compute_voxel_map(const Dist::Comm& comm, VoxelMasker<CoordType, dim_>& masker, bool gather_to_all)
1624 {
1625 // single process or MPI parallel?
1626 if(comm.size() <= 1)
1627 {
1628 // compute all voxel map lines
1629 this->_compute_voxel_map_lines(masker, 0u, this->_num_lines, 0u);
1630 }
1631 else if(u64(comm.size()) <= this->_num_lines)
1632 {
1633 // there are at least as many lines in the voxel map as there are MPI processes; this is the usual case
1634 // we can use the entire communicator (usually MPI_COMM_WORLD) for the voxel map computation
1635 u64 comm_rank = u64(comm.rank());
1636 u64 comm_size = u64(comm.size());
1637
1638 // compute line count for a single process and round up; this may be bigger than _num_lines,
1639 // so the last process may have less lines to chew through than all other processes
1640 u64 line_count = (this->_num_lines + comm_size - 1u) / comm_size;
1641 std::size_t block_len = this->_stride_line * line_count;
1642
1643 // allocate voxel map and format to zero
1644 std::size_t vmap_size = block_len;
1645 // do we need the entire map on this process?
1646 if(gather_to_all || (comm_rank == 0))
1647 vmap_size *= u64(comm_size);
1648 this->_voxel_map.resize(vmap_size, 0u);
1649
1650 // compute first and last+1 line of this process; make sure the last process doesn't go beyond the total count
1651 u64 line_beg = comm_rank * line_count;
1652 u64 line_end = Math::min((comm_rank + 1u) * line_count, this->_num_lines);
1653
1654 // debug output
1655 //this->_comm.allprint(String(">>>") + stringify(line_beg).pad_front(6) + ":" + stringify(line_count) + ">" + stringify(line_end).pad_front(6));
1656
1657 // compute lines for this process
1658 this->_compute_voxel_map_lines(masker, line_beg, line_end, gather_to_all ? u64(0) : line_beg);
1659
1660 // perform an in-place allgather to synchronize the voxel map over all processes
1661 if(gather_to_all)
1662 comm.allgather(this->_voxel_map.data(), block_len, this->_voxel_map.data(), block_len);
1663 else
1664 comm.gather(this->_voxel_map.data(), block_len, this->_voxel_map.data(), block_len, 0);
1665 }
1666 else if(this->_num_lines < u64(comm.size()))
1667 {
1668 // more processes than slag lines; this is a borderline scenario, but we have to support it anyways
1669 // create a sub-communicator and then compute mask on that sub-communicator
1670 Dist::Comm sub_comm = comm.comm_create_range_incl(int(this->_num_lines));
1671
1672 // does this process participate in the sub-communicator?
1673 if(!sub_comm.is_null())
1674 {
1675 // get sub-communicator rank and size
1676 u64 comm_rank = u64(sub_comm.rank());
1677 u64 comm_size = u64(sub_comm.size());
1678
1679 // compute line count for a single process and round up; this may be bigger than _num_lines,
1680 // so the last process may have less lines to chew through than all other processes
1681 u64 line_count = (this->_num_lines + comm_size - 1u) / comm_size;
1682 std::size_t block_len = this->_stride_line * line_count;
1683
1684 // allocate voxel map and format to zero
1685 std::size_t vmap_size = block_len;
1686 // do we need the entire map on this process?
1687 if(gather_to_all || (comm_rank == 0))
1688 vmap_size *= u64(comm_size);
1689 this->_voxel_map.resize(vmap_size, 0u);
1690
1691 // compute first and last+1 line of this process; make sure the last process doesn't go beyond the total count
1692 u64 line_beg = comm_rank * line_count;
1693 u64 line_end = Math::min((comm_rank + 1u) * line_count, this->_num_lines);
1694
1695 // debug output
1696 //this->_comm.allprint(String(">>>") + stringify(line_beg).pad_front(6) + ":" + stringify(line_count) + ">" + stringify(line_end).pad_front(6));
1697
1698 // compute lines for this process
1699 this->_compute_voxel_map_lines(masker, line_beg, line_end, gather_to_all ? u64(0) : line_beg);
1700
1701 // perform an in-place gather to synchronize the voxel map on rank 0
1702 sub_comm.gather(this->_voxel_map.data(), block_len, this->_voxel_map.data(), block_len, 0);
1703 }
1704 else
1705 {
1706 // just allocate the voxel map vector for the following broadcast
1707 if(gather_to_all)
1708 this->_voxel_map.resize(this->_stride_line * this->_num_lines, 0u);
1709 }
1710
1711 // broadcast from rank 0 to all processes our entire domain communicator
1712 if(gather_to_all)
1713 comm.bcast(this->_voxel_map.data(), this->_stride_line * this->_num_lines, 0);
1714 }
1715
1716 // compute domain coverage on rank 0
1717 if(comm.rank() == 0)
1718 this->_coverage = this->_compute_domain_coverage();
1719
1720 // broadcast domain coverage to all ranks
1721 comm.bcast(&this->_coverage, std::size_t(1u), 0);
1722
1723 // that's it
1724 }
1725
1738 void _export_plane_to_bmp(std::ostream& os, u64 plane) const;
1739
1759 void _render_plane_to_bmp(std::ostream& os, Index width, Index height, i64 box_min_z, i64 box_max_z) const;
1760 }; // class VoxelMap
1761 } // namespace Geometry
1762} // namespace FEAT
#define ASSERT(expr)
Debug-Assertion macro definition.
Definition: assertion.hpp:229
#define XASSERT(expr)
Assertion macro definition.
Definition: assertion.hpp:262
#define XASSERTM(expr, msg)
Assertion macro definition with custom message.
Definition: assertion.hpp:263
FEAT Kernel base header.
Communicator class.
Definition: dist.hpp:1349
void bcast(void *buffer, std::size_t count, const Datatype &datatype, int root) const
Blocking broadcast.
Definition: dist.cpp:541
Comm comm_create_range_incl(int count, int first=0, int stride=1) const
Creates a new sub-communicator from a strided range of ranks.
Definition: dist.cpp:472
int size() const
Returns the size of this communicator.
Definition: dist.hpp:1506
void gather(const void *sendbuf, std::size_t sendcount, const Datatype &sendtype, void *recvbuf, std::size_t recvcount, const Datatype &recvtype, int root) const
Blocking gather.
Definition: dist.cpp:553
int rank() const
Returns the rank of this process in this communicator.
Definition: dist.hpp:1494
void allgather(const void *sendbuf, std::size_t sendcount, const Datatype &sendtype, void *recvbuf, std::size_t recvcount, const Datatype &recvtype) const
Blocking gather-to-all.
Definition: dist.cpp:589
bool is_null() const
Checks whether this communicator is a null communicator.
Definition: dist.cpp:454
Base class for file related errors.
Definition: exception.hpp:173
virtual CoordType signed_dist(const WorldPoint &point) const =0
Computes the signed distance of a point to this chart.
Wrapper for the CGAL Library.
Definition: cgal.hpp:57
bool point_inside(DataType x, DataType y, DataType z) const
Check whether a point is inside the Polyhedron defined at objects' construction.
Voxel masker implementation for CGAL wrapper.
Definition: voxel_map.hpp:144
const Geometry::CGALWrapper< CoordType_ > & _cgal_wrapper
a reference to our CGAL wrapper
Definition: voxel_map.hpp:152
virtual void mask_line(std::vector< int > &mask, const CoordType x_min, const CoordType x_max, const PointType &point) override
Computes the mask for an entire X-coordinate row.
Definition: voxel_map.hpp:171
VoxelCGALMasker(const Geometry::CGALWrapper< CoordType_ > &cgal_wrapper, bool invert)
Constructor.
Definition: voxel_map.hpp:165
Voxel masker implementation for chart classes.
Definition: voxel_map.hpp:196
CoordType_ CoordType
the coordinate type
Definition: voxel_map.hpp:74
Tiny::Vector< CoordType_, dim_ > PointType
the point type
Definition: voxel_map.hpp:76
VoxelChartMasker(const Geometry::Atlas::ChartBase< MeshType > &chart, bool invert)
Constructor.
Definition: voxel_map.hpp:216
Voxel masker implementation for function parser expression tests.
Definition: voxel_map.hpp:304
VoxelFormulaMasker(const String &formula)
Constructor.
Definition: voxel_map.hpp:324
virtual void mask_line(std::vector< int > &mask, const CoordType x_min, const CoordType x_max, const PointType &point) override
Computes the mask for an entire X-coordinate row.
Definition: voxel_map.hpp:350
::FunctionParser _parser
the function parser
Definition: voxel_map.hpp:314
Voxel masker implementation for lambda expression tests.
Definition: voxel_map.hpp:250
CoordType_ CoordType
the coordinate type
Definition: voxel_map.hpp:74
VoxelLambdaMasker(Lambda_ &&lambda)
Constructor.
Definition: voxel_map.hpp:268
Lambda_ _lambda
the lambda expression
Definition: voxel_map.hpp:258
virtual void mask_line(std::vector< int > &mask, const CoordType x_min, const CoordType x_max, const PointType &point) override
Computes the mask for an entire X-coordinate row.
Definition: voxel_map.hpp:273
helper class for read function result
Definition: voxel_map.hpp:502
helper class for write function result
Definition: voxel_map.hpp:462
Error class for VoxelMap related file errors.
Definition: voxel_map.hpp:37
Error class for VoxelMap related formula parsing errors.
Definition: voxel_map.hpp:50
bool check_box(const Tiny::Vector< Coord_, dim_ > &box_min, const Tiny::Vector< Coord_, dim_ > &box_max) const
Checks the voxel map entries for a given box of voxels.
Definition: voxel_map.hpp:1070
i64 _map_coord_idx_lower(i64 xyz, std::size_t sdim) const
Maps a unit coordinate to a X-/Y-/Z-index of the lower voxel in the voxel map.
Definition: voxel_map.cpp:565
bool _check_point_nearest(const std::array< i64, 1 > &p) const
Checks the nearest voxel map entry for a given 1D point.
Definition: voxel_map.cpp:631
static constexpr u64 header_size
size of voxel map header in bytes
Definition: voxel_map.hpp:417
Real _sample_box_1d(i64 px0, i64 px1, i64 xidx0, i64 xidx1, i64 yidx=i64(0), i64 zidx=i64(0)) const
Helper function for _sample_box: samples a 1D edge in X line.
Definition: voxel_map.cpp:750
void set_out_of_bounds_value(bool value)
Sets the out-of-bounds value for the voxel map.
Definition: voxel_map.hpp:621
Real _calc_sample_rate(i64 xyz, i64 idx, std::size_t sdim) const
Helper function for _sample_voxel_map_Xd: compute the sample rate in a given dimension.
Definition: voxel_map.cpp:601
std::vector< char > _voxel_map
the actual voxel map; its size may be larger than necessary due to padding
Definition: voxel_map.hpp:545
void export_to_bmp(const String &filename_prefix) const
Exports the voxel map to a sequence of monochrome BMP image files.
Definition: voxel_map.cpp:456
bool _check_point(i64 xidx, i64 yidx, i64 zidx) const
Helper function for _sample_point: checks a single voxel point value.
Definition: voxel_map.cpp:620
Real get_bounding_box_min(int dim) const
Returns the minimum bounding box coordinate for a given dimensions.
Definition: voxel_map.hpp:594
bool get_out_of_bounds_value() const
Returns the out-of-bounds value for the voxel map.
Definition: voxel_map.hpp:627
WriteResult write(const String &filename, const u64 compress_block_size=128u, const int compress_level=9) const
Writes the voxel map into a file that can later be read in.
Definition: voxel_map.cpp:186
void render_to_bmp(const String &filename_prefix, Index width, Index height, Index depth) const
Renders the voxel map to a sequence of gray-scale BMP image files.
Definition: voxel_map.cpp:481
void _export_plane_to_bmp(std::ostream &os, u64 plane) const
Exports a single plane of the voxel map to a monochrome BMP image file.
Definition: voxel_map.cpp:1008
i64 _map_coord_idx_upper(i64 xyz, std::size_t sdim) const
Maps a unit coordinate to a X-/Y-/Z-index of the upper voxel in the voxel map.
Definition: voxel_map.cpp:580
Real _sample_point_1d_y(i64 py, i64 xidx, i64 yidx, i64 zidx=i64(0)) const
Helper function for _sample_point: samples a 1D edge in Y-parallel line.
Definition: voxel_map.cpp:706
Index get_num_points(int dim) const
Returns the number of points of the voxel map in each dimension.
Definition: voxel_map.hpp:641
Real _sample_box_2d(i64 px0, i64 px1, i64 py0, i64 py1, i64 xidx0, i64 xidx1, i64 yidx0, i64 yidx1, i64 zidx=i64(0)) const
Helper function for _sample_box: samples a 2D rectangle in XY plane.
Definition: voxel_map.cpp:843
std::array< u64, 3u > _num_points
number of points in each dimension
Definition: voxel_map.hpp:535
Real _sample_box_3d(i64 px0, i64 px1, i64 py0, i64 py1, i64 pz0, i64 pz1, i64 xidx0, i64 xidx1, i64 yidx0, i64 yidx1, i64 zidx0, i64 zidx1) const
Helper function for _sample_box: samples a 3D cuboid in XYZ volume.
Definition: voxel_map.cpp:900
Real sample_point(const Tiny::Vector< Coord_, dim_ > &point) const
Samples the voxel map entry for a given point by multi-linear interpolation.
Definition: voxel_map.hpp:1044
void compute_map_from_chart(const Dist::Comm &comm, const Geometry::Atlas::ChartBase< MeshType_ > &chart, bool invert, bool gather_to_all=true)
Creates the voxel map based on a chart by utilizing MPI parallelization.
Definition: voxel_map.hpp:760
void _compress_voxel_map_line(const std::vector< int > &mask, const u64 line)
Compresses a voxel map line into the voxel map.
Definition: voxel_map.cpp:997
u64 get_stride_line() const
Returns the line stride, i.e. the size of a single X-line in bytes.
Definition: voxel_map.hpp:664
Real get_bounding_box_max(int dim) const
Returns the maximum bounding box coordinate for a given dimensions.
Definition: voxel_map.hpp:601
Real get_domain_coverage() const
Returns the domain coverage of the voxel map.
Definition: voxel_map.hpp:695
u64 _compute_domain_coverage() const
Computes the domain coverage of the voxel map.
Definition: voxel_map.cpp:518
void export_plane_to_bmp(const String &filename, Real z_coord) const
Exports a single plane of the voxel map to a monochrome BMP image file.
Definition: voxel_map.cpp:469
void compute_map(const Dist::Comm &comm, VoxelMasker< Coord_, dim_ > &masker, bool gather_to_all=true)
Creates the voxel map based on a given masker object by utilizing MPI parallelization.
Definition: voxel_map.hpp:729
void _compute_voxel_map_lines(VoxelMasker< CoordType_, 2 > &masker, u64 beg, u64 end, u64 offset)
Computes a range of voxel map lines for a 2D domain.
Definition: voxel_map.hpp:1540
void _compute_voxel_map(const Dist::Comm &comm, VoxelMasker< CoordType, dim_ > &masker, bool gather_to_all)
Computes the voxel map for the domain.
Definition: voxel_map.hpp:1623
static constexpr u64 magic_number
voxel map magic number
Definition: voxel_map.hpp:414
const std::vector< char > & get_map() const
Returns a reference to the voxel map.
Definition: voxel_map.hpp:682
void compute_map_from_lambda_3d(const Dist::Comm &comm, Lambda_ &&lambda, bool gather_to_all=true)
Creates the voxel map based on a 3D lambda expression by utilizing MPI parallelization.
Definition: voxel_map.hpp:821
u64 get_stride_plane() const
Returns the plane stride, i.e. the size of a single XY-plane in bytes.
Definition: voxel_map.hpp:670
bool check_point(u64 ix, u64 iy=0u, u64 iz=0u) const
Returns the value of a specific voxel point in the voxel map.
Definition: voxel_map.hpp:1006
Real get_bounding_box_volume() const
Returns the volume of the 1D/2D/3D voxel map bounding box.
Definition: voxel_map.cpp:507
u64 _num_planes
number of planes; 2D = 1; 3D = num_points[3]
Definition: voxel_map.hpp:543
std::uint64_t u64
unsigned 64-bit integer type
Definition: voxel_map.hpp:411
Real _sample_point_1d_z(i64 pz, i64 xidx, i64 yidx, i64 zidx) const
Helper function for _sample_point: samples a 1D edge in Z-parallel line.
Definition: voxel_map.cpp:713
Index get_num_voxels() const
Returns the total number of voxels in the voxel map.
Definition: voxel_map.hpp:658
void set_resolution(Real max_res)
Sets the resolution for the voxel map, i.e. the maximum voxel size in each dimension.
Definition: voxel_map.cpp:127
u64 _stride_line
stride of a single voxel line in X dimension
Definition: voxel_map.hpp:537
bool check_point_nearest(const Tiny::Vector< Coord_, dim_ > &point) const
Checks the voxel map entry for a given point.
Definition: voxel_map.hpp:1025
void compute_map_from_formula_3d(const Dist::Comm &comm, const String &formula, bool gather_to_all=true)
Creates the voxel map based on a 3D formula by utilizing MPI parallelization.
Definition: voxel_map.cpp:149
void set_num_points(Index num_x, Index num_y, Index num_z=0u)
Sets the number of points of the voxel map in each dimension.
Definition: voxel_map.cpp:108
virtual ~VoxelMap()
virtual destructor
Definition: voxel_map.cpp:75
void render_plane_to_bmp(const String &filename, Index width, Index height, Real z_min, Real z_max) const
Renders a plane range of voxel map to a single gray-scale BMP image file.
Definition: voxel_map.cpp:495
std::int64_t i64
signed 64-bit integer type
Definition: voxel_map.hpp:408
Real sample_box(const Tiny::Vector< Coord_, dim_ > &box_min, const Tiny::Vector< Coord_, dim_ > &box_max) const
Samples the voxel map entries for a given box of voxels.
Definition: voxel_map.hpp:1122
void _compute_voxel_map_lines(VoxelMasker< CoordType_, 3 > &masker, u64 beg, u64 end, u64 offset)
Computes a range of voxel map lines for a 3D domain.
Definition: voxel_map.hpp:1576
Real _sample_point_1d_x(i64 px, i64 xidx, i64 yidx=i64(0), i64 zidx=i64(0)) const
Helper function for _sample_point: samples a 1D edge in X-parallel line.
Definition: voxel_map.cpp:699
void compute_map_from_off_3d(const Dist::Comm &comm, const String &filename, bool invert, bool gather_to_all=true)
Creates the voxel map based on a 3D OFF model handled by CGAL by utilizing MPI parallelization.
Definition: voxel_map.cpp:162
u64 _stride_plane
stride of a single plane in XY dimensions
Definition: voxel_map.hpp:539
void _compute_voxel_map_lines(VoxelMasker< CoordType_, 1 > &masker, u64 beg, u64 end, u64 offset)
Computes a range of voxel map lines for a 1D domain.
Definition: voxel_map.hpp:1510
VoxelMap(const VoxelMap &)=delete
no copies, no problems
void compute_map_from_lambda_2d(const Dist::Comm &comm, Lambda_ &&lambda, bool gather_to_all=true)
Creates the voxel map based on a 2D lambda expression by utilizing MPI parallelization.
Definition: voxel_map.hpp:791
u64 _coverage
the coverage of the domain, relative to unit size
Definition: voxel_map.hpp:549
void set_bounding_box_2d(Real x_min, Real x_max, Real y_min, Real y_max)
Sets the bounding box for a 2D voxel map.
Definition: voxel_map.cpp:79
Real _sample_point_2d(i64 px, i64 py, i64 xidx, i64 yidx, i64 zidx=i64(0)) const
Helper function for _sample_point: samples a 2D square in XY-parallel plane.
Definition: voxel_map.cpp:720
static constexpr i64 unit_size
size of a real unit (meter) in our internal units (nanometers)
Definition: voxel_map.hpp:420
bool _out_of_bounds_value
the out-of-bounds-value for the voxel map
Definition: voxel_map.hpp:547
ReadResult read(const Dist::Comm &comm, const String &filename)
Reads a voxel map from a file.
Definition: voxel_map.cpp:322
std::array< i64, 3u > _bbox_min
bounding box dimensions of domain
Definition: voxel_map.hpp:533
bool _check_box(const std::array< u64, 1 > &box_min, const std::array< u64, 1 > &box_max) const
Checks whether a 1D box contains at least one active voxel.
Definition: voxel_map.cpp:659
void compute_map_from_formula_2d(const Dist::Comm &comm, const String &formula, bool gather_to_all=true)
Creates the voxel map based on a 2D formula by utilizing MPI parallelization.
Definition: voxel_map.cpp:136
u64 get_stride_volume() const
Returns the volume stride, i.e. the size of a single XYZ-volume in bytes.
Definition: voxel_map.hpp:676
Real _sample_point(const std::array< i64, 1 > &p) const
Samples the voxel map for a given 1D point by multi-linear interpolation.
Definition: voxel_map.cpp:734
int _create_stage
current creation stage
Definition: voxel_map.hpp:531
u64 _map_coord_idx_nearest(i64 xyz, std::size_t sdim) const
Maps a unit coordinate to a X-/Y-/Z-index of the closest voxel in the voxel map.
Definition: voxel_map.cpp:535
VoxelMap()
standard constructor
Definition: voxel_map.cpp:23
Real _sample_point_3d(i64 px, i64 py, i64 pz, i64 xidx, i64 yidx, i64 zidx) const
Helper function for _sample_point: samples a 3D cube in XYZ volume.
Definition: voxel_map.cpp:727
void set_bounding_box_3d(Real x_min, Real x_max, Real y_min, Real y_max, Real z_min, Real z_max)
Sets the bounding box for a 3D voxel map.
Definition: voxel_map.cpp:92
void _render_plane_to_bmp(std::ostream &os, Index width, Index height, i64 box_min_z, i64 box_max_z) const
Renders a plane range of voxel map to a single gray-scale BMP image file.
Definition: voxel_map.cpp:1087
static u64 calc_line_stride(u64 num_x)
ensure that we're not compiling on some freak architecture...
Definition: voxel_map.hpp:448
Real _sample_box(const std::array< i64, 1 > &box_min, const std::array< i64, 1 > &box_max) const
Samples a 1D box of the voxel map.
Definition: voxel_map.cpp:957
Real get_domain_volume() const
Returns the covered domain volume.
Definition: voxel_map.hpp:702
u64 _num_lines
number of lines; 2D = num_points[2]; 3D: = num_points[2] * num_points[3]
Definition: voxel_map.hpp:541
Interface for voxel masker for the VoxelMap class.
Definition: voxel_map.hpp:71
CoordType_ CoordType
the coordinate type
Definition: voxel_map.hpp:74
static CoordType x_coord(const CoordType x_min, const CoordType x_max, const std::size_t i, const std::size_t n)
Computes the X-coordinate for a given point.
Definition: voxel_map.hpp:101
Tiny::Vector< CoordType_, dim_ > PointType
the point type
Definition: voxel_map.hpp:76
virtual void mask_line(std::vector< int > &mask, const CoordType x_min, const CoordType x_max, const PointType &point)=0
Computes the mask for an entire X-coordinate row.
virtual ~VoxelMasker()
virtual destructor
Definition: voxel_map.hpp:79
Class for parser related errors.
Definition: exception.hpp:132
String class implementation.
Definition: string.hpp:46
Tiny Vector class template.
T_ v[s_]
actual vector data
std::uint64_t u64
unsigned 64-bit integer type
Definition: voxel_map.cpp:21
@ other
generic/other permutation strategy
std::int64_t i64
signed 64-bit integer type
Definition: voxel_map.cpp:19
T_ min(T_ a, T_ b)
Returns the minimum of two values.
Definition: math.hpp:123
FEAT namespace.
Definition: adjactor.hpp:12
double Real
Real data type.
@ value
specifies whether the space should supply basis function values
std::uint64_t Index
Index data type.
header structure of voxel map file header
Definition: voxel_map.hpp:424