FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
mesh_node.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
9#include <kernel/geometry/adaptive_mesh.hpp>
10#include <kernel/geometry/conformal_mesh.hpp>
11#include <kernel/geometry/mesh_atlas.hpp>
12#include <kernel/geometry/mesh_part.hpp>
13#include <kernel/geometry/macro_factory.hpp>
14#include <kernel/geometry/partition_set.hpp>
15#include <kernel/geometry/patch_halo_factory.hpp>
16#include <kernel/geometry/patch_halo_splitter.hpp>
17#include <kernel/geometry/patch_mesh_factory.hpp>
18#include <kernel/geometry/patch_meshpart_factory.hpp>
19#include <kernel/geometry/patch_meshpart_splitter.hpp>
20#include <kernel/geometry/subdivision_levels.hpp>
21#include <kernel/geometry/intern/dual_adaptor.hpp>
22#include <kernel/adjacency/graph.hpp>
23
24// includes, STL
25#include <set>
26#include <map>
27#include <deque>
28#include <vector>
29
30namespace FEAT
31{
32 namespace Geometry
33 {
34 // forward declarations
36 namespace Intern
37 {
38 template<typename MeshType_>
39 struct TypeConverter;
40
41 template<int dim_>
42 struct AdjacenciesFiller;
43 }
44
45 template<typename Policy_>
46 class MeshPartNode DOXY({});
48
52 enum class AdaptMode
53 {
54 none = 0x0,
55 chart = 0x1,
56 dual = 0x2
57 };
58
61 {
62 return static_cast<AdaptMode>(int(x) | int(y));
63 }
64
66 {
67 return static_cast<AdaptMode>(int(x) & int(y));
68 }
69
73 inline std::ostream& operator<<(std::ostream& os, AdaptMode mode)
74 {
75 switch(mode)
76 {
77 case AdaptMode::none:
78 return os << "none";
79 case AdaptMode::chart:
80 return os << "chart";
81 case AdaptMode::dual:
82 return os << "dual";
83 default:
84 return os << "-unknown-";
85 }
86 }
87
88 inline void operator<<(AdaptMode& mode, const String& mode_name)
89 {
90 if(mode_name == "none")
91 mode = AdaptMode::none;
92 else if(mode_name == "chart")
93 mode = AdaptMode::chart;
94 else if(mode_name == "dual")
95 mode = AdaptMode::dual;
96 else
97 XABORTM("Unknown AdaptMode identifier string " + mode_name);
98 }
100
114 template<
115 typename RootMesh_,
116 typename ThisMesh_>
118 {
119 public:
121 typedef RootMesh_ RootMeshType;
123 typedef ThisMesh_ MeshType;
132
133 protected:
138 {
139 public:
141 std::unique_ptr<MeshPartNodeType> node;
146
147 public:
157 explicit MeshPartNodeBin(std::unique_ptr<MeshPartNodeType> node_, String chart_name_, const MeshChartType* chart_) :
158 node(std::move(node_)),
159 chart_name(chart_name_),
160 chart(chart_)
161 {
162 }
163
164 // use default move constructor
165 MeshPartNodeBin(MeshPartNodeBin&&) = default;
166
167 // use default move-assignment operator
168 MeshPartNodeBin& operator=(MeshPartNodeBin&&) = default;
169 }; // class MeshPartNodeBin
170
172 typedef std::map<String, MeshPartNodeBin> MeshPartNodeContainer;
174 typedef typename MeshPartNodeContainer::iterator MeshPartNodeIterator;
176 typedef typename MeshPartNodeContainer::const_iterator MeshPartNodeConstIterator;
178 typedef typename MeshPartNodeContainer::reverse_iterator MeshPartNodeReverseIterator;
179
180 protected:
182 std::unique_ptr<MeshType> _mesh;
185
186 protected:
193 explicit MeshNode(std::unique_ptr<MeshType> mesh) :
194 _mesh(std::move(mesh)),
196 {
197 }
198
199 public:
203 virtual ~MeshNode()
204 {
205 // nothing to do here thanks to std::unique_ptr
206 }
207
209 std::size_t bytes() const
210 {
211 std::size_t s(0);
212 if(_mesh != nullptr)
213 s += _mesh->bytes();
214 for(auto it = _mesh_part_nodes.begin(); it != _mesh_part_nodes.end(); ++it)
215 s += it->second.node->bytes();
216 return s;
217 }
218
226 {
227 return _mesh.get();
228 }
229
231 const MeshType* get_mesh() const
232 {
233 return _mesh.get();
234 }
235
236 void set_mesh(std::unique_ptr<MeshType> mesh)
237 {
238 XASSERTM(_mesh == nullptr, "Mesh node already has a mesh");
239 _mesh = std::move(mesh);
240 }
241
251 std::deque<String> get_mesh_part_names(bool no_internals = false) const
252 {
253 std::deque<String> names;
254 for(auto it = _mesh_part_nodes.begin(); it != _mesh_part_nodes.end(); ++it)
255 {
256 String mpname = (*it).first;
257 if(!(no_internals && (mpname.front() == '_')))
258 names.push_back(mpname);
259 }
260 return names;
261 }
262
282 const String& part_name,
283 std::unique_ptr<MeshPartNodeType> mesh_part_node,
284 const String& chart_name = "",
285 const MeshChartType* chart = nullptr)
286 {
287 if(mesh_part_node)
288 {
289 auto r = _mesh_part_nodes.emplace(part_name, MeshPartNodeBin(std::move(mesh_part_node), chart_name, chart));
290 if(r.second)
291 {
292 return r.first->second.node.get();
293 }
294 }
295 return nullptr;
296 }
297
317 const String& part_name,
318 std::unique_ptr<MeshPartType> mesh_part,
319 const String& chart_name = "",
320 const MeshChartType* chart = nullptr)
321 {
322 return add_mesh_part_node(part_name, MeshPartNodeType::make_unique(std::move(mesh_part)), chart_name, chart);
323 }
324
333 bool remove_mesh_part(const String& part_name)
334 {
335 return _mesh_part_nodes.erase(part_name) > std::size_t(0);
336 }
337
340 {
341 _mesh_part_nodes.clear();
342 }
343
357 bool set_mesh_part_chart(const String& part_name, const String& chart_name, const MeshChartType* chart)
358 {
359 MeshPartNodeIterator it(_mesh_part_nodes.find(part_name));
360 if(it == _mesh_part_nodes.end())
361 return false;
362 it->second.chart_name = chart_name;
363 it->second.chart = chart;
364 return true;
365 }
366
377 {
378 MeshPartNodeIterator it(_mesh_part_nodes.find(part_name));
379 return (it != _mesh_part_nodes.end()) ? it->second.node.get() : nullptr;
380 }
381
383 const MeshPartNodeType* find_mesh_part_node(const String& part_name) const
384 {
386 return (it != _mesh_part_nodes.end()) ? it->second.node.get() : nullptr;
387 }
388
399 {
400 MeshPartNodeType* node = find_mesh_part_node(part_name);
401 return (node != nullptr) ? node->get_mesh() : nullptr;
402 }
403
405 const MeshPartType* find_mesh_part(const String& part_name) const
406 {
407 const MeshPartNodeType* node = find_mesh_part_node(part_name);
408 return (node != nullptr) ? node->get_mesh() : nullptr;
409 }
410
421 const MeshChartType* find_mesh_part_chart(const String& part_name) const
422 {
424 return (it != _mesh_part_nodes.end()) ? it->second.chart : nullptr;
425 }
426
438 {
440 return (it != _mesh_part_nodes.end()) ? it->second.chart_name : String();
441 }
442
449 void rename_mesh_parts(const std::map<String,String>& renames)
450 {
451 if(renames.empty())
452 return;
453
454 MeshPartNodeContainer new_map;
455 for(auto& v : _mesh_part_nodes)
456 {
457 auto it = renames.find(v.first);
458 if(it == renames.end())
459 {
460 // no rename, use old name
461 new_map.emplace(v.first, std::move(v.second));
462 }
463 else
464 {
465 // insert with new name
466 new_map.emplace(it->second, std::move(v.second));
467 }
468 }
469 _mesh_part_nodes = std::move(new_map);
470 }
471
481 void adapt(bool recursive = true)
482 {
483 // loop over all mesh_part nodes
486 for(; it != jt; ++it)
487 {
488 // adapt child node
489 if(recursive)
490 {
491 it->second.node->adapt(true);
492 }
493
494 // adapt this node if a chart is given
495 if(it->second.chart != nullptr)
496 {
497 // we need to check whether the mesh part really exists
498 // because it may be nullptr in a parallel run, which
499 // indicates that the current patch is not adjacent to
500 // the boundary represented by the mesh part.
501 const MeshPartType* mesh_part = it->second.node->get_mesh();
502 if(mesh_part != nullptr)
503 it->second.chart->adapt(*_mesh, *mesh_part);
504 }
505 }
506 }
507
523 bool adapt_by_name(const String& part_name, bool recursive = false)
524 {
525 // Try to find the corresponding mesh_part node
526 MeshPartNodeIterator it(_mesh_part_nodes.find(part_name));
527 // Do not proceed if the mesh_part node does not exist or exists but is empty on the current patch
528 if(it == _mesh_part_nodes.end() || it->second.node->get_mesh() == nullptr)
529 return false;
530
531 // adapt child node
532 if(recursive)
533 {
534 it->second.node->adapt(true);
535 }
536
537 // Adapt this node if we have a chart
538 if(it->second.chart != nullptr)
539 {
540 it->second.chart->adapt(*_mesh, *(it->second.node->get_mesh()));
541 return true;
542 }
543
544 // no chart associated
545 return false;
546 }
547
553 static String name()
554 {
555 return "MeshNode<...>";
556 }
557
558 protected:
565 void refine_children(MeshNode& refined_node) const
566 {
567 // refine mesh parts
568 refine_mesh_parts(refined_node);
569 }
570
577 void refine_mesh_parts(MeshNode& refined_node) const
578 {
581
582 for(; it != jt; ++it)
583 {
584 refined_node.add_mesh_part_node(it->first, it->second.node->refine(*_mesh), it->second.chart_name, it->second.chart);
585 }
586 }
587 }; // class MeshNode
588
589 /* ***************************************************************************************** */
590
598 template<typename RootMesh_>
600 : public MeshNode<RootMesh_, MeshPart<RootMesh_>>
601 {
602 public:
605
614
615 protected:
616 void _clone(const MeshPartNode& other)
617 {
618 XASSERT(this->_mesh == nullptr);
619 XASSERT(this->_mesh_part_nodes.empty());
620
621 if(other._mesh != nullptr)
622 this->set_mesh(std::unique_ptr<MeshType>(new MeshType(other._mesh->clone())));
623
624 for(auto it = other._mesh_part_nodes.begin(); it != other._mesh_part_nodes.end(); ++it)
625 {
626 this->add_mesh_part_node(it->first, it->second.node->clone_unique(), it->second.chart_name, it->second.chart);
627 }
628 }
629
630 public:
637 explicit MeshPartNode(std::unique_ptr<MeshPartType> mesh_part) :
638 BaseClass(std::move(mesh_part))
639 {
640 }
641
644 {
645 }
646
656 static std::unique_ptr<MeshPartNode> make_unique(std::unique_ptr<MeshPartType> mesh_part)
657 {
658 return std::unique_ptr<MeshPartNode>(new MeshPartNode(std::move(mesh_part)));
659 }
660
666 std::unique_ptr<MeshPartNode> clone_unique() const
667 {
668 std::unique_ptr<MeshPartNode> node(new MeshPartNode(nullptr));
669 node->_clone(*this);
670 return node;
671 }
672
682 template<typename ParentType_>
683 std::unique_ptr<MeshPartNode> refine(const ParentType_& parent) const
684 {
685 // the mesh part may be a nullptr; in this case also return a node containing a nullptr
686 if(this->_mesh == nullptr)
687 {
688 return std::unique_ptr<MeshPartNode>(new MeshPartNode(nullptr));
689 }
690
691 // create a refinery
692 StandardRefinery<MeshPartType> refinery(*this->_mesh, parent);
693
694 // create a new MeshPartNode
695 auto fine_node = make_unique(refinery.make_unique());
696
697 // refine our children
698 refine_mesh_parts(*fine_node);
699
700 // okay
701 return fine_node;
702 }
703
709 static String name()
710 {
711 return "MeshPartNode<...>";
712 }
713
714 protected:
724 void refine_mesh_parts(MeshPartNode& refined_node) const
725 {
728 for(; it != jt; ++it)
729 {
730 refined_node.add_mesh_part_node(it->first, it->second.node->refine(*this->_mesh));
731 }
732 }
733
734 }; // class MeshPartNode<...>
735
736 /* ***************************************************************************************** */
737
745 template<typename RootMesh_>
747 : public MeshNode<RootMesh_, RootMesh_>
748 {
749 public:
752
761
762 protected:
766 std::map<int, std::unique_ptr<MeshPartType>> _halos;
768 std::map<int, std::unique_ptr<MeshPartType>> _patches;
769
770
771 void _clone(const RootMeshNode& other)
772 {
773 XASSERT(this->_mesh == nullptr);
774 XASSERT(this->_mesh_part_nodes.empty());
775
776 if(other._mesh != nullptr)
777 this->set_mesh(std::unique_ptr<MeshType>(new MeshType(other._mesh->clone())));
778
779 for(auto it = other._mesh_part_nodes.begin(); it != other._mesh_part_nodes.end(); ++it)
780 {
781 this->add_mesh_part_node(it->first, it->second.node->clone_unique(), it->second.chart_name, it->second.chart);
782 }
783
784 this->_atlas = other._atlas;
785
786 for(auto it = other._halos.begin(); it != other._halos.end(); ++it)
787 this->add_halo(it->first, std::unique_ptr<MeshPartType>(new MeshPartType(it->second->clone())));
788
789 for(auto it = other._patches.begin(); it != other._patches.end(); ++it)
790 this->add_patch(it->first, std::unique_ptr<MeshPartType>(new MeshPartType(it->second->clone())));
791 }
792
793
794 public:
804 explicit RootMeshNode(std::unique_ptr<MeshType> mesh, MeshAtlasType* atlas = nullptr) :
805 BaseClass(std::move(mesh)),
806 _atlas(atlas),
807 _halos(),
808 _patches()
809 {
810 }
811
816 {
817 }
818
821 {
822 return _atlas;
823 }
824
837 static std::unique_ptr<RootMeshNode> make_unique(std::unique_ptr<MeshType> mesh, MeshAtlasType* atlas = nullptr)
838 {
839 return std::unique_ptr<RootMeshNode>(new RootMeshNode(std::move(mesh), atlas));
840 }
841
847 std::unique_ptr<RootMeshNode> clone_unique() const
848 {
849 std::unique_ptr<RootMeshNode> node(new RootMeshNode(nullptr, nullptr));
850 node->_clone(*this);
851 return node;
852 }
853
855 std::size_t bytes() const
856 {
857 std::size_t s = BaseClass::bytes();
858 for(const auto& x : _halos)
859 s += x.second->bytes();
860 for(const auto& x : _patches)
861 s += x.second->bytes();
862 return s;
863 }
864
874 void add_halo(int rank, std::unique_ptr<MeshPartType> halo_part)
875 {
876 XASSERTM(bool(halo_part), "cannot add empty halos");
877 _halos.emplace(rank, std::move(halo_part));
878 }
879
889 const MeshPartType* get_halo(int rank) const
890 {
891 auto it = _halos.find(rank);
892 return (it != _halos.end() ? it->second.get() : nullptr);
893 }
894
896 const std::map<int, std::unique_ptr<MeshPartType>>& get_halo_map() const
897 {
898 return this->_halos;
899 }
900
903 {
904 _halos.clear();
905 }
906
916 void rename_halos(const std::map<int,int>& ranks)
917 {
918 if(ranks.empty())
919 return;
920
921 std::map<int, std::unique_ptr<MeshPartType>> new_halos;
922
923 for(auto& v : _halos)
924 {
925 auto it = ranks.find(v.first);
926 if(it == ranks.end())
927 new_halos.emplace(v.first, std::move(v.second));
928 else
929 new_halos.emplace(it->second, std::move(v.second));
930 }
931
932 _halos = std::move(new_halos);
933 }
934
947 MeshPartType* add_patch(int rank, std::unique_ptr<MeshPartType> patch_part)
948 {
949 XASSERT(patch_part != nullptr);
950 return _patches.emplace(rank, std::move(patch_part)).first->second.get();
951 }
952
962 const MeshPartType* get_patch(int rank) const
963 {
964 auto it = _patches.find(rank);
965 return (it != _patches.end() ? it->second.get() : nullptr);
966 }
967
969 const std::map<int, std::unique_ptr<MeshPartType>>& get_patch_map() const
970 {
971 return this->_patches;
972 }
973
976 {
977 _patches.clear();
978 }
979
989 std::unique_ptr<RootMeshNode> refine_unique(AdaptMode adapt_mode = AdaptMode::chart) const
990 {
991 // create a refinery
992 StandardRefinery<MeshType> refinery(*this->_mesh);
993
994 // create a new root mesh node
995 std::unique_ptr<RootMeshNode> fine_node = make_unique(refinery.make_unique(), this->_atlas);
996
997 // refine our children
998 this->refine_children(*fine_node);
999
1000 // refine our halos
1001 for(const auto& v : _halos)
1002 {
1003 if(v.second)
1004 {
1005 StandardRefinery<MeshPartType> halo_refinery(*v.second, *this->_mesh);
1006 fine_node->add_halo(v.first, halo_refinery.make_unique());
1007 }
1008 else
1009 fine_node->add_halo(v.first, nullptr);
1010 }
1011
1012 // refine our patch mesh-parts
1013 for(const auto& v : _patches)
1014 {
1015 if(v.second)
1016 {
1017 StandardRefinery<MeshPartType> patch_refinery(*v.second, *this->_mesh);
1018 fine_node->add_patch(v.first, patch_refinery.make_unique());
1019 }
1020 else
1021 fine_node->add_patch(v.first, nullptr);
1022 }
1023
1024 // adapt by chart?
1025 if((adapt_mode & AdaptMode::chart) != AdaptMode::none)
1026 {
1027 fine_node->adapt(true);
1028 }
1029
1030 // adapt dual?
1031 if((adapt_mode & AdaptMode::dual) != AdaptMode::none)
1032 {
1033 Intern::DualAdaptor<MeshType>::adapt(*fine_node->get_mesh(), *this->get_mesh());
1034 }
1035
1036 // okay
1037 return fine_node;
1038 }
1039
1049 template<typename TemplateSet_, typename VertexMarker_>
1050 std::unique_ptr<RootMeshNode> refine_partial_unique(const VertexMarker_& marker, AdaptMode adapt_mode = AdaptMode::chart) const
1051 {
1053
1054 // Create subdivision levels
1055 const Index num_vertices = this->_mesh->get_num_vertices();
1056 SubdivisionLevels sdls(num_vertices);
1057
1058 for(Index i(0); i < num_vertices; ++i)
1059 {
1060 sdls[i] = marker(i);
1061 }
1062
1063 AdaptiveMeshType adaptive_mesh(*this->_mesh);
1064 adaptive_mesh.adapt(sdls, AdaptiveMeshType::ImportBehaviour::All);
1065
1066 Layer top_layer{adaptive_mesh.num_layers() - 1};
1067
1068 // create a new root mesh node
1069 std::unique_ptr<RootMeshNode> fine_node = make_unique(
1070 std::make_unique<MeshType>(adaptive_mesh.to_conformal_mesh(top_layer)),
1071 this->_atlas);
1072
1073 // Projects mesh parts
1074 typename BaseClass::MeshPartNodeConstIterator it(this->_mesh_part_nodes.begin());
1076
1077 for(; it != jt; ++it)
1078 {
1079 auto new_mesh_part = std::make_unique<MeshPartType>(
1080 adaptive_mesh.template project_meshpart<MeshType>(top_layer, *(it->second.node->get_mesh())));
1081 auto new_mesh_part_node = std::make_unique<typename BaseClass::MeshPartNodeType>(std::move(new_mesh_part));
1082
1083 fine_node->add_mesh_part_node(
1084 it->first,
1085 std::move(new_mesh_part_node),
1086 it->second.chart_name,
1087 it->second.chart);
1088 }
1089
1090 // refine our halos
1091 for(const auto& v : _halos)
1092 {
1093 if(v.second)
1094 {
1095 auto new_halo = std::make_unique<MeshPartType>(adaptive_mesh.template project_meshpart<MeshType>(top_layer, *v.second));
1096 fine_node->add_halo(v.first, std::move(new_halo));
1097 }
1098 else
1099 fine_node->add_halo(v.first, nullptr);
1100 }
1101
1102 // refine our patch mesh-parts
1103 for(const auto& v : _patches)
1104 {
1105 if(v.second)
1106 {
1107 auto new_halo = std::make_unique<MeshPartType>(adaptive_mesh.template project_meshpart<MeshType>(top_layer, *v.second));
1108 fine_node->add_patch(v.first, std::move(new_halo));
1109 }
1110 else
1111 fine_node->add_patch(v.first, nullptr);
1112 }
1113
1114 // adapt by chart?
1115 if((adapt_mode & AdaptMode::chart) != AdaptMode::none)
1116 {
1117 fine_node->adapt(true);
1118 }
1119
1120 // adapt dual?
1121 if((adapt_mode & AdaptMode::dual) != AdaptMode::none)
1122 {
1123 Intern::DualAdaptor<MeshType>::adapt(*fine_node->get_mesh(), *this->get_mesh());
1124 }
1125
1126 // okay
1127 return fine_node;
1128 }
1129
1151 std::unique_ptr<RootMeshNode> extract_patch(std::vector<Index>&& elements,
1152 bool split_meshparts, bool split_halos, bool split_patches)
1153 {
1154 XASSERTM(!elements.empty(), "cannot create empty patch!");
1155
1156 // get our mesh
1157 const MeshType* base_root_mesh = this->get_mesh();
1158 XASSERTM(base_root_mesh != nullptr, "mesh node has no mesh");
1159
1160 // Step 1: create mesh part of the patch
1161 MeshPartType* patch_mesh_part = nullptr;
1162 {
1163 // create a factory for our partition
1164 PatchMeshPartFactory<MeshType> part_factory(std::forward<std::vector<Index>>(elements));
1165
1166 // create patch mesh part and add it to our map
1167 patch_mesh_part = this->add_patch(-1, part_factory.make_unique());
1168
1169 // deduct the target sets
1170 patch_mesh_part->template deduct_target_sets_from_top<MeshType::shape_dim>(
1171 base_root_mesh->get_index_set_holder());
1172 }
1173
1174 // Step 2: Create root mesh node of partition by using PatchMeshFactory
1175 std::unique_ptr<RootMeshNode> patch_node;
1176 {
1177 // create patch root mesh
1178 PatchMeshFactory<MeshType> patch_factory(*base_root_mesh, *patch_mesh_part);
1179 patch_node = RootMeshNode::make_unique(patch_factory.make_unique(), this->_atlas);
1180 }
1181
1182 // Step 3: intersect boundary and other base mesh parts
1183 if(split_meshparts)
1184 {
1185 // create mesh part splitter
1186 PatchMeshPartSplitter<MeshType> part_splitter(*base_root_mesh, *patch_mesh_part);
1187
1188 // get all mesh part names
1189 std::deque<String> part_names = this->get_mesh_part_names();
1190
1191 // loop over all base-mesh mesh parts
1192 for(auto it = part_names.begin(); it != part_names.end(); ++it)
1193 {
1194 // get base mesh part node
1195 auto* base_part_node = this->find_mesh_part_node(*it);
1196 XASSERTM(base_part_node != nullptr, String("base-mesh part '") + (*it) + "' not found!");
1197
1198 // our split mesh part
1199 std::unique_ptr<MeshPartType> split_part;
1200
1201 // get base-mesh part
1202 MeshPartType* base_part = base_part_node->get_mesh();
1203
1204 // build
1205 if((base_part != nullptr) && part_splitter.build(*base_part))
1206 {
1207 // create our mesh part
1208 split_part = part_splitter.make_unique();
1209 }
1210
1211 // Insert patch mesh part
1212 patch_node->add_mesh_part(*it, std::move(split_part), this->find_mesh_part_chart_name(*it), this->find_mesh_part_chart(*it));
1213 }
1214 }
1215
1216 // Step 4: intersect halos
1217 if(split_halos)
1218 {
1219 // create mesh part splitter
1220 PatchMeshPartSplitter<MeshType> part_splitter(*base_root_mesh, *patch_mesh_part);
1221
1222 // loop over all halo mesh parts
1223 for(auto it = this->_halos.begin(); it != this->_halos.end(); ++it)
1224 {
1225 // our split halo
1226 std::unique_ptr<MeshPartType> split_halo;
1227
1228 // get base-mesh halo
1229 MeshPartType* base_halo = it->second.get();
1230
1231 // build
1232 if((base_halo != nullptr) && part_splitter.build(*base_halo))
1233 {
1234 // create our mesh halo
1235 split_halo = part_splitter.make_unique();
1236 }
1237
1238 // Insert patch mesh halo
1239 patch_node->add_halo(it->first, std::move(split_halo));
1240 }
1241 }
1242
1243 // Step 5: intersect patches
1244 if(split_patches)
1245 {
1246 // create mesh part splitter
1247 PatchMeshPartSplitter<MeshType> part_splitter(*base_root_mesh, *patch_mesh_part);
1248
1249 // loop over all halo mesh parts
1250 for(auto it = this->_patches.begin(); it != this->_patches.end(); ++it)
1251 {
1252 // skip the -1 patch, which is the one that we're currently creating
1253 if(it->first < 0)
1254 continue;
1255
1256 // our split patch
1257 std::unique_ptr<MeshPartType> split_patch;
1258
1259 // get base-mesh patch
1260 MeshPartType* base_patch = it->second.get();
1261
1262 // build
1263 if((base_patch != nullptr) && part_splitter.build(*base_patch))
1264 {
1265 // create our mesh patch
1266 split_patch = part_splitter.make_unique();
1267 }
1268
1269 // Insert patch mesh halo
1270 patch_node->add_patch(it->first, std::move(split_patch));
1271 }
1272 }
1273
1274 // return patch node
1275 return patch_node;
1276 }
1277
1296 std::unique_ptr<RootMeshNode> extract_patch(
1297 std::vector<int>& comm_ranks,
1298 const Adjacency::Graph& elems_at_rank,
1299 const int rank)
1300 {
1301 // get dimensions of graph
1302 const Index num_elems = elems_at_rank.get_num_nodes_image();
1303
1304 // get our mesh
1305 const MeshType* base_root_mesh = this->get_mesh();
1306 XASSERTM(base_root_mesh != nullptr, "mesh node has no mesh");
1307
1308 // validate element count
1309 XASSERTM(num_elems == base_root_mesh->get_num_elements(), "mesh vs partition: element count mismatch");
1310
1311 // transpose the partitioning graph here, as we will need it multiple times
1312 const Adjacency::Graph ranks_at_elem(Adjacency::RenderType::transpose, elems_at_rank);
1313
1314 // Step 1: compute neighbor ranks
1315 {
1316 // get vertices-at-element
1317 const auto& verts_at_elem = base_root_mesh->template get_index_set<MeshType::shape_dim, 0>();
1318
1319 // Note:
1320 // In the following, we are building the ranks-at-rank adjacency graph in an apparently
1321 // cumbersome manner in five steps (including the ranks-at-elem graph assembly above).
1322 // Let "R>E" be the elements-at-rank graph, that is given as a parameter to this function,
1323 // and let "E>V" be the vertices-at-element graph, then we perform the following steps:
1324 //
1325 // 1: compute ranks-at-element by transposition: E>R := (R>E)^T
1326 // 2: compute elements-at-vertex by transposition: V>E := (E>V)^T
1327 // 3: compute ranks-at-vertex by composition: V>R := (V>E) * (E>R)
1328 // 4: compute vertices-at-rank by transposition: R>V := (V>R)^T
1329 // 5: compute ranks-at-rank by composition: R>R := (R>V) * (V>R)
1330 //
1331 // As said before, this looks as if it is more complicated than it has to be, because
1332 // one might also try the following three-step approach (which was, in fact, implemented
1333 // here before):
1334 //
1335 // 1. compute vertices-at-rank by composition: R>V := (R>E) * (E>V)
1336 // 2. compute ranks-at-vertex by transposition: V>R := (R>V)^T
1337 // 3: compute ranks-at-rank by composition: R>R := (R>V) * (V>R)
1338 //
1339 // The million dollar question is: why don't use the 3-step approach?
1340 // Answer: Assume that we have N elements in the base-mesh and P processes, then it
1341 // can be shown that the first step "R>V := (R>E) * (E>V)" has a runtime of O(N^2/P),
1342 // which results in quadratic runtime in N unless N = O(P). So the practically important
1343 // scenario of "many elements on few processors" lead to this bottleneck. However, it is
1344 // worth mentioning that the 3-step approach has linear runtime in the case N = O(P).
1345 // On the other hand, the 5-step approach implemented here can be shown to have
1346 // linear runtime in both N and P in any relevant case, which is the reason why it
1347 // was chosen here.
1348
1349 // build elements-at-vertex graph
1350 Adjacency::Graph elems_at_vert(Adjacency::RenderType::transpose, verts_at_elem);
1351
1352 // build ranks-at-vertex graph and transpose it
1353 Adjacency::Graph ranks_at_vert(Adjacency::RenderType::injectify, elems_at_vert, ranks_at_elem);
1354 Adjacency::Graph verts_at_rank(Adjacency::RenderType::transpose, ranks_at_vert);
1355
1356 // build ranks-at-rank (via vertices) graph
1357 Adjacency::Graph ranks_at_rank(Adjacency::RenderType::injectify, verts_at_rank, ranks_at_vert);
1358
1359 // build comm neighbor ranks vector
1360 for(auto it = ranks_at_rank.image_begin(Index(rank)); it != ranks_at_rank.image_end(Index(rank)); ++it)
1361 {
1362 if(int(*it) != rank)
1363 comm_ranks.push_back(int(*it));
1364 }
1365 }
1366
1367 // Step 2: create mesh part of the patch
1368 MeshPartType* patch_mesh_part = nullptr;
1369 {
1370 // create a factory for our partition
1371 PatchMeshPartFactory<MeshType> part_factory(Index(rank), elems_at_rank);
1372
1373 // ensure that the partition is not empty
1374 if(part_factory.empty())
1375 {
1376 String msg("Rank ");
1377 msg += stringify(rank);
1378 msg += " received empty patch from partitioner!";
1379 XABORTM(msg);
1380 }
1381
1382 // create patch mesh part and add it to our map
1383 patch_mesh_part = this->add_patch(rank, part_factory.make_unique());
1384
1385 // deduct the target sets
1386 patch_mesh_part->template deduct_target_sets_from_top<MeshType::shape_dim>(
1387 base_root_mesh->get_index_set_holder());
1388 }
1389
1390 // Step 3: Create root mesh node of partition by using PatchMeshFactory
1391 std::unique_ptr<RootMeshNode> patch_node;
1392 {
1393 // create patch root mesh
1394 PatchMeshFactory<MeshType> patch_factory(*base_root_mesh, *patch_mesh_part);
1395 patch_node = RootMeshNode::make_unique(patch_factory.make_unique(), this->_atlas);
1396 }
1397
1398 // Step 4: intersect boundary and other base mesh parts
1399 {
1400 // create mesh part splitter
1401 PatchMeshPartSplitter<MeshType> part_splitter(*base_root_mesh, *patch_mesh_part);
1402
1403 // get all mesh part names
1404 std::deque<String> part_names = this->get_mesh_part_names();
1405
1406 // loop over all base-mesh mesh parts
1407 for(auto it = part_names.begin(); it != part_names.end(); ++it)
1408 {
1409 // get base mesh part node
1410 auto* base_part_node = this->find_mesh_part_node(*it);
1411 XASSERTM(base_part_node != nullptr, String("base-mesh part '") + (*it) + "' not found!");
1412
1413 // our split mesh part
1414 std::unique_ptr<MeshPartType> split_part;
1415
1416 // get base-mesh part
1417 MeshPartType* base_part = base_part_node->get_mesh();
1418
1419 // build
1420 if((base_part != nullptr) && part_splitter.build(*base_part))
1421 {
1422 // create our mesh part
1423 split_part = part_splitter.make_unique();
1424 }
1425
1426 // Insert patch mesh part
1427 patch_node->add_mesh_part(*it, std::move(split_part), this->find_mesh_part_chart_name(*it), this->find_mesh_part_chart(*it));
1428 }
1429 }
1430
1431 // Step 5: Create halos
1432 {
1433 // create halo factory
1434 PatchHaloFactory<MeshType> halo_factory(ranks_at_elem, *base_root_mesh, *patch_mesh_part);
1435
1436 // loop over all comm ranks
1437 for(auto it = comm_ranks.begin(); it != comm_ranks.end(); ++it)
1438 {
1439 // build halo
1440 halo_factory.build(Index(*it));
1441
1442 // create halo mesh part and add to our map
1443 patch_node->add_halo(*it, halo_factory.make_unique());
1444 }
1445 }
1446
1447 // return patch mesh part
1448 return patch_node;
1449 }
1450
1468 std::unique_ptr<RootMeshNode> extract_patch(
1469 std::vector<int>& comm_ranks,
1470 const Partition& partition,
1471 const int rank)
1472 {
1473 return extract_patch(comm_ranks, partition.get_patches(), rank);
1474 }
1475
1485 void create_patch_meshpart(const Adjacency::Graph& elems_at_rank, const int rank)
1486 {
1487 // create a factory for our partition
1488 PatchMeshPartFactory<MeshType> part_factory(Index(rank), elems_at_rank);
1489
1490 // create patch mesh part
1491 std::unique_ptr<MeshPartType> patch_mesh_part = part_factory.make_unique();
1492 patch_mesh_part->template deduct_target_sets_from_top<MeshType::shape_dim>(
1493 this->get_mesh()->get_index_set_holder());
1494
1495 // add patch meshpart to this node
1496 this->add_patch(rank, std::move(patch_mesh_part));
1497 }
1498
1512 {
1513 XASSERTM(this->_mesh != nullptr, "mesh node has no mesh yet and therefore cannot be permuted!");
1514
1515 // permute the mesh, which creates the actual permutation
1516 this->_mesh->create_permutation(strategy);
1517
1518 // permute mesh parts, halos and patches
1520 }
1521
1531 {
1532 XASSERTM(this->_mesh != nullptr, "mesh node has no mesh yet and therefore cannot be permuted!");
1533
1534 // permute the mesh, which creates the actual permutation
1535 this->_mesh->set_permutation(std::forward<MeshPermutation<typename MeshType::ShapeType>>(mesh_perm));
1536
1537 // permute mesh parts, halos and patches
1539 }
1540
1546 static String name()
1547 {
1548 return "RootMeshNode<...>";
1549 }
1550
1551 protected:
1554 {
1555 // do we have a permutation to apply?
1556 if(!this->_mesh->is_permuted())
1557 return;
1558
1559 // get the inverse permutations array
1560 const auto& mesh_perm = this->_mesh->get_mesh_permutation();
1561
1562 // permute all mesh part nodes
1563 for(auto it = this->_mesh_part_nodes.begin(); it != this->_mesh_part_nodes.end(); ++it)
1564 {
1565 MeshPartType* mpart = it->second.node->get_mesh();
1566 if(mpart != nullptr)
1567 mpart->permute(mesh_perm);
1568 }
1569
1570 // permute all halos
1571 for(auto it = _halos.begin(); it != _halos.end(); ++it)
1572 {
1573 if(it->second != nullptr)
1574 it->second->permute(mesh_perm);
1575 }
1576
1577 // permute all patches
1578 for(auto it = _patches.begin(); it != _patches.end(); ++it)
1579 {
1580 if(it->second != nullptr)
1581 it->second->permute(mesh_perm);
1582 }
1583 }
1584 }; // class RootMeshNode
1585
1586#ifdef FEAT_EICKT
1587 extern template class MeshNode<ConformalMesh<Shape::Simplex<2>, 2, Real>, ConformalMesh<Shape::Simplex<2>, 2, Real>>;
1588 extern template class MeshNode<ConformalMesh<Shape::Simplex<3>, 3, Real>, ConformalMesh<Shape::Simplex<3>, 3, Real>>;
1589 extern template class MeshNode<ConformalMesh<Shape::Hypercube<2>, 2, Real>, ConformalMesh<Shape::Hypercube<2>, 2, Real>>;
1590 extern template class MeshNode<ConformalMesh<Shape::Hypercube<3>, 3, Real>, ConformalMesh<Shape::Hypercube<3>, 3, Real>>;
1591
1592 extern template class MeshNode<ConformalMesh<Shape::Simplex<2>, 2, Real>, MeshPart<ConformalMesh<Shape::Simplex<2>, 2, Real>>>;
1593 extern template class MeshNode<ConformalMesh<Shape::Simplex<3>, 3, Real>, MeshPart<ConformalMesh<Shape::Simplex<3>, 3, Real>>>;
1594 extern template class MeshNode<ConformalMesh<Shape::Hypercube<2>, 2, Real>, MeshPart<ConformalMesh<Shape::Hypercube<2>, 2, Real>>>;
1595 extern template class MeshNode<ConformalMesh<Shape::Hypercube<3>, 3, Real>, MeshPart<ConformalMesh<Shape::Hypercube<3>, 3, Real>>>;
1596
1597 extern template class RootMeshNode<ConformalMesh<Shape::Simplex<2>, 2, Real>>;
1598 extern template class RootMeshNode<ConformalMesh<Shape::Simplex<3>, 3, Real>>;
1599 extern template class RootMeshNode<ConformalMesh<Shape::Hypercube<2>, 2, Real>>;
1600 extern template class RootMeshNode<ConformalMesh<Shape::Hypercube<3>, 3, Real>>;
1601#endif // FEAT_EICKT
1602 } // namespace Geometry
1603} // namespace FEAT
#define XABORTM(msg)
Abortion macro definition with custom message.
Definition: assertion.hpp:192
#define XASSERT(expr)
Assertion macro definition.
Definition: assertion.hpp:262
#define XASSERTM(expr, msg)
Assertion macro definition with custom message.
Definition: assertion.hpp:263
Adjacency Graph implementation.
Definition: graph.hpp:34
ImageIterator image_begin(Index domain_node) const
Returns an iterator for the first adjacent image node.
Definition: graph.hpp:958
ImageIterator image_end(Index domain_node) const
Returns an iterator for the first position past the last adjacent image node.
Definition: graph.hpp:966
Dynamic mesh data structure.
std::unique_ptr< MeshPartType > make_unique()
Creates a new mesh part on the heap and returns a unique pointer to it.
Definition: mesh_part.hpp:638
Mesh Atlas class template.
Definition: mesh_atlas.hpp:32
Container class for bundling MeshPartNodes with their corresponding charts.
Definition: mesh_node.hpp:138
MeshPartNodeBin(std::unique_ptr< MeshPartNodeType > node_, String chart_name_, const MeshChartType *chart_)
Constructor.
Definition: mesh_node.hpp:157
const MeshChartType * chart
Chart belonging to node.
Definition: mesh_node.hpp:145
std::unique_ptr< MeshPartNodeType > node
This container's MeshPartNode.
Definition: mesh_node.hpp:141
String chart_name
Name of the chart.
Definition: mesh_node.hpp:143
Mesh Node base class.
Definition: mesh_node.hpp:118
virtual ~MeshNode()
Virtual destructor.
Definition: mesh_node.hpp:203
bool set_mesh_part_chart(const String &part_name, const String &chart_name, const MeshChartType *chart)
Sets the chart for a particular mesh part.
Definition: mesh_node.hpp:357
std::size_t bytes() const
Definition: mesh_node.hpp:209
const MeshPartType * find_mesh_part(const String &part_name) const
Searches this container for a MeshPart.
Definition: mesh_node.hpp:405
void rename_mesh_parts(const std::map< String, String > &renames)
Renames a set of mesh-parts.
Definition: mesh_node.hpp:449
MeshPartNodeContainer::reverse_iterator MeshPartNodeReverseIterator
submesh node reverse-iterator type
Definition: mesh_node.hpp:178
MeshPartNodeContainer::const_iterator MeshPartNodeConstIterator
submesh node const-iterator type
Definition: mesh_node.hpp:176
const MeshPartNodeType * find_mesh_part_node(const String &part_name) const
Searches this container for a MeshPartNode.
Definition: mesh_node.hpp:383
void remove_all_mesh_parts()
Removes all mesh parts from this mesh node.
Definition: mesh_node.hpp:339
MeshPartNodeContainer::iterator MeshPartNodeIterator
submesh node iterator type
Definition: mesh_node.hpp:174
const MeshChartType * find_mesh_part_chart(const String &part_name) const
Searches for a chart belonging to a MeshPart by name.
Definition: mesh_node.hpp:421
void refine_children(MeshNode &refined_node) const
Refines all child nodes of this node.
Definition: mesh_node.hpp:565
RootMesh_ RootMeshType
the root mesh type, has to be a Mesh
Definition: mesh_node.hpp:121
MeshPartNodeType * add_mesh_part_node(const String &part_name, std::unique_ptr< MeshPartNodeType > mesh_part_node, const String &chart_name="", const MeshChartType *chart=nullptr)
Adds a new mesh-part child node.
Definition: mesh_node.hpp:281
MeshNode(std::unique_ptr< MeshType > mesh)
Constructor.
Definition: mesh_node.hpp:193
ThisMesh_ MeshType
mesh type of this node, can be a Mesh or MeshPart
Definition: mesh_node.hpp:123
void adapt(bool recursive=true)
Adapts this mesh node.
Definition: mesh_node.hpp:481
void refine_mesh_parts(MeshNode &refined_node) const
Refines all child MeshPart nodes of this node.
Definition: mesh_node.hpp:577
MeshPartNodeContainer _mesh_part_nodes
child submesh nodes
Definition: mesh_node.hpp:184
MeshPartNode< RootMeshType > MeshPartNodeType
the mesh part node type
Definition: mesh_node.hpp:127
static String name()
Returns the name of the class.
Definition: mesh_node.hpp:553
bool adapt_by_name(const String &part_name, bool recursive=false)
Adapts this mesh node.
Definition: mesh_node.hpp:523
MeshAtlas< RootMeshType > MeshAtlasType
the mesh atlas type
Definition: mesh_node.hpp:129
MeshPartType * find_mesh_part(const String &part_name)
Searches this container for a MeshPart.
Definition: mesh_node.hpp:398
String find_mesh_part_chart_name(const String &part_name) const
Searches for a chart name belonging to a MeshPart by name.
Definition: mesh_node.hpp:437
std::map< String, MeshPartNodeBin > MeshPartNodeContainer
submesh node bin container type
Definition: mesh_node.hpp:172
std::deque< String > get_mesh_part_names(bool no_internals=false) const
Returns the names of all mesh parts of this node.
Definition: mesh_node.hpp:251
MeshType * get_mesh()
Returns the mesh of this node.
Definition: mesh_node.hpp:225
std::unique_ptr< MeshType > _mesh
a pointer to the mesh of this node
Definition: mesh_node.hpp:182
Atlas::ChartBase< RootMeshType > MeshChartType
the mesh chart type
Definition: mesh_node.hpp:131
MeshPartNodeType * find_mesh_part_node(const String &part_name)
Searches this container for a MeshPartNode.
Definition: mesh_node.hpp:376
MeshPartNodeType * add_mesh_part(const String &part_name, std::unique_ptr< MeshPartType > mesh_part, const String &chart_name="", const MeshChartType *chart=nullptr)
Adds a new mesh-part child node.
Definition: mesh_node.hpp:316
MeshPart< RootMeshType > MeshPartType
the mesh part type
Definition: mesh_node.hpp:125
bool remove_mesh_part(const String &part_name)
Removes a mesh-part and its corresponding node.
Definition: mesh_node.hpp:333
const MeshType * get_mesh() const
Returns the mesh of this node.
Definition: mesh_node.hpp:231
Class template for partial meshes.
Definition: mesh_part.hpp:90
MeshPart mesh tree node class template.
Definition: mesh_node.hpp:601
BaseClass::MeshAtlasType MeshAtlasType
mesh atlas type
Definition: mesh_node.hpp:611
MeshPartNode(std::unique_ptr< MeshPartType > mesh_part)
Constructor.
Definition: mesh_node.hpp:637
BaseClass::MeshType MeshType
this mesh type
Definition: mesh_node.hpp:607
static String name()
Returns the name of the class.
Definition: mesh_node.hpp:709
std::unique_ptr< MeshPartNode > clone_unique() const
Creates an independent clone of this object and returns a unique pointer to it.
Definition: mesh_node.hpp:666
std::unique_ptr< MeshPartNode > refine(const ParentType_ &parent) const
Refines this node and its sub-tree.
Definition: mesh_node.hpp:683
virtual ~MeshPartNode()
virtual destructor
Definition: mesh_node.hpp:643
void refine_mesh_parts(MeshPartNode &refined_node) const
Refines this node's child nodes.
Definition: mesh_node.hpp:724
MeshNode< RootMesh_, MeshPart< RootMesh_ > > BaseClass
base class typedef
Definition: mesh_node.hpp:604
BaseClass::MeshPartType MeshPartType
mesh part type
Definition: mesh_node.hpp:609
static std::unique_ptr< MeshPartNode > make_unique(std::unique_ptr< MeshPartType > mesh_part)
Creates a new MeshPartNode on the heap and returns a unique pointer to it.
Definition: mesh_node.hpp:656
BaseClass::MeshChartType MeshChartType
mesh chart type
Definition: mesh_node.hpp:613
Mesh permutation class template.
const Adjacency::Graph & get_patches() const
Factory for building a PatchBaseMesh from a given partitioning.
bool empty() const
Checks whether the patch is empty.
Class for creating MeshParts referring to a patch BaseMesh.
Root mesh node class template.
Definition: mesh_node.hpp:748
void clear_patches()
Deletes all patch meshparts from this mesh node.
Definition: mesh_node.hpp:975
virtual ~RootMeshNode()
Virtual destructor.
Definition: mesh_node.hpp:815
const MeshPartType * get_halo(int rank) const
Returns a halo meshpart for a given neighbor.
Definition: mesh_node.hpp:889
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
MeshNode< RootMesh_, RootMesh_ > BaseClass
base class typedef
Definition: mesh_node.hpp:751
const MeshPartType * get_patch(int rank) const
Returns a patch meshpart for a given child.
Definition: mesh_node.hpp:962
MeshPartType * add_patch(int rank, std::unique_ptr< MeshPartType > patch_part)
Adds a patch mesh part to this mesh node.
Definition: mesh_node.hpp:947
const std::map< int, std::unique_ptr< MeshPartType > > & get_patch_map() const
Definition: mesh_node.hpp:969
void clear_halos()
Deletes all halo meshparts from this mesh node.
Definition: mesh_node.hpp:902
std::unique_ptr< RootMeshNode > extract_patch(std::vector< int > &comm_ranks, const Partition &partition, const int rank)
Extracts a patch from a manual partition.
Definition: mesh_node.hpp:1468
void create_patch_meshpart(const Adjacency::Graph &elems_at_rank, const int rank)
Creates a patch meshpart for a child and adds it to the patch map.
Definition: mesh_node.hpp:1485
std::unique_ptr< RootMeshNode > extract_patch(std::vector< int > &comm_ranks, const Adjacency::Graph &elems_at_rank, const int rank)
Extracts a patch from the root mesh as a new mesh node.
Definition: mesh_node.hpp:1296
std::unique_ptr< RootMeshNode > clone_unique() const
Creates an independent clone of this object and returns a unique pointer to it.
Definition: mesh_node.hpp:847
void _apply_mesh_perm_to_parts()
helper function: applies the mesh permutation to all mesh parts, halos and patches
Definition: mesh_node.hpp:1553
std::size_t bytes() const
Definition: mesh_node.hpp:855
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
void create_permutation(PermutationStrategy strategy)
Creates a mesh permutation.
Definition: mesh_node.hpp:1511
std::map< int, std::unique_ptr< MeshPartType > > _patches
a map of our patch mesh-parts
Definition: mesh_node.hpp:768
std::unique_ptr< RootMeshNode > refine_unique(AdaptMode adapt_mode=AdaptMode::chart) const
Refines this node and its sub-tree.
Definition: mesh_node.hpp:989
BaseClass::MeshType MeshType
this mesh type
Definition: mesh_node.hpp:754
const MeshAtlasType * get_atlas() const
Definition: mesh_node.hpp:820
RootMeshNode(std::unique_ptr< MeshType > mesh, MeshAtlasType *atlas=nullptr)
Constructor.
Definition: mesh_node.hpp:804
void set_permutation(MeshPermutation< typename MeshType::ShapeType > &&mesh_perm)
Creates a mesh permutation.
Definition: mesh_node.hpp:1530
std::unique_ptr< RootMeshNode > refine_partial_unique(const VertexMarker_ &marker, AdaptMode adapt_mode=AdaptMode::chart) const
Refines this node and its sub-tree partially.
Definition: mesh_node.hpp:1050
BaseClass::MeshPartType MeshPartType
mesh part type
Definition: mesh_node.hpp:756
const std::map< int, std::unique_ptr< MeshPartType > > & get_halo_map() const
Definition: mesh_node.hpp:896
BaseClass::MeshChartType MeshChartType
mesh chart type
Definition: mesh_node.hpp:760
static String name()
Returns the name of the class.
Definition: mesh_node.hpp:1546
BaseClass::MeshAtlasType MeshAtlasType
mesh atlas type
Definition: mesh_node.hpp:758
MeshAtlasType * _atlas
our atlas pointer
Definition: mesh_node.hpp:764
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
std::map< int, std::unique_ptr< MeshPartType > > _halos
a map of our halo mesh-parts
Definition: mesh_node.hpp:766
void rename_halos(const std::map< int, int > &ranks)
Renames the halo meshparts.
Definition: mesh_node.hpp:916
Standard Refinery class template.
Definition: factory.hpp:58
Subdivision level markings for meshes.
String class implementation.
Definition: string.hpp:46
@ transpose
Render-Transpose mode.
@ injectify
Render-Injectified mode.
AdaptMode
Adapt mode enumeration.
Definition: mesh_node.hpp:53
PermutationStrategy
Mesh permutation strategy enumeration.
@ other
generic/other permutation strategy
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:944
static constexpr TrafoTags operator|(TrafoTags a, TrafoTags b)
Binary OR operator for TrafoTags values.
Definition: eval_tags.hpp:53
static constexpr TrafoTags operator&(TrafoTags a, TrafoTags b)
Binary AND operator for TrafoTags values.
Definition: eval_tags.hpp:67
std::uint64_t Index
Index data type.
Newtype wrapper for mesh layers.