FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
voxel_domain_control.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#pragma once
6
8
9#include <kernel/util/dist.hpp>
10#include <kernel/util/dist_file_io.hpp>
11#include <kernel/util/stop_watch.hpp>
12#include <kernel/runtime.hpp>
13#include <kernel/util/simple_arg_parser.hpp>
14#include <kernel/util/property_map.hpp>
15#include <kernel/util/statistics.hpp>
16#include <kernel/geometry/mesh_node.hpp>
17#include <kernel/geometry/mesh_file_reader.hpp>
18#include <kernel/geometry/partition_set.hpp>
19#include <kernel/geometry/parti_2lvl.hpp>
20#include <kernel/geometry/parti_iterative.hpp>
21#include <kernel/geometry/parti_parmetis.hpp>
22#include <kernel/geometry/parti_zoltan.hpp>
23#include <kernel/geometry/common_factories.hpp>
24#include <kernel/geometry/patch_mesh_factory.hpp>
25#include <kernel/geometry/patch_meshpart_factory.hpp>
26#include <kernel/geometry/patch_meshpart_splitter.hpp>
27#include <kernel/geometry/cgal.hpp>
28#include <kernel/geometry/voxel_map.hpp>
29
30#include <control/domain/parti_domain_control_base.hpp>
31
32namespace FEAT
33{
34 namespace Control
35 {
36 namespace Domain
37 {
48 template<typename DomainLevel_>
50 public DomainLevel_
51 {
52 public:
54 typedef DomainLevel_ BaseClass;
56 using typename BaseClass::MeshType;
58 using typename BaseClass::MeshNodeType;
59
61 std::shared_ptr<DomainLevel_> slag_level;
62
65
68
69 explicit VoxelDomainLevelWrapper(int _lvl_idx, std::unique_ptr<MeshNodeType> node,
70 Adjacency::Coloring&& coloring, Adjacency::Coloring&& layering) :
71 BaseClass(_lvl_idx, std::move(node)),
72 slag_level(),
73 element_coloring(std::forward<Adjacency::Coloring>(coloring)),
74 element_layering(std::forward<Adjacency::Coloring>(layering))
75 {
76 }
77
78 explicit VoxelDomainLevelWrapper(int _lvl_idx, std::unique_ptr<MeshNodeType> node,
79 std::unique_ptr<MeshNodeType> slag_node, Adjacency::Coloring&& coloring, Adjacency::Coloring&& layering) :
80 BaseClass(_lvl_idx, std::move(node)),
81 slag_level(),
82 element_coloring(std::forward<Adjacency::Coloring>(coloring)),
83 element_layering(std::forward<Adjacency::Coloring>(layering))
84 {
85 if(slag_node)
86 slag_level = std::make_shared<DomainLevel_>(_lvl_idx, std::move(slag_node));
87 }
88 }; // class VoxelDomainLevelWrapper<...>
89
95 template<typename DomainLevel_>
97 public Control::Domain::PartiDomainControlBase< DomainLevel_ >
98 {
99 public:
103 using typename BaseClass::LevelType;
105 using typename BaseClass::LayerType;
107 using typename BaseClass::MeshType;
109 using typename BaseClass::AtlasType;
111 using typename BaseClass::MeshNodeType;
113 using typename BaseClass::MeshPartType;
115 using typename BaseClass::WeightType;
117 using typename BaseClass::Ancestor;
118
120 static constexpr int shape_dim = MeshType::shape_dim;
121
123 typedef typename MeshType::CoordType CoordType;
124
125 protected:
128
132 std::array<Index, shape_dim> _base_slices;
133
135 std::unique_ptr<Geometry::VoxelMap> _voxel_map;
136
138 std::unique_ptr<MeshNodeType> _base_mesh_node;
139
141 StopWatch _watch_create_base_mesh, _watch_create_voxel_map, _watch_create_hierarchy;
142
145
147 bool _unstructered_mesh = false;
148
149 public:
159 explicit VoxelDomainControl(const Dist::Comm& comm_, bool support_multi_layered) :
160 BaseClass(comm_, support_multi_layered),
161 _create_stage(0),
162 _keep_voxel_map(false),
163 _unstructered_mesh(false)
164 {
165 }
166
169 {
170 }
171
185 {
186 this->_keep_voxel_map = true;
187 }
188
189 Tiny::Vector<CoordType, shape_dim> get_bounding_box_min() const
190 {
191 return _bbox_min;
192 }
193
194 Tiny::Vector<CoordType, shape_dim> get_bounding_box_max() const
195 {
196 return _bbox_max;
197 }
198
222 {
223 XASSERTM(shape_dim == 2, "invalid dimension: this function can only be called for 2D domains!");
224 XASSERTM(_create_stage == 0, "base mesh already created!");
225
226 XASSERT(num_x > Index(0));
227 XASSERT(num_y > Index(0));
228 XASSERT(x_min < x_max);
229 XASSERT(y_min < y_max);
230
232
233 _base_slices[0] = num_x;
234 _base_slices[1] = num_y;
235 _bbox_min[0] = x_min;
236 _bbox_max[0] = x_max;
237 _bbox_min[1] = y_min;
238 _bbox_max[1] = y_max;
239
240 // create a structured mesh from factory
243
244 // get the node's vertex set
245 auto& vtx = _base_mesh_node->get_mesh()->get_vertex_set();
246 Index n = vtx.get_num_vertices();
247 for(Index i(0); i < n; ++i)
248 {
249 vtx[i][0] = x_min + (x_max - x_min) * vtx[i][0];
250 vtx[i][1] = y_min + (y_max - y_min) * vtx[i][1];
251 }
252
254
255 // update creation stage
256 this->_create_stage = 1;
257
258 // return the base-mesh node
259 return *_base_mesh_node.get();
260 }
261
288 CoordType y_min, CoordType y_max, CoordType z_min, CoordType z_max)
289 {
290 XASSERTM(shape_dim == 3, "invalid dimension: this function can only be called for 3D domains!");
291 XASSERTM(_create_stage == 0, "base mesh already created!");
292
293 XASSERT(num_x > Index(0));
294 XASSERT(num_y > Index(0));
295 XASSERT(num_z > Index(0));
296 XASSERT(x_min < x_max);
297 XASSERT(y_min < y_max);
298 XASSERT(z_min < z_max);
299
301
302 _base_slices[0] = num_x;
303 _base_slices[1] = num_y;
304 _base_slices[2] = num_z;
305 _bbox_min[0] = x_min;
306 _bbox_max[0] = x_max;
307 _bbox_min[1] = y_min;
308 _bbox_max[1] = y_max;
309 _bbox_min[2] = z_min;
310 _bbox_max[2] = z_max;
311
312 // create a structured mesh from factory
314 Geometry::StructUnitCubeFactory<MeshType>::make_unique_from(num_x, num_y, num_z), &this->_atlas);
315
316 // get the node's vertex set
317 auto& vtx = _base_mesh_node->get_mesh()->get_vertex_set();
318 Index n = vtx.get_num_vertices();
319 for(Index i(0); i < n; ++i)
320 {
321 vtx[i][0] = x_min + (x_max - x_min) * vtx[i][0];
322 vtx[i][1] = y_min + (y_max - y_min) * vtx[i][1];
323 vtx[i][2] = z_min + (z_max - z_min) * vtx[i][2];
324 }
325
327
328 // update creation stage
329 this->_create_stage = 1;
330
331 // return the base-mesh node
332 return *_base_mesh_node.get();
333 }
334
335 MeshNodeType& set_base_mesh(std::unique_ptr<MeshNodeType>&& mesh_node)
336 {
337 XASSERTM(_create_stage == 0, "base mesh already created!");
338
340 _base_mesh_node = std::move(mesh_node);
341
342 for(std::size_t k = 0; k < std::size_t(shape_dim); ++k)
343 {
345 }
346
347 for(int k = 0; k < shape_dim; ++k)
348 {
350 _bbox_max[k] = Math::Limits<CoordType>::lowest();
351 }
352
353 auto& vtx = _base_mesh_node->get_mesh()->get_vertex_set();
354 Index n = vtx.get_num_vertices();
355 for(Index i(0); i < n; ++i)
356 {
357 for(int k = 0; k < shape_dim; ++k)
358 {
359 _bbox_min[k] = Math::min(_bbox_min[k], vtx[i][k]);
360 _bbox_max[k] = Math::max(_bbox_max[k], vtx[i][k]);
361 }
362 }
363
365
366 // update creation stage
367 this->_create_stage = 1;
368
369 // update unstructered mesh flag
370 this->_unstructered_mesh = true;
371
372 // return the base-mesh node
373 return *_base_mesh_node.get();
374 }
375
386 {
387 this->_voxel_map->set_out_of_bounds_value(value);
388 }
389
410 {
411 XASSERTM(this->_create_stage >= 1, "invalid creation stage; create the base-mesh first");
412 XASSERTM(this->_create_stage <= 1, "invalid creation stage: voxel map already set");
413
414 this->_watch_create_voxel_map.start();
415#ifdef FEAT_COMPILER_CLANG
416 this->_voxel_map.reset(new Geometry::VoxelMap());
417#else
418 this->_voxel_map = std::make_unique<Geometry::VoxelMap>();
419#endif
420 this->_precreate_voxel_map(resolution);
421 this->_voxel_map->compute_map(this->_comm, masker, true);
422 this->_watch_create_voxel_map.stop();
423
424 // update creation stage
425 this->_create_stage = 2;
426 }
427
449 template<typename Lambda_>
450 void create_voxel_map_from_lambda(Lambda_&& lambda, Real resolution)
451 {
452 XASSERTM(this->_create_stage >= 1, "invalid creation stage; create the base-mesh first");
453 XASSERTM(this->_create_stage <= 1, "invalid creation stage: voxel map already set");
454
455 this->_watch_create_voxel_map.start();
456#ifdef FEAT_COMPILER_CLANG
457 this->_voxel_map.reset(new Geometry::VoxelMap());
458#else
459 this->_voxel_map = std::make_unique<Geometry::VoxelMap>();
460#endif
461 this->_precreate_voxel_map(resolution);
462 if constexpr(shape_dim == 2)
463 this->_voxel_map->compute_map_from_lambda_2d(this->_comm, std::forward<Lambda_>(lambda), true);
464 else
465 this->_voxel_map->compute_map_from_lambda_3d(this->_comm, std::forward<Lambda_>(lambda), true);
466 this->_watch_create_voxel_map.stop();
467
468 // update creation stage
469 this->_create_stage = 2;
470 }
471
493 {
494 XASSERTM(this->_create_stage >= 1, "invalid creation stage; create the base-mesh first");
495 XASSERTM(this->_create_stage <= 1, "invalid creation stage: voxel map already set");
496
497 this->_watch_create_voxel_map.start();
498#ifdef FEAT_COMPILER_CLANG
499 this->_voxel_map.reset(new Geometry::VoxelMap());
500#else
501 this->_voxel_map = std::make_unique<Geometry::VoxelMap>();
502#endif
503 this->_precreate_voxel_map(resolution);
504 this->_voxel_map->compute_map_from_chart(this->_comm, chart, invert, true);
505 this->_watch_create_voxel_map.stop();
506
507 // update creation stage
508 this->_create_stage = 2;
509 }
510
532 void create_voxel_map_from_off(const String& filename, bool invert, Real resolution)
533 {
534 std::stringstream sstr;
535 DistFileIO::read_common(sstr, filename, this->_comm);
536 this->create_voxel_map_from_off(sstr, invert, resolution);
537 }
538
562 void create_voxel_map_from_off(std::istream& is, bool invert, Real resolution)
563 {
564 XASSERTM(this->_create_stage >= 1, "invalid creation stage; create the base-mesh first");
565 XASSERTM(this->_create_stage <= 1, "invalid creation stage: voxel map already set");
566
567 // this only makes sense in 3D...
568 XASSERTM(shape_dim == 3, "CGAL OFF voxel map creation is only available in 3D");
569
570 this->_watch_create_voxel_map.start();
571
572#ifdef FEAT_COMPILER_CLANG
573 this->_voxel_map.reset(new Geometry::VoxelMap());
574#else
575 this->_voxel_map = std::make_unique<Geometry::VoxelMap>();
576#endif
577 this->_precreate_voxel_map(resolution);
578 this->_voxel_map->compute_map_from_off_3d(this->_comm, is, invert, true);
579
580 this->_watch_create_voxel_map.stop();
581
582 // update creation stage
583 this->_create_stage = 2;
584 }
585
596 {
597 XASSERTM(this->_create_stage >= 1, "invalid creation stage; create the base-mesh first");
598 XASSERTM(this->_create_stage <= 1, "invalid creation stage: voxel map already set");
599
600 this->_watch_create_voxel_map.start();
601
602#ifdef FEAT_COMPILER_CLANG
603 this->_voxel_map.reset(new Geometry::VoxelMap());
604#else
605 this->_voxel_map = std::make_unique<Geometry::VoxelMap>();
606#endif
607 Geometry::VoxelMap::ReadResult result = this->_voxel_map->read(this->_comm, filename);
608
609 this->_watch_create_voxel_map.stop();
610
611 // update creation stage
612 this->_create_stage = 2;
613
614 return result;
615 }
616
627 {
628 XASSERTM(this->_voxel_map, "voxel map not created yet");
629 return this->_voxel_map->write(filename);
630 }
631
639 {
640 XASSERTM(this->_create_stage >= 2, "invalid creation stage; create the base-mesh and voxel map first");
641 XASSERTM(this->_create_stage <= 2, "invalid creation stage: domain hierarchy already created");
642
643 this->_watch_create_hierarchy.start();
644
645 // create the domain control
646#ifdef FEAT_HAVE_MPI
647 if(this->_comm.size() == 1)
648 {
649 // We've got just one process, so it's a simple choice:
650 this->_create_single_process(std::move(this->_base_mesh_node));
651 }
652 else if(this->_support_multi_layered && (this->_desired_levels.size() > std::size_t(2)))
653 {
654 // The application supports multi-layered domain controls and
655 // the user wants that, so create a multi-layered one:
656 this->_create_multi_layered(std::move(this->_base_mesh_node));
657 }
658 else
659 {
660 // Create a single-layered domain control:
661 this->_create_single_layered(std::move(this->_base_mesh_node));
662 }
663#else // not FEAT_HAVE_MPI
664 {
665 // In the non-MPI case, we always have only one process:
666 this->_create_single_process(std::move(this->_base_mesh_node));
667 }
668#endif // FEAT_HAVE_MPI
669
670 // compile virtual levels
671 this->compile_virtual_levels();
672
673 this->_watch_create_hierarchy.stop();
674
675 // collect statistics
676 FEAT::Statistics::toe_partition = this->_watch_create_base_mesh.elapsed() +
677 this->_watch_create_voxel_map.elapsed() + this->_watch_create_hierarchy.elapsed();
678
679 // update creation stage
680 this->_create_stage = 3;
681 this->_was_created = true;
682
683 // delete the voxel map unless we're meant to keep it
684 if(!this->_keep_voxel_map)
685 this->_voxel_map.reset();
686 }
687
690 {
691 return this->_watch_create_base_mesh;
692 }
693
696 {
697 return this->_watch_create_voxel_map;
698 }
699
702 {
703 return this->_watch_create_hierarchy;
704 }
705
710 {
711 return *this->_voxel_map;
712 }
713
723 std::vector<int> gather_vertex_voxel_map(Index level) const
724 {
725 XASSERTM(this->_create_stage == 3, "domain level hierarchy has to be created before the vertex mask can be computed");
726 XASSERT(level < this->size_physical());
727
728 const auto& vtx = this->at(level)->get_mesh().get_vertex_set();
729 const Index nv = vtx.get_num_vertices();
730 std::vector<int> mask(nv, 0);
731
732 for(Index i(0); i < nv; ++i)
733 mask[i] = this->_voxel_map->check_point_nearest(vtx[i]);
734
735 return mask;
736 }
737
751 std::vector<WeightType> gather_element_voxel_weights(Index level) const
752 {
753 XASSERT(level < this->size_physical());
754 return this->_gather_element_weights(this->at(level)->get_mesh());
755 }
756
761 {
762 String msg;
763 for(auto it = this->_layer_levels.begin(); it != this->_layer_levels.end(); ++it)
764 {
765 if(it != this->_layer_levels.begin())
766 msg += " |";
767 for(auto jt = it->begin(); jt != it->end(); ++jt)
768 {
769 msg += " " + stringify((*jt)->get_level_index());
770 msg += "[";
771 msg += stringify((*jt)->get_mesh().get_num_elements()).pad_front(4);
772 msg += "]";
773 if((*jt)->slag_level)
774 ((msg += "<[") += stringify((*jt)->slag_level->get_mesh().get_num_elements()).pad_front(4)) += "]";
775 }
776 }
777 return msg;
778 }
779
789 virtual void create(const std::deque<String>& filenames, String dirpath = "")
790 {
791 //dummy implementation
792 ASSERTM(false, "Thou shall not arrive here!");
793 (void) filenames;
794 (void) dirpath;
795 }
796
804 {
805 //dummy implementation
806 ASSERTM(false, "Thou shall not arrive here!");
807 }
808
815 virtual void create(std::unique_ptr<MeshNodeType>&)
816 {
817 //dummy implementation
818 ASSERTM(false, "Thou shall not arrive here!");
819 }
820
821 protected:
825 void _precreate_voxel_map(Real resolution)
826 {
827 // set voxel map bounding box based on domain's bounding box
828 if constexpr(shape_dim == 2)
829 this->_voxel_map->set_bounding_box_2d(this->_bbox_min[0], this->_bbox_max[0], this->_bbox_min[1], this->_bbox_max[1]);
830 else
831 this->_voxel_map->set_bounding_box_3d(this->_bbox_min[0], this->_bbox_max[0],
832 this->_bbox_min[1], this->_bbox_max[1], this->_bbox_min[2], this->_bbox_max[2]);
833
834 // is the resolution given?
835 if(resolution > Real(0))
836 {
837 this->_voxel_map->set_resolution(resolution);
838 return;
839 }
840 else if(_unstructered_mesh)
841 {
842 XABORTM("Required to provide resolution for voxel map");
843 }
844
845 XASSERTM(this->_base_slices[0] != Math::Limits<Index>::max(), "Set Resolution explicitly");
846 // compute the mesh width on the base mesh level
847 Real base_res = (this->_bbox_max[0] - this->_bbox_min[0]) / Real(this->_base_slices[0]);
848 for(int i(1); i < shape_dim; ++i)
849 base_res = Math::min(base_res, this->_bbox_max[i] - this->_bbox_min[i]) / Real(this->_base_slices[std::size_t(i)]);
850
851 // set resolution for voxel map to base resolution divided by 2^{desired-level-max+1)
852 this->_voxel_map->set_resolution(base_res / Real(2ull << this->get_desired_level_max()));
853 }
854
869 std::vector<Index> _gather_masked_elements(const MeshType& mesh) const
870 {
871 const Index num_elems = mesh.get_num_elements();
872
873 // reserve the vector
874 std::vector<Index> masked_elems;
875 masked_elems.reserve(num_elems);
876
877 // get the vertex set and the vertices-at-element index set
878 const auto& vtx = mesh.get_vertex_set();
879 const auto& verts_at_elem = mesh.template get_index_set<shape_dim, 0>();
880
881 // element bounding box coordinates
882 Tiny::Vector<CoordType, shape_dim> elbox_min, elbox_max;
883
884 // loop over all elements
885 for(Index ielem(0); ielem < num_elems; ++ielem)
886 {
887 // compute bounding box of element
888 // note: actually, we should always have
889 // elbox_min = vtx[verts_at_elem(ielem, 0)]
890 // elbox_max = vtx[verts_at_elem(ielem, 1 << shape_dim - 1)]
891 // because of the element orientation of the base mesh, but we'll compute the bounding
892 // box for each element manually anyways, just to be sure in case that a derived class
893 // might give us a mesh object that is not directly refined from the base mesh using
894 // the standard 2-level refinement...
895 elbox_min = elbox_max = vtx[verts_at_elem(ielem, 0)];
896 for(int j(1); j < verts_at_elem.num_indices; ++j)
897 {
898 const auto& v = vtx[verts_at_elem(ielem, j)];
899 for(int k(0); k < shape_dim; ++k)
900 Math::minimax(v[k], elbox_min[k], elbox_max[k]);
901 }
902
903 // check the bounding box against the voxel map
904 if(this->_voxel_map->check_box(elbox_min, elbox_max))
905 masked_elems.push_back(ielem);
906 }
907
908 // return the list of all elements that we found
909 return masked_elems;
910 }
911
928 std::vector<Index> _gather_masked_elements(const MeshType& mesh, const Dist::Comm& sibling_comm) const
929 {
930 const Index num_elems = mesh.get_num_elements();
931 const Index num_procs = Index(sibling_comm.size());
932 const Index cur_rank = Index(sibling_comm.rank());
933 const Index elems_per_rank = num_elems/num_procs + Index((num_elems%num_procs)>0u);
934
935 // reserve the vector
936 std::vector<Index> masked_elems;
937 masked_elems.reserve(elems_per_rank);
938
939 // get the vertex set and the vertices-at-element index set
940 const auto& vtx = mesh.get_vertex_set();
941 const auto& verts_at_elem = mesh.template get_index_set<shape_dim, 0>();
942
943 // element bounding box coordinates
944 Tiny::Vector<CoordType, shape_dim> elbox_min, elbox_max;
945
946 // loop over all elements
947 for(Index ielem = cur_rank*elems_per_rank; ielem < Math::min((cur_rank+1u)*elems_per_rank, num_elems); ++ielem)
948 {
949 // compute bounding box of element
950 // note: actually, we should always have
951 // elbox_min = vtx[verts_at_elem(ielem, 0)]
952 // elbox_max = vtx[verts_at_elem(ielem, 1 << shape_dim - 1)]
953 // because of the element orientation of the base mesh, but we'll compute the bounding
954 // box for each element manually anyways, just to be sure in case that a derived class
955 // might give us a mesh object that is not directly refined from the base mesh using
956 // the standard 2-level refinement...
957 elbox_min = elbox_max = vtx[verts_at_elem(ielem, 0)];
958 for(int j(1); j < verts_at_elem.num_indices; ++j)
959 {
960 const auto& v = vtx[verts_at_elem(ielem, j)];
961 for(int k(0); k < shape_dim; ++k)
962 Math::minimax(v[k], elbox_min[k], elbox_max[k]);
963 }
964
965 // check the bounding box against the voxel map
966 if(this->_voxel_map->check_box(elbox_min, elbox_max))
967 masked_elems.push_back(ielem);
968 }
969
970 // communicate sizes of buffers
971 std::vector<int> recv_sizes(num_procs);
972 recv_sizes.at(cur_rank) = int(masked_elems.size());
973
974 sibling_comm.allgather(recv_sizes.data(), 1, recv_sizes.data(), 1);
975
976 // and now, create big buffer
977 std::vector<Index> gathered_mask(std::size_t(std::accumulate(recv_sizes.begin(), recv_sizes.end(), 0)), 0u);
978
979 // and also, we have to caclulate our displacements into our big buffer
980 std::vector<int> displacements;
981 displacements.reserve(recv_sizes.size());
982 std::exclusive_scan(recv_sizes.begin(), recv_sizes.end(), std::back_inserter(displacements), 0);
983
984 // and now gather
985 sibling_comm.allgatherv(masked_elems.data(), masked_elems.size(), gathered_mask.data(), recv_sizes.data(), displacements.data());
986
987 // return the list of all elements that we found
988 return gathered_mask;
989 }
990
1004 std::vector<WeightType> _gather_element_weights(const MeshType& mesh) const
1005 {
1006 const Index num_elems = mesh.get_num_elements();
1007
1008 // allocate the weight vector
1009 std::vector<WeightType> weights(num_elems, 0.0);
1010
1011 // get the vertex set and the vertices-at-element index set
1012 const auto& vtx = mesh.get_vertex_set();
1013 const auto& verts_at_elem = mesh.template get_index_set<shape_dim, 0>();
1014
1015 // element bounding box coordinates
1016 Tiny::Vector<CoordType, shape_dim> elbox_min, elbox_max;
1017
1018 // loop over all elements
1019 for(Index ielem(0); ielem < num_elems; ++ielem)
1020 {
1021 // compute bounding box of element
1022 // note: actually, we should always have
1023 // elbox_min = vtx[verts_at_elem(ielem, 0)]
1024 // elbox_max = vtx[verts_at_elem(ielem, 1 << shape_dim - 1)]
1025 // because of the element orientation of the base mesh, but we'll compute the bounding
1026 // box for each element manually anyways, just to be sure in case that a derived class
1027 // might give us a mesh object that is not directly refined from the base mesh using
1028 // the standard 2-level refinement...
1029 elbox_min = elbox_max = vtx[verts_at_elem(ielem, 0)];
1030 for(int j(1); j < verts_at_elem.num_indices; ++j)
1031 {
1032 const auto& v = vtx[verts_at_elem(ielem, j)];
1033 for(int k(0); k < shape_dim; ++k)
1034 Math::minimax(v[k], elbox_min[k], elbox_max[k]);
1035 }
1036
1037 // gather element weight based on the bounding box
1038 weights[ielem] = this->_voxel_map->sample_box(elbox_min, elbox_max);
1039 }
1040
1041 // returns the element weights
1042 return weights;
1043 }
1044
1060 virtual std::unique_ptr<MeshNodeType> _deslag_mesh_node(MeshNodeType& mesh_node)
1061 {
1062 XASSERTM(mesh_node.get_halo_map().empty(), "This function must not be used for partitioned mesh nodes!");
1063 return mesh_node.extract_patch(_gather_masked_elements(*mesh_node.get_mesh(), this->_comm), true, false, false);
1064 }
1065
1084 virtual std::unique_ptr<MeshNodeType> _deslag_mesh_node(MeshNodeType& mesh_node, const Ancestor& ancestor, bool is_child)
1085 {
1086 const auto* prod_comm = is_child ? &ancestor.progeny_comm : nullptr;
1087 std::unique_ptr<MeshNodeType> new_node = prod_comm ? mesh_node.extract_patch(_gather_masked_elements(*mesh_node.get_mesh(), *prod_comm), true, false, false):
1088 mesh_node.extract_patch(_gather_masked_elements(*mesh_node.get_mesh()), true, false, false);
1089 this->_deslag_patch_halos(*new_node, mesh_node, ancestor, is_child);
1090 return new_node;
1091 }
1092
1111 MeshNodeType& patch_mesh_node,
1112 const MeshNodeType& base_mesh_node,
1113 const Ancestor& ancestor,
1114 bool is_child)
1115 {
1116 // get the map of the base-mesh halos
1117 const std::map<int, std::unique_ptr<MeshPartType>>& base_halo_map = base_mesh_node.get_halo_map();
1118
1119 // if the base mesh has no halos, then we can jump out of here
1120 if(base_halo_map.empty())
1121 return;
1122
1123 // get number of halos
1124 const std::size_t num_halos = base_halo_map.size();
1125
1126 // create a halo splitter
1127 Geometry::PatchHaloSplitter<MeshType> halo_splitter(*base_mesh_node.get_mesh(), *base_mesh_node.get_patch(-1));
1128
1129 // add each base-mesh halo to our halo splitter and store the resulting split data size
1130 std::vector<int> halo_ranks;
1131 std::vector<std::size_t> halo_send_sizes;
1132 for(auto it = base_halo_map.begin(); it != base_halo_map.end(); ++it)
1133 {
1134 // store halo rank
1135 halo_ranks.push_back(it->first);
1136
1137 // add halo and compute send buffer size
1138 halo_send_sizes.push_back(halo_splitter.add_halo(it->first, *it->second));
1139 }
1140
1141 // This vector will receive the split halo data from all our potential neighbor processes
1142 std::vector<std::size_t> halo_recv_sizes(num_halos);
1143 std::vector<std::vector<Index>> halo_send_data(num_halos), halo_recv_data(num_halos);
1144 Dist::RequestVector halo_recv_reqs(num_halos), halo_send_reqs(num_halos);
1145
1146 // get the layer index of our comm layer; the ancestor layer unless we got the child ancestry during
1147 // multi-layered partitioning; this may be equal to -1 in either case if this process does not participate
1148 // in that corresponding layer
1149 const int layer_idx = is_child ? ancestor.layer_p : ancestor.layer;
1150
1151 // split and serialize halos and store sizes
1152 for(std::size_t i(0); i < num_halos; ++i)
1153 {
1154 // serialize the split halo into the send data buffer
1155 if(halo_send_sizes.at(i) > std::size_t(0))
1156 halo_send_data.at(i) = halo_splitter.serialize_split_halo(halo_ranks[i], -1);
1157 }
1158
1159 // exchange halo send data sizes over the corresponding layer communicator
1160 if(layer_idx >= 0)
1161 {
1162 // get the corresponding layer communicator
1163 const Dist::Comm& layer_comm = this->_layers.at(std::size_t(layer_idx))->comm();
1164
1165 // exchange halos sizes
1166 for(std::size_t i(0); i < num_halos; ++i)
1167 {
1168 // post receive requests
1169 halo_recv_reqs[i] = layer_comm.irecv(&halo_recv_sizes[i], std::size_t(1), halo_ranks[i]);
1170
1171 // post send requests
1172 halo_send_reqs[i] = layer_comm.isend(&halo_send_sizes[i], std::size_t(1), halo_ranks[i]);
1173 }
1174
1175 // wait for sends and receives to finish
1176 halo_recv_reqs.wait_all();
1177 halo_send_reqs.wait_all();
1178
1179 // exchange halo data
1180 for(std::size_t i(0); i < num_halos; ++i)
1181 {
1182 // do we receive any data from our neighbor?
1183 if(halo_recv_sizes[i] > Index(0))
1184 {
1185 // resize buffer and post receive
1186 halo_recv_data.at(i).resize(halo_recv_sizes[i]);
1187 halo_recv_reqs[i] = layer_comm.irecv(halo_recv_data.at(i).data(), halo_recv_sizes.at(i), halo_ranks[i]);
1188 }
1189
1190 // do we send any data to our neighbor?
1191 if(halo_send_sizes.at(i) > Index(0))
1192 {
1193 // post send of actual halo buffer
1194 halo_send_reqs[i] = layer_comm.isend(halo_send_data.at(i).data(), halo_send_sizes.at(i), halo_ranks[i]);
1195 }
1196 }
1197
1198 // wait for sends and receives to finish
1199 halo_recv_reqs.wait_all();
1200 halo_send_reqs.wait_all();
1201 }
1202
1203 // broadcast halo receive data over progeny comm in case of multi-layered partitioning
1204 if(is_child)
1205 {
1206 // broadcast sizes
1207 ancestor.progeny_comm.bcast(halo_recv_sizes.data(), num_halos, 0);
1208
1209 // allocate buffers
1210 if(ancestor.progeny_comm.rank() != 0)
1211 {
1212 for(std::size_t i(0); i < num_halos; ++i)
1213 halo_recv_data.at(i).resize(halo_recv_sizes[i]);
1214 }
1215
1216 // broadcast all halos
1217 for(std::size_t i(0); i < num_halos; ++i)
1218 {
1219 if(halo_recv_sizes[i] > std::size_t(0))
1220 ancestor.progeny_comm.bcast(halo_recv_data[i].data(), halo_recv_sizes[i], 0);
1221 }
1222 }
1223
1224 /*{
1225 String s;
1226 for(std::size_t i(0); i < num_halos; ++i)
1227 {
1228 s += stringify(halo_ranks[i]);
1229 s += " >";
1230 for(Index j(halo_recv_data[i]); j < halo_recv_data[i+1]; ++j)
1231 (s += " ") += stringify(halo_recv_data[j]);
1232 s += "\n";
1233 }
1234 this->_comm.allprint(s);
1235 }*/
1236
1237 // create a vector of split halo sizes
1238 std::vector<std::array<Index, shape_dim+1>> halo_send_intsec_sizes(num_halos), halo_recv_intsec_sizes(num_halos);
1239
1240 // process all halos
1241 for(std::size_t i(0); i < num_halos; ++i)
1242 {
1243 // did we receive any data from our neighbor?
1244 if(halo_recv_sizes.at(i) == Index(0))
1245 continue;
1246
1247 // intersect with our other halo
1248 if(!halo_splitter.intersect_split_halo(halo_ranks[i], halo_recv_data.at(i), 0u))
1249 continue; // no intersection between halos
1250
1251 // create the new halo
1252 std::unique_ptr<MeshPartType> split_halo = halo_splitter.make_unique();
1253
1254 // store the entity counts of the halo in our split sizes vector
1255 for(int j(0); j <= shape_dim; ++j)
1256 halo_send_intsec_sizes[i][Index(j)] = split_halo->get_num_entities(j);
1257
1258 // create new halo mesh-part
1259 patch_mesh_node.add_halo(halo_ranks[i], std::move(split_halo));
1260 }
1261
1262 // exchange halo intersected halo sizes over progeny comm; we do this just to ensure consistency
1263 if((ancestor.layer_p >= 0) || (!is_child && (ancestor.layer >= 0)))
1264 {
1265 // get the corresponding layer communicator
1266 const LayerType& layer = *this->_layers.at(std::size_t(is_child ? ancestor.layer_p : ancestor.layer));
1267
1268 // exchange intersected halo sizes
1269 for(std::size_t i(0); i < num_halos; ++i)
1270 {
1271 halo_recv_reqs[i] = layer.comm().irecv(halo_recv_intsec_sizes.at(i).data(), std::size_t(shape_dim+1), halo_ranks[i]);
1272 halo_send_reqs[i] = layer.comm().isend(halo_send_intsec_sizes.at(i).data(), std::size_t(shape_dim+1), halo_ranks[i]);
1273 }
1274
1275 // wait for sends and receives to finish
1276 halo_recv_reqs.wait_all();
1277 halo_send_reqs.wait_all();
1278
1279 // ensure that the halo sizes are consistent between neighboring processes
1280 for(std::size_t i(0); i < num_halos; ++i)
1281 {
1282 for(int j(0); j <= shape_dim; ++j)
1283 {
1284 if(halo_recv_intsec_sizes[i][Index(j)] != halo_send_intsec_sizes[i][Index(j)])
1285 {
1286 String msg = "Inconsistent deslagged halo size between process ";
1287 msg += stringify(this->_comm.rank());
1288 msg += " and neighbor with layer rank ";
1289 msg += stringify(halo_ranks[i]);
1290
1291 // abort execution
1292 XABORTM(msg.c_str());
1293 }
1294 }
1295 }
1296 }
1297 }
1298
1299 // virtual bool _parse_parti_type(const String& type) override
1300 // {
1301 // if(type.compare_no_case("extern") == 0)
1302 // return this->_allow_parti_extern = true;
1303 // // else if(type.compare_no_case("2level") == 0)
1304 // // return _allow_parti_2level = true;
1305 // else
1306 // return BaseClass::_parse_parti_type(type);
1307 // }
1308
1309 Adjacency::Coloring _compute_unstructered_coloring(const MeshNodeType& base_node) const
1310 {
1311 const auto& verts_at_elem = base_node.get_mesh()->template get_index_set<MeshType::shape_dim, 0>();
1312 Adjacency::Graph elems_at_vert(Adjacency::RenderType::transpose, verts_at_elem);
1313 Adjacency::Graph elems_at_elem(Adjacency::RenderType::injectify, verts_at_elem, elems_at_vert);
1314 return Adjacency::Coloring(elems_at_elem);
1315 }
1316
1317 Adjacency::Coloring _compute_unstructered_layering(const MeshNodeType& DOXY(base_node)) const
1318 {
1319 // ASSERTM(false, "Unstructured layering computation not implemented yet!");
1320 #ifdef FEAT_DEBUG_MODE
1321 std::cout << "Unstructered Layering Computation not implemented yet!";
1322 #endif
1323 return Adjacency::Coloring();
1324 }
1325
1336 {
1337 // get element target set of slag patch
1338 const Geometry::MeshPart<MeshType>* slag_part = slag_node.get_patch(-1);
1339 XASSERT(slag_part != nullptr);
1340 const Geometry::TargetSet& slag_target = slag_part->template get_target_set<MeshType::shape_dim>();
1341
1342 // number of colors = 2^shape_dim
1343 const Index num_colors = Index(1) << MeshType::shape_dim;
1344 const Index num_elems = slag_target.get_num_entities();
1345
1346 // allocate coloring
1347 Adjacency::Coloring coloring(num_elems, num_colors);
1348 Index* colors = coloring.get_coloring();
1349
1350 // unrefined base mesh: structured numbering
1351 if constexpr(MeshType::shape_dim == 1)
1352 {
1353 for(Index i(0); i < num_elems; ++i)
1354 colors[i] = slag_target[i] & 1;
1355 }
1356 else if constexpr(MeshType::shape_dim == 2)
1357 {
1358 for(Index i(0); i < num_elems; ++i)
1359 {
1360 Index iel = slag_target[i];
1361 Index ix = iel % this->_base_slices[0];
1362 Index iy = iel / this->_base_slices[0];
1363 colors[i] = (ix & 1) | ((iy & 1) << 1);
1364 }
1365 }
1366 else if constexpr(MeshType::shape_dim == 3)
1367 {
1368 for(Index i(0); i < num_elems; ++i)
1369 {
1370 Index iel = slag_target[i];
1371 Index ix = iel % this->_base_slices[0];
1372 Index iy = (iel / this->_base_slices[0]) % this->_base_slices[1];
1373 Index iz = iel / (this->_base_slices[0] * this->_base_slices[1]);
1374 colors[i] = (ix & 1) | ((iy & 1) << 1) | ((iz & 1) << (1 << 1));
1375 }
1376 }
1377
1378 return coloring;
1379 }
1380
1391 {
1392 // get element target set of slag patch
1393 const Geometry::MeshPart<MeshType>* slag_part = slag_node.get_patch(-1);
1394 XASSERT(slag_part != nullptr);
1395 const Geometry::TargetSet& slag_target = slag_part->template get_target_set<MeshType::shape_dim>();
1396
1397 // number of colors = 2^shape_dim
1398 const Index num_colors = Index(1) << MeshType::shape_dim;
1399 const Index num_elems = slag_target.get_num_entities();
1400
1401 // allocate coloring
1402 Adjacency::Coloring coloring(num_elems, num_colors);
1403 Index* colors = coloring.get_coloring();
1404
1405 // color of element i = i % num_colors
1406 for(Index i(0); i < num_elems; ++i)
1407 colors[i] = slag_target[i] % num_colors;
1408
1409 return coloring;
1410 }
1411
1427 Adjacency::Coloring _extract_patch_coloring(const MeshNodeType& slag_node, const Adjacency::Coloring& parent_coloring, int child_rank) const
1428 {
1429 // get element target set of patch
1430 const Geometry::MeshPart<MeshType>* patch_part = slag_node.get_patch(child_rank);
1431 XASSERT(patch_part != nullptr);
1432 const Geometry::TargetSet& patch_target = patch_part->template get_target_set<MeshType::shape_dim>();
1433
1434 // number of colors = 2^shape_dim
1435 const Index num_colors = parent_coloring.get_num_colors();
1436 const Index num_elems = patch_target.get_num_entities();
1437
1438 // allocate coloring
1439 Adjacency::Coloring coloring(num_elems, num_colors);
1440 Index* colors = coloring.get_coloring();
1441
1442 // color of element i = i % num_colors
1443 for(Index i(0); i < num_elems; ++i)
1444 colors[i] = parent_coloring[patch_target[i]];
1445
1446 return coloring;
1447 }
1448
1459 {
1460 // get element target set of slag patch
1461 const Geometry::MeshPart<MeshType>* slag_part = slag_node.get_patch(-1);
1462 XASSERT(slag_part != nullptr);
1463 const Geometry::TargetSet& slag_target = slag_part->template get_target_set<MeshType::shape_dim>();
1464
1465 // maximum number of layers = number of slices in highest dimensions; this may be less than
1466 // base_slices[shape_dim], since entire layers might have been removed during the deslagging process
1467 const Index max_layers = this->_base_slices[shape_dim-1];
1468 const Index num_elems = slag_target.get_num_entities();
1469
1470 // compute denominator for layer index computation
1471 Index denom = 1u;
1472 for(int j(0); j+1 < shape_dim; ++j)
1473 denom *= this->_base_slices[Index(j)];
1474
1475 // compute number of elements for each potential layer
1476 std::vector<Index> aux(max_layers, 0u);
1477 for(Index i(0); i < num_elems; ++i)
1478 ++aux[slag_target[i] / denom];
1479
1480 // count number of actually used layers
1481 Index num_layers = 0u;
1482 for(Index i(0); i < max_layers; ++i)
1483 {
1484 Index k = num_layers;
1485 if(aux[i] > 0u)
1486 ++num_layers;
1487 aux[i] = k;
1488 }
1489
1490 // compute layering
1491 Adjacency::Coloring layering(num_elems, num_layers);
1492 Index* layers = layering.get_coloring();
1493 for(Index i(0); i < num_elems; ++i)
1494 layers[i] = aux[slag_target[i] / denom];
1495
1496 return layering;
1497 }
1498
1509 {
1511 {
1512 return Adjacency::Coloring();
1513 }
1514 // get element target set of slag patch
1515 const Geometry::MeshPart<MeshType>* slag_part = slag_node.get_patch(-1);
1516 XASSERT(slag_part != nullptr);
1517 const Geometry::TargetSet& slag_target = slag_part->template get_target_set<MeshType::shape_dim>();
1518
1519 // maximum number of layers = twice the number of layers in coarse mesh; this may actually be less,
1520 // since entire layers might have been removed during the deslagging process
1521 const Index max_layers = 2 * coarse_layering.get_num_colors();
1522 const Index num_elems = slag_target.get_num_entities();
1523
1524 // compute number of elements for each potential layer
1525 std::vector<Index> aux(max_layers, 0u);
1526 for(Index i(0); i < num_elems; ++i)
1527 {
1528 Index qux = slag_target[i] >> (shape_dim - 1);
1529 ++aux[(coarse_layering[qux >> 1] << 1) | (qux & 1)]; // all hail to bit-shift magic!
1530 }
1531
1532 // count number of actually used layers
1533 Index num_layers = 0u;
1534 for(Index i(0); i < max_layers; ++i)
1535 {
1536 Index k = num_layers;
1537 if(aux[i] > 0u)
1538 ++num_layers;
1539 aux[i] = k;
1540 }
1541
1542 // compute layering
1543 Adjacency::Coloring layering(num_elems, num_layers);
1544 Index* layers = layering.get_coloring();
1545 for(Index i(0); i < num_elems; ++i)
1546 {
1547 Index qux = slag_target[i] >> (shape_dim - 1);
1548 layers[i] = aux[(coarse_layering[qux >> 1] << 1) | (qux & 1)];
1549 }
1550
1551 return layering;
1552 }
1553
1569 Adjacency::Coloring _extract_patch_layering(const MeshNodeType& slag_node, const Adjacency::Coloring& parent_layering, int child_rank) const
1570 {
1572 return Adjacency::Coloring();
1573 // get element target set of patch
1574 const Geometry::MeshPart<MeshType>* patch_part = slag_node.get_patch(child_rank);
1575 XASSERT(patch_part != nullptr);
1576 const Geometry::TargetSet& patch_target = patch_part->template get_target_set<MeshType::shape_dim>();
1577
1578 // maximum number of layers = number of layers in parent layering; this may actually be less,
1579 // since entire layers might have been removed during the deslagging process
1580 const Index max_layers = parent_layering.get_num_colors();
1581 const Index num_elems = patch_target.get_num_entities();
1582
1583 // compute number of elements for each potential layer
1584 std::vector<Index> aux(max_layers, 0u);
1585 for(Index i(0); i < num_elems; ++i)
1586 ++aux[parent_layering[patch_target[i]]];
1587
1588 // count number of actually used layers
1589 Index num_layers = 0u;
1590 for(Index i(0); i < max_layers; ++i)
1591 {
1592 Index k = num_layers;
1593 if(aux[i] > 0u)
1594 ++num_layers;
1595 aux[i] = k;
1596 }
1597
1598 // compute layering
1599 Adjacency::Coloring layering(num_elems, num_layers);
1600 Index* layers = layering.get_coloring();
1601 for(Index i(0); i < num_elems; ++i)
1602 layers[i] = aux[parent_layering[patch_target[i]]];
1603
1604 return layering;
1605 }
1606
1618 virtual void _create_single_process(std::unique_ptr<MeshNodeType> base_mesh_node)
1619 {
1620 // create and push single layer
1621 this->push_layer(std::make_shared<LayerType>(this->_comm.comm_dup(), 0));
1622
1623 // create single ancestry
1625 Ancestor& ancestor = this->_ancestry.front();
1626
1627 // use the whole base mesh here
1628 ancestor.parti_info = "Using base-mesh";
1629
1630 // save slagged base mesh node
1631 std::unique_ptr<MeshNodeType> base_slag_node = std::move(base_mesh_node);
1632 // deslag base mesh node
1633 base_mesh_node = this->_deslag_mesh_node(*base_slag_node);
1634
1635 // compute base-mesh layering
1636 Adjacency::Coloring base_layering = _unstructered_mesh ? this->_compute_unstructered_layering(*base_mesh_node) : this->_compute_base_mesh_layering(*base_slag_node);
1637
1638 // refine and deslag up to desired minimum level
1639 int lvl = 0;
1640 for(; lvl < ancestor.desired_level_min; ++lvl)
1641 {
1642 base_slag_node = base_mesh_node->refine_unique(this->_adapt_mode);
1643 base_mesh_node = this->_deslag_mesh_node(*base_slag_node);
1644 base_layering = _unstructered_mesh ? this->_compute_unstructered_layering(*base_mesh_node) : this->_compute_refined_mesh_layering(*base_slag_node, base_layering);
1645 }
1646
1647 // compute coloring for the coarse level
1648 Adjacency::Coloring base_coloring;
1650 {
1651 base_coloring = this->_compute_unstructered_coloring(*base_mesh_node);
1652 }
1653 else
1654 {
1655 if(lvl == 0)
1656 base_coloring = this->_compute_base_mesh_coloring(*base_slag_node);
1657 else
1658 base_coloring = this->_compute_refined_mesh_coloring(*base_slag_node);
1659 }
1660
1661 // save chosen minimum level if it is not equal to the desired maximum level
1662 if(lvl < ancestor.desired_level_max)
1663 this->_chosen_levels.push_front(std::make_pair(lvl, 0));
1664
1665 // refine up to maximum level and push to control
1666 for(; lvl < ancestor.desired_level_max; ++lvl)
1667 {
1668 // refine the base mesh
1669 auto refined_node = base_mesh_node->refine_unique(this->_adapt_mode);
1670
1671 // push this level
1672 std::shared_ptr<LevelType> level_ptr = std::make_shared<LevelType>(lvl, std::move(base_mesh_node),
1673 std::move(base_slag_node), std::move(base_coloring), std::move(base_layering));
1674 this->push_level_front(0, level_ptr);
1675
1676 // continue with refined node
1677 base_slag_node = std::move(refined_node);
1678 base_mesh_node = this->_deslag_mesh_node(*base_slag_node);
1679 base_coloring = _unstructered_mesh ? this->_compute_unstructered_coloring(*base_mesh_node) : this->_compute_refined_mesh_coloring(*base_slag_node);
1680 base_layering = _unstructered_mesh ? this->_compute_unstructered_layering(*base_mesh_node) : this->_compute_refined_mesh_layering(*base_slag_node, level_ptr->element_layering);
1681 }
1682
1683 // save chosen maximum level
1684 this->_chosen_levels.push_front(std::make_pair(lvl, 1));
1685
1686 // push finest level
1687 this->push_level_front(0, std::make_shared<LevelType>(lvl, std::move(base_mesh_node),
1688 std::move(base_slag_node), std::move(base_coloring), std::move(base_layering)));
1689 }
1690
1691 // Note: all following member functions are only required for parallel builds,
1692 // so we enclose them in the following #if-block to reduce compile times.
1693
1694#if defined(FEAT_HAVE_MPI) || defined(DOXYGEN)
1695
1702 virtual void _create_single_layered(std::unique_ptr<MeshNodeType> base_mesh_node)
1703 {
1704 // create and push single layer
1705 std::shared_ptr<LayerType> layer = std::make_shared<LayerType>(this->_comm.comm_dup(), 0);
1706 this->push_layer(layer);
1707
1708 // create single-layered ancestry
1710 Ancestor& ancestor = this->_ancestry.front();
1711
1712 XASSERTM(!this->_keep_base_levels, "VoxelDomainControl cannot keep base levels!");
1713
1714 // save slagged base mesh node
1715 std::unique_ptr<MeshNodeType> base_slag_node = std::move(base_mesh_node);
1716
1717 // deslag base mesh node
1718 base_mesh_node = this->_deslag_mesh_node(*base_slag_node);
1719 Adjacency::Coloring base_coloring;
1720 Adjacency::Coloring base_layering = _unstructered_mesh ? this->_compute_unstructered_layering(*base_mesh_node) : this->_compute_base_mesh_layering(*base_slag_node);
1721
1722 // refine up to chosen partition level
1723 int lvl = 0;
1724 for(; lvl <= ancestor.desired_level_max; ++lvl)
1725 {
1726 // can we apply a partitioner?
1727 bool enough_elems = (base_mesh_node->get_mesh()->get_num_elements() >= Index(this->_required_elems_per_rank) * Index(ancestor.num_procs));
1728 if((lvl >= ancestor.parti_level) && enough_elems && this->_apply_parti(ancestor, *base_mesh_node))
1729 break;
1730
1731 // no partitioning found?
1732 if(lvl >= ancestor.desired_level_max)
1733 break;
1734
1735 // refine and deslag base mesh node
1736 base_slag_node = base_mesh_node->refine_unique(this->_adapt_mode);
1737 base_mesh_node = this->_deslag_mesh_node(*base_slag_node);
1738 base_coloring = _unstructered_mesh ? this->_compute_unstructered_coloring(*base_mesh_node) : this->_compute_refined_mesh_coloring(*base_slag_node);
1739 base_layering = _unstructered_mesh ? this->_compute_unstructered_layering(*base_mesh_node) : this->_compute_refined_mesh_layering(*base_slag_node, base_layering);
1740 }
1741
1742 // no valid partitioning found?
1743 XASSERTM(ancestor.parti_found, "VoxelDomainControl failed to find a valid partitioning");
1744
1745 // set the selected partitioner level
1746 ancestor.parti_level = lvl;
1747
1748 // compute coloring if we're still on level 0; otherwise the coloring has been computed in the loop above
1749 if(lvl == 0)
1750 {
1751 base_coloring = _unstructered_mesh ? this->_compute_unstructered_coloring(*base_mesh_node) : this->_compute_refined_mesh_coloring(*base_slag_node);
1752 }
1753
1754 // extract our patch
1755 std::vector<int> neighbor_ranks;
1756 std::unique_ptr<MeshNodeType> patch_mesh_node(
1757 base_mesh_node->extract_patch(neighbor_ranks, ancestor.parti_graph, this->_comm.rank()));
1758
1759 // extract our coloring (only if we need it on this level)
1760 Adjacency::Coloring patch_coloring;
1761 if(lvl == ancestor.desired_level_min)
1762 patch_coloring = this->_extract_patch_coloring(*base_mesh_node, base_coloring, this->_comm.rank());
1763
1764 // extract layering
1765 Adjacency::Coloring patch_layering = this->_extract_patch_layering(*base_mesh_node, base_layering, this->_comm.rank());
1766
1767 // set the neighbor ranks of our child layer
1768 layer->set_neighbor_ranks(neighbor_ranks);
1769
1770 // create an empty patch slag node
1771 std::unique_ptr<MeshNodeType> patch_slag_node;
1772
1773 // refine up to minimum level
1774 for(; lvl < ancestor.desired_level_min; ++lvl)
1775 {
1776 // refine the patch mesh
1777 patch_slag_node = patch_mesh_node->refine_unique(this->_adapt_mode);
1778 patch_mesh_node = this->_deslag_mesh_node(*patch_slag_node, ancestor, false);
1779 patch_layering = _unstructered_mesh ? this->_compute_unstructered_layering(*patch_mesh_node) : this->_compute_refined_mesh_layering(*patch_slag_node, patch_layering);
1780 }
1781
1782 // compute coloring if we don't have one yet
1783 if(patch_coloring.empty())
1784 patch_coloring = _unstructered_mesh ? this->_compute_unstructered_coloring(*patch_mesh_node) : this->_compute_refined_mesh_coloring(*patch_slag_node);
1785
1786 // save chosen minimum level
1787 if(lvl < ancestor.desired_level_max)
1788 this->_chosen_levels.push_front(std::make_pair(lvl, 0));
1789
1790 // refine up to maximum level
1791 for(; lvl < ancestor.desired_level_max; ++lvl)
1792 {
1793 // refine the patch mesh
1794 auto refined_node = patch_mesh_node->refine_unique(this->_adapt_mode);
1795
1796 // create new level
1797 std::shared_ptr<LevelType> level_ptr = std::make_shared<LevelType>(lvl, std::move(patch_mesh_node),
1798 std::move(patch_slag_node), std::move(patch_coloring), std::move(patch_layering));
1799
1800 // push this (unrefined) level
1801 this->push_level_front(0, level_ptr);
1802
1803 // continue with refined node
1804 patch_slag_node = std::move(refined_node);
1805 patch_mesh_node = this->_deslag_mesh_node(*patch_slag_node, ancestor, false);
1806 patch_coloring = _unstructered_mesh ? this->_compute_unstructered_coloring(*patch_mesh_node) : this->_compute_refined_mesh_coloring(*patch_slag_node);
1807 patch_layering = _unstructered_mesh ? this->_compute_unstructered_layering(*patch_mesh_node) : this->_compute_refined_mesh_layering(*patch_slag_node, level_ptr->element_layering);
1808 }
1809
1810 // save chosen maximum level
1811 this->_chosen_levels.push_front(std::make_pair(lvl, this->_comm.size()));
1812
1813 // push finest level
1814 this->push_level_front(0, std::make_shared<LevelType>(lvl, std::move(patch_mesh_node),
1815 std::move(patch_slag_node), std::move(patch_coloring), std::move(patch_layering)));
1816 }
1817
1824 virtual void _create_multi_layered(std::unique_ptr<MeshNodeType> base_mesh_node)
1825 {
1826 // create layers
1828
1829 // create ancestry
1831
1832 XASSERTM(!this->_keep_base_levels, "VoxelDomainControl cannot keep base levels!");
1833
1834 // we start counting at level 0
1835 int lvl = 0;
1836
1837 // deslag the base-mesh node and move pointer to a new parent-mesh pointer;
1838 // the base-mesh is always the one on the layer with only 1 process
1839 std::unique_ptr<MeshNodeType> parent_slag_node;
1840 std::unique_ptr<MeshNodeType> parent_mesh_node = this->_deslag_mesh_node(*base_mesh_node);
1841
1842 // create the coloring and layering for the unrefined base mesh
1843 Adjacency::Coloring parent_coloring = _unstructered_mesh ? this->_compute_unstructered_coloring(*parent_mesh_node) : this->_compute_base_mesh_coloring(*base_mesh_node);
1844 Adjacency::Coloring parent_layering = _unstructered_mesh ? this->_compute_unstructered_layering(*parent_mesh_node) : this->_compute_base_mesh_layering(*base_mesh_node);
1845
1846 base_mesh_node.reset();
1847
1848 // loop over all global layers in reverse order (coarse to fine)
1849 for(std::size_t slayer = this->_ancestry.size(); slayer > std::size_t(0); )
1850 {
1851 // is this the base-mesh layer aka the 1-process layer?
1852 const bool is_base_layer = (slayer == this->_ancestry.size());
1853
1854 --slayer;
1855
1856 // get the ancestor object
1857 Ancestor& ancestor = this->_ancestry.at(slayer);
1858
1859 // determine the minimum desired level of our parent layer
1860 int parent_min_lvl = -1;
1861 if(!is_base_layer)
1862 parent_min_lvl = this->_chosen_levels.front().first;
1863 else if(this->_ancestry.size() + 1u < this->_desired_levels.size())
1864 parent_min_lvl = this->_desired_levels.back().first;
1865
1866 // check available partitioning strategies
1867 this->_check_parti(ancestor, *parent_mesh_node, is_base_layer);
1868
1869 // the check_parti function returns the partitioning level w.r.t. the current
1870 // level (which may be > 0), so we have to compensate that by adding our current level:
1871 ancestor.parti_level += lvl;
1872 ancestor.parti_level = Math::max(ancestor.parti_level, ancestor.desired_level_min);
1873
1874 // Note: each progeny group within the main communicator may have chosen a different
1875 // partitioning level at this point. We will compensate this by adjusting the minimum
1876 // refinement level of the child layer after the partitioning step below.
1877
1878 // refine up to the chosen partitioning level
1879 //for(; lvl < ancestor.parti_level; ++lvl)
1880 for(; lvl <= ancestor.desired_level_max; ++lvl)
1881 {
1882 // can we apply a partitioner?
1883 if(lvl >= ancestor.parti_level)
1884 {
1885 // try to apply the partitioner
1886 this->_apply_parti(ancestor, *parent_mesh_node);
1887
1888 // partitioning successful?
1889 int parti_ok = ancestor.parti_found ? 1 : 0;
1890
1891 // check if all processes found a valid partitioning
1892 this->_comm.allreduce(&parti_ok, &parti_ok, std::size_t(1), Dist::op_min);
1893 if(parti_ok > 0)
1894 break;
1895
1896 // nope, at least one process did not receive a partition, so keep refining
1897 ancestor.parti_found = false;
1898 }
1899
1900 // no partitioning found?
1901 if(lvl >= ancestor.desired_level_max)
1902 break;
1903
1904 // refine and deslag the parent mesh node
1905 auto refined_node = parent_mesh_node->refine_unique(this->_adapt_mode);
1906
1907 // a level pointer for the unrefined level; we need this to access the parent layering
1908 std::shared_ptr<LevelType> level_ptr;
1909
1910 // push the base mesh into our parent layer if desired
1911 if((ancestor.layer_p >= 0) && (parent_min_lvl >= 0) && (lvl >= parent_min_lvl))
1912 {
1913 level_ptr = std::make_shared<LevelType>(lvl, std::move(parent_mesh_node),
1914 std::move(parent_slag_node), std::move(parent_coloring), std::move(parent_layering));
1915 this->push_level_front(ancestor.layer_p, level_ptr);
1916 }
1917
1918 // continue with refined node
1919 parent_slag_node = std::move(refined_node);
1920 parent_mesh_node = this->_deslag_mesh_node(*parent_slag_node, ancestor, !is_base_layer);
1921 parent_coloring = _unstructered_mesh ? this->_compute_unstructered_coloring(*parent_mesh_node) : this->_compute_refined_mesh_coloring(*parent_slag_node);
1922 parent_layering = _unstructered_mesh ? this->_compute_unstructered_layering(*parent_mesh_node) : this->_compute_refined_mesh_layering(*parent_slag_node,
1923 level_ptr ? level_ptr->element_layering : parent_layering);
1924 }
1925
1926 // no valid partitioning found?
1927 XASSERTM(ancestor.parti_found, "VoxelDomainControl failed to find a valid partitioning");
1928
1929 // set the selected partitioner level
1930 ancestor.parti_level = lvl;
1931
1932 // extract our patch
1933 std::vector<int> neighbor_ranks;
1934 std::unique_ptr<MeshNodeType> patch_mesh_node(
1935 parent_mesh_node->extract_patch(neighbor_ranks, ancestor.parti_graph, ancestor.progeny_child));
1936
1937 // extract our coloring
1938 Adjacency::Coloring patch_coloring = this->_extract_patch_coloring(*parent_mesh_node, parent_coloring, ancestor.progeny_child);
1939
1940 // extract our layering
1941 Adjacency::Coloring patch_layering = this->_extract_patch_layering(*parent_mesh_node, parent_layering, ancestor.progeny_child);
1942
1943 // create an empty patch slag node
1944 std::unique_ptr<MeshNodeType> patch_slag_node;
1945
1946 // translate neighbor ranks by progeny group to obtain the neighbor ranks
1947 // w.r.t. this layer's communicator
1948 {
1949 std::map<int,int> halo_map;
1950 for(auto& i : neighbor_ranks)
1951 {
1952 int old_i(i);
1953 halo_map.emplace(old_i, i += ancestor.progeny_group);
1954 }
1955 patch_mesh_node->rename_halos(halo_map);
1956 }
1957
1958 // does this process participate in the parent layer or do we need to keep the base-meshes anyways?
1959 if(ancestor.layer_p >= 0)
1960 {
1961 // Note: patch mesh-part for rank = 0 was already created by 'extract_patch' call
1962 for(int i(1); i < ancestor.num_parts; ++i)
1963 {
1964 parent_mesh_node->create_patch_meshpart(ancestor.parti_graph, i);
1965 }
1966 }
1967
1968 // make sure we choose the same minimum level for all processes, because we may
1969 // have chosen different partitioning levels for each patch
1970 int global_level_min = Math::max(ancestor.desired_level_min, ancestor.parti_level);
1971 this->_comm.allreduce(&global_level_min, &global_level_min, std::size_t(1), Dist::op_max);
1972
1973 // make sure our minimum level is greater than the minimum level of the previous layer,
1974 // because each layer must contain at least one non-ghost level
1975 if(!is_base_layer)
1976 global_level_min = Math::max(global_level_min, this->_chosen_levels.front().first+1);
1977
1978 // refine up to desired minimum level of this layer
1979 XASSERTM(lvl == global_level_min, "INTERNAL ERROR");
1980 /*for(; lvl < global_level_min; ++lvl)
1981 {
1982 // refine the base mesh node
1983 std::unique_ptr<MeshNodeType> coarse_slag_node(std::move(parent_slag_node));
1984 std::unique_ptr<MeshNodeType> coarse_mesh_node(std::move(parent_mesh_node));
1985 parent_slag_node = coarse_mesh_node->refine_unique(this->_adapt_mode);
1986 parent_mesh_node = this->_deslag_mesh_node(*parent_slag_node);
1987
1988 // push base mesh to parent layer if desired
1989 if((ancestor.layer_p >= 0) && (parent_min_lvl >= 0) && (lvl >= parent_min_lvl))
1990 {
1991 // clear patches before pushing this node as they are redundant here
1992 //coarse_mesh_node->clear_patches();
1993 this->push_level_front(ancestor.layer_p, std::make_shared<LevelType>(lvl, std::move(coarse_mesh_node), std::move(coarse_slag_node)));
1994 }
1995
1996 // refine the patch mesh
1997 //patch_slag_node = patch_mesh_node->refine_unique(this->_adapt_mode);
1998 //patch_mesh_node = this->_deslag_mesh_node(*patch_slag_node);
1999 patch_mesh_node = this->_deslag_mesh_node(*patch_mesh_node->refine_unique(this->_adapt_mode));
2000 }*/
2001
2002 // split the halos of our base-mesh and compute the halos of our patches from that
2003 //this->_split_basemesh_halos(ancestor, *parent_slag_node, *patch_slag_node, neighbor_ranks);
2004 this->_split_basemesh_halos(ancestor, *parent_mesh_node, *patch_mesh_node, neighbor_ranks);
2005
2006 // does this process participate in the child layer?
2007 if(ancestor.layer >= 0)
2008 {
2009 // set the neighbor ranks in our child layer
2010 this->_layers.at(std::size_t(ancestor.layer))->set_neighbor_ranks(neighbor_ranks);
2011 }
2012
2013 // set chosen minimum level for this layer
2014 if(!is_base_layer)
2015 this->_chosen_levels.push_front(std::make_pair(lvl, this->_ancestry.at(slayer+1u).num_procs));
2016 else if(parent_min_lvl < 0)
2017 this->_chosen_levels.push_front(std::make_pair(lvl, 0));
2018 else
2019 {
2020 this->_chosen_levels.push_front(std::make_pair(parent_min_lvl, 0));
2021 this->_chosen_levels.push_front(std::make_pair(lvl, 1));
2022 }
2023
2024 // a level pointer for the unrefined level; we need this to access the parent layering
2025 std::shared_ptr<LevelType> level_ptr;
2026
2027 // push the finest base-mesh
2028 if(ancestor.layer_p >= 0)
2029 {
2030 this->push_level_front(ancestor.layer_p, std::make_shared<LevelType>(lvl, std::move(parent_mesh_node),
2031 std::move(parent_slag_node), std::move(parent_coloring), std::move(parent_layering)));
2032 }
2033
2034 // continue with the next layer
2035 parent_slag_node = std::move(patch_slag_node);
2036 parent_mesh_node = std::move(patch_mesh_node);
2037 parent_coloring = std::move(patch_coloring);
2038 parent_layering = std::move(patch_layering);
2039 }
2040
2041 // get the desired maximum level
2042 // if we have more than one layer, make sure that the finest one contains at
2043 // least one level, as otherwise the finest global level would be a ghost level
2044 int desired_level_max = Math::max(this->_ancestry.front().desired_level_max, lvl+1);
2045
2046 for(; lvl < desired_level_max; ++lvl)
2047 {
2048 // refine the patch mesh
2049 auto refined_node = parent_mesh_node->refine_unique(this->_adapt_mode);
2050
2051 // a level pointer for the unrefined level; we need this to access the parent layering
2052 std::shared_ptr<LevelType> level_ptr = std::make_shared<LevelType>(lvl, std::move(parent_mesh_node),
2053 std::move(parent_slag_node), std::move(parent_coloring), std::move(parent_layering));
2054
2055
2056 // push patch mesh to this level
2057 this->push_level_front(0, level_ptr);
2058
2059 // continue with refined node
2060 parent_slag_node = std::move(refined_node);
2061 parent_mesh_node = this->_deslag_mesh_node(*parent_slag_node, this->_ancestry.front(), false);
2062 parent_coloring = _unstructered_mesh ? this->_compute_unstructered_coloring(*parent_mesh_node) : this->_compute_refined_mesh_coloring(*parent_slag_node);
2063 parent_layering = _unstructered_mesh ? this->_compute_unstructered_layering(*parent_mesh_node) : this->_compute_refined_mesh_layering(*parent_slag_node, level_ptr->element_layering);
2064 }
2065
2066 // set chosen maximum level for finest layer
2067 this->_chosen_levels.push_front(std::make_pair(lvl, this->_comm.size()));
2068
2069 // push finest level
2070 this->push_level_front(0, std::make_shared<LevelType>(lvl, std::move(parent_mesh_node),
2071 std::move(parent_slag_node), std::move(parent_coloring), std::move(parent_layering)));
2072 }
2073
2074#endif // defined(FEAT_HAVE_MPI) || defined(DOXYGEN)
2075 }; // class VoxelDomainControl<...>
2076 } // namespace Domain
2077 } // namespace Control
2078} // namespace FEAT
#define XABORTM(msg)
Abortion macro definition with custom message.
Definition: assertion.hpp:192
#define ASSERTM(expr, msg)
Debug-Assertion macro definition with custom message.
Definition: assertion.hpp:230
#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.
Coloring object implementation.
Definition: coloring.hpp:37
bool empty() const
Checks whether the coloring is empty.
Definition: coloring.hpp:223
Index * get_coloring()
Returns the coloring array.
Definition: coloring.hpp:175
Index get_num_colors() const
Returns the number of colors.
Definition: coloring.hpp:217
Adjacency Graph implementation.
Definition: graph.hpp:34
bool _keep_base_levels
keep base-mesh levels on root process?
int desired_level_max
the desired minimum and maximum refinement levels for this layer
int parti_level
the refinement level on which the patch is to be partitioned
String parti_info
a string containing some information about the chosen partitioning
bool parti_found
specifies whether a partitioning was found
int num_procs
the number of processes that participate in this layer
Adjacency::Graph parti_graph
this is the actual elements-at-rank partitioning graph
int layer_p
the index of the parent layer or -1, if this process is not part of the parent layer
int layer
the index of the layer that this ancestor object belongs to
int num_parts
the number of partitions for each patch of the parent layer
int progeny_child
Which direct child this process belongs to in its progeny group.
Base-Class for Hierarchical Domain Control implementations.
std::deque< std::pair< int, int > > _desired_levels
desired level deque
int _required_elems_per_rank
required number of elements per rank for a-posteriori partitioning
std::deque< std::pair< int, int > > _chosen_levels
chosen level deque
virtual void _create_ancestry_scattered()
Creates the layers for a multi-layered domain control in a scattered fashion.
Real WeightType
weight type for partitioner element weights; always Real
std::deque< Ancestor > _ancestry
the partition ancestry deque
Geometry::RootMeshNode< MeshType > MeshNodeType
our root mesh node type
LevelType::PartType MeshPartType
our mesh-part type
virtual void _create_ancestry_single()
Creates the ancestry for a single layer (or a single process)
Geometry::AdaptMode _adapt_mode
the adapt mode for refinement
int get_desired_level_max() const
Returns the desired maximum refinement level.
bool _was_created
specifies whether the domain control was already created
virtual bool _check_parti(Ancestor &ancestor, const MeshNodeType &mesh_node, bool is_base_layer)
Checks for an appropriate partitioning strategy.
bool _support_multi_layered
support multi-layered hierarchy?
virtual bool _apply_parti(Ancestor &ancestor, MeshNodeType &base_mesh_node)
Applies an a-posteriori partitioner.
virtual void _create_multi_layers_scattered()
Creates the layers for a multi-layered domain control in a scattered fashion.
virtual void _split_basemesh_halos(const Ancestor &ancestor, const MeshNodeType &base_mesh_node, MeshNodeType &patch_mesh_node, std::vector< int > &neighbor_ranks)
Splits the base-mesh halos and computes the inter-patch-mesh halos.
Hierarchical partitioned Voxel Domain Control.
void create_voxel_map_from_off(std::istream &is, bool invert, Real resolution)
Creates a voxel map based on a surface triangulation stored in an OFF file.
Adjacency::Coloring _extract_patch_coloring(const MeshNodeType &slag_node, const Adjacency::Coloring &parent_coloring, int child_rank) const
Extracts a patch coloring from the parent mesh coloring.
Adjacency::Coloring _compute_base_mesh_coloring(const MeshNodeType &slag_node) const
Computes the coloring for the unpartitioned base mesh.
virtual void _create_multi_layered(std::unique_ptr< MeshNodeType > base_mesh_node)
Creates a multi-layered mesh hierarchy.
std::unique_ptr< MeshNodeType > _base_mesh_node
the input base-mesh node on level 0
virtual std::unique_ptr< MeshNodeType > _deslag_mesh_node(MeshNodeType &mesh_node)
Deslags an unpartitioned mesh node including its mesh-parts.
std::vector< Index > _gather_masked_elements(const MeshType &mesh) const
Gather a vector of element indices that intersect the masked domain.
Geometry::VoxelMap::WriteResult write_voxel_map(const String &filename)
Writes the voxel map to a voxel map file.
void create_hierarchy()
Creates the domain level hierarchy.
bool _unstructered_mesh
specifies whether we use a non voxel base mesh
const StopWatch & get_watch_voxel_map() const
Returns a const reference to the StopWatch that measures the voxel-map creation phase.
Geometry::RootMeshNode< MeshType > MeshNodeType
our root mesh node type
static constexpr int shape_dim
shape dimension
void _precreate_voxel_map(Real resolution)
Pre-creates the voxel map by setting the bounding box and resolution.
Control::Domain::PartiDomainControlBase< DomainLevel_ > BaseClass
our base class
virtual void create(Geometry::MeshFileReader &)
Creates a domain control from a MeshFileReader.
const StopWatch & get_watch_hierarchy() const
Returns a const reference to the StopWatch that measures the base-mesh creation phase.
Adjacency::Coloring _compute_refined_mesh_layering(const MeshNodeType &slag_node, const Adjacency::Coloring &coarse_layering) const
Computes the layering for a refined mesh.
virtual void create(std::unique_ptr< MeshNodeType > &)
Creates a domain control from a base-mesh node.
Tiny::Vector< CoordType, shape_dim > _bbox_min
the bounding box of the structured domain
bool _keep_voxel_map
specifies whether to keep the voxel map after hierarchy creation
StopWatch _watch_create_base_mesh
a bunch of stop-watches
void create_voxel_map_from_lambda(Lambda_ &&lambda, Real resolution)
Creates a voxel map based on a lambda expression.
Adjacency::Coloring _compute_refined_mesh_coloring(const MeshNodeType &slag_node) const
Computes the coloring for a refined mesh.
MeshNodeType & create_base_mesh_2d(Index num_x, Index num_y, CoordType x_min, CoordType x_max, CoordType y_min, CoordType y_max)
Creates a 2D structured rectangle base mesh and returns its base-mesh node.
int _create_stage
creation stage to keep track what has already been initialized
void create_voxel_map(Geometry::VoxelMasker< CoordType, shape_dim > &masker, Real resolution=Real(0))
Creates a voxel map based on a VoxelMasker object.
virtual void create(const std::deque< String > &filenames, String dirpath="")
Creates a domain control from a list of filenames.
std::vector< WeightType > _gather_element_weights(const MeshType &mesh) const
Gathers the element slag weights for a given mesh.
const StopWatch & get_watch_base_mesh() const
Returns a const reference to the StopWatch that measures the base-mesh creation phase.
MeshType::CoordType CoordType
coordinate type
void set_voxel_map_out_of_bounds_balue(bool value)
Sets the out-of-bounds value for the voxel map.
std::vector< int > gather_vertex_voxel_map(Index level) const
Gathers the vertex voxel map on a given domain level.
virtual std::unique_ptr< MeshNodeType > _deslag_mesh_node(MeshNodeType &mesh_node, const Ancestor &ancestor, bool is_child)
Deslags a (potentially partitioned) mesh node including its mesh-parts and halos.
virtual void _create_single_layered(std::unique_ptr< MeshNodeType > base_mesh_node)
Creates a single-layered mesh hierarchy.
std::vector< WeightType > gather_element_voxel_weights(Index level) const
Gathers the element voxel map weights on a given domain level.
std::array< Index, shape_dim > _base_slices
number of element slices on base mesh level 0
Adjacency::Coloring _extract_patch_layering(const MeshNodeType &slag_node, const Adjacency::Coloring &parent_layering, int child_rank) const
Extracts a patch layering from the parent mesh layering.
VoxelDomainControl(const Dist::Comm &comm_, bool support_multi_layered)
Constructor.
Adjacency::Coloring _compute_base_mesh_layering(const MeshNodeType &slag_node) const
Computes the element layering for the unpartitioned base mesh.
MeshNodeType & create_base_mesh_3d(Index num_x, Index num_y, Index num_z, CoordType x_min, CoordType x_max, CoordType y_min, CoordType y_max, CoordType z_min, CoordType z_max)
Creates a 3D structured cuboid base mesh and returns its base-mesh node.
void create_voxel_map_from_chart(const Geometry::Atlas::ChartBase< MeshType > &chart, bool invert, Real resolution)
Creates a voxel map based on a chart.
Geometry::VoxelMap::ReadResult read_voxel_map(const String &filename)
Reads the voxel map from a voxel map file.
virtual void _create_single_process(std::unique_ptr< MeshNodeType > base_mesh_node)
Creates a single-layered mesh hierarchy for a single process.
const Geometry::VoxelMap & get_voxel_map() const
Returns a const reference to the internal voxel map.
void keep_voxel_map()
Instructs the domain controller to keep the voxel map after hierarchy creation.
void create_voxel_map_from_off(const String &filename, bool invert, Real resolution)
Creates a voxel map based on a surface triangulation stored in an OFF file.
std::vector< Index > _gather_masked_elements(const MeshType &mesh, const Dist::Comm &sibling_comm) const
Gather a vector of element indices that intersect the masked domain in a copperative manner.
std::unique_ptr< Geometry::VoxelMap > _voxel_map
the voxel map
virtual void _deslag_patch_halos(MeshNodeType &patch_mesh_node, const MeshNodeType &base_mesh_node, const Ancestor &ancestor, bool is_child)
Deslags the halos of a patch mesh node.
String dump_slag_layer_levels() const
Debugging function: Returns a string containing encoded slag layer level information.
Wrapper class for domain levels for VoxelDomainControl.
Adjacency::Coloring element_layering
element layering (stored as coloring)
DomainLevel_ BaseClass
our base-class; the actual domain level
std::shared_ptr< DomainLevel_ > slag_level
attachable slag level
Adjacency::Coloring element_coloring
element coloring
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
void allreduce(const void *sendbuf, void *recvbuf, std::size_t count, const Datatype &datatype, const Operation &op) const
Blocking All-Reduce.
Definition: dist.cpp:655
int size() const
Returns the size of this communicator.
Definition: dist.hpp:1506
Request irecv(void *buffer, std::size_t count, const Datatype &datatype, int source, int tag=0) const
Nonblocking Receive.
Definition: dist.cpp:716
Request isend(const void *buffer, std::size_t count, const Datatype &datatype, int dest, int tag=0) const
Nonblocking Send.
Definition: dist.cpp:704
Comm comm_dup() const
Creates a copy of this communicator.
Definition: dist.cpp:459
void allgatherv(const void *sendbuf, std::size_t sendcount, const Datatype &sendtype, void *recvbuf, const int *recvcounts, const int *displs, const Datatype &recvtype) const
Blocking gather-to-all.
Definition: dist.cpp:607
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
Communication Request vector class.
Definition: dist.hpp:640
void wait_all()
Blocks until all active requests are fulfilled.
Definition: dist.cpp:324
static void read_common(std::stringstream &stream, const String &filename, const Dist::Comm &comm, int root_rank=0)
Reads a common text file for all ranks.
MeshType * get_mesh()
Returns the mesh of this node.
Definition: mesh_node.hpp:225
Class template for partial meshes.
Definition: mesh_part.hpp:90
Base-Mesh Patch Halo splitter.
std::unique_ptr< RootMeshNode > extract_patch(std::vector< Index > &&elements, bool split_meshparts, bool split_halos, bool split_patches)
Extracts a patch from the root mesh as a new mesh node.
Definition: mesh_node.hpp:1151
const MeshPartType * get_patch(int rank) const
Returns a patch meshpart for a given child.
Definition: mesh_node.hpp:962
static std::unique_ptr< RootMeshNode > make_unique(std::unique_ptr< MeshType > mesh, MeshAtlasType *atlas=nullptr)
Creates a new RootMeshNode on the heap and returns a unique pointer to it.
Definition: mesh_node.hpp:837
const std::map< int, std::unique_ptr< MeshPartType > > & get_halo_map() const
Definition: mesh_node.hpp:896
void add_halo(int rank, std::unique_ptr< MeshPartType > halo_part)
Adds a halo mesh part to this mesh node.
Definition: mesh_node.hpp:874
Structured unit-cube mesh factory.
Target set class.
Definition: target_set.hpp:27
Index get_num_entities() const
Returns the number of entities.
Definition: target_set.hpp:92
helper class for read function result
Definition: voxel_map.hpp:502
helper class for write function result
Definition: voxel_map.hpp:462
Interface for voxel masker for the VoxelMap class.
Definition: voxel_map.hpp:71
Math Limits class template.
Definition: math.hpp:1475
static double toe_partition
time of partitioning in seconds, needs initialization
Definition: statistics.hpp:167
Stop-Watch class.
Definition: stop_watch.hpp:21
double elapsed() const
Returns the total elapsed time in seconds.
Definition: stop_watch.hpp:70
void start()
Starts the stop-watch.
Definition: stop_watch.hpp:43
void stop()
Stops the stop-watch and increments elapsed time.
Definition: stop_watch.hpp:51
String class implementation.
Definition: string.hpp:47
String pad_front(size_type len, char c=' ') const
Pads the front of the string up to a desired length.
Definition: string.hpp:393
Tiny Vector class template.
@ transpose
Render-Transpose mode.
@ injectify
Render-Injectified mode.
const Operation op_min(MPI_MIN)
Operation wrapper for MPI_MIN.
Definition: dist.hpp:275
const Operation op_max(MPI_MAX)
Operation wrapper for MPI_MAX.
Definition: dist.hpp:273
void minimax(T_ x, T_ &a, T_ &b)
Updates the minimum and maximum.
Definition: math.hpp:195
T_ min(T_ a, T_ b)
Returns the minimum of two values.
Definition: math.hpp:123
T_ max(T_ a, T_ b)
Returns the maximum of two values.
Definition: math.hpp:137
FEAT namespace.
Definition: adjactor.hpp:12
double Real
Real data type.
String stringify(const T_ &item)
Converts an item into a String.
Definition: string.hpp:993
@ value
specifies whether the space should supply basis function values
std::uint64_t Index
Index data type.