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>
38 template<
typename MeshType_>
42 struct AdjacenciesFiller;
45 template<
typename Policy_>
46 class MeshPartNode DOXY({});
62 return static_cast<AdaptMode>(int(x) | int(y));
67 return static_cast<AdaptMode>(int(x) & int(y));
73 inline std::ostream& operator<<(std::ostream& os,
AdaptMode mode)
79 case AdaptMode::chart:
84 return os <<
"-unknown-";
88 inline void operator<<(
AdaptMode& mode,
const String& mode_name)
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;
97 XABORTM(
"Unknown AdaptMode identifier string " + mode_name);
141 std::unique_ptr<MeshPartNodeType>
node;
158 node(std::move(node_)),
193 explicit MeshNode(std::unique_ptr<MeshType> mesh) :
194 _mesh(std::move(mesh)),
215 s += it->second.node->bytes();
236 void set_mesh(std::unique_ptr<MeshType> mesh)
239 _mesh = std::move(mesh);
253 std::deque<String> names;
256 String mpname = (*it).first;
257 if(!(no_internals && (mpname.front() ==
'_')))
258 names.push_back(mpname);
283 std::unique_ptr<MeshPartNodeType> mesh_part_node,
284 const String& chart_name =
"",
292 return r.first->second.node.get();
318 std::unique_ptr<MeshPartType> mesh_part,
319 const String& chart_name =
"",
362 it->second.chart_name = chart_name;
363 it->second.chart = chart;
401 return (node !=
nullptr) ? node->
get_mesh() :
nullptr;
408 return (node !=
nullptr) ? node->
get_mesh() :
nullptr;
457 auto it = renames.find(v.first);
458 if(it == renames.end())
461 new_map.emplace(v.first, std::move(v.second));
466 new_map.emplace(it->second, std::move(v.second));
486 for(; it != jt; ++it)
491 it->second.node->adapt(
true);
495 if(it->second.chart !=
nullptr)
501 const MeshPartType* mesh_part = it->second.node->get_mesh();
502 if(mesh_part !=
nullptr)
503 it->second.chart->adapt(*
_mesh, *mesh_part);
534 it->second.node->adapt(
true);
538 if(it->second.chart !=
nullptr)
540 it->second.chart->adapt(*
_mesh, *(it->second.node->get_mesh()));
555 return "MeshNode<...>";
582 for(; it != jt; ++it)
584 refined_node.
add_mesh_part_node(it->first, it->second.node->refine(*
_mesh), it->second.chart_name, it->second.chart);
598 template<
typename RootMesh_>
600 :
public MeshNode<RootMesh_, MeshPart<RootMesh_>>
621 if(other._mesh !=
nullptr)
622 this->set_mesh(std::unique_ptr<MeshType>(
new MeshType(
other._mesh->clone())));
624 for(
auto it =
other._mesh_part_nodes.begin(); it !=
other._mesh_part_nodes.end(); ++it)
626 this->
add_mesh_part_node(it->first, it->second.node->clone_unique(), it->second.chart_name, it->second.chart);
656 static std::unique_ptr<MeshPartNode>
make_unique(std::unique_ptr<MeshPartType> mesh_part)
658 return std::unique_ptr<MeshPartNode>(
new MeshPartNode(std::move(mesh_part)));
668 std::unique_ptr<MeshPartNode> node(
new MeshPartNode(
nullptr));
682 template<
typename ParentType_>
683 std::unique_ptr<MeshPartNode>
refine(
const ParentType_& parent)
const
686 if(this->
_mesh ==
nullptr)
688 return std::unique_ptr<MeshPartNode>(
new MeshPartNode(
nullptr));
695 auto fine_node =
make_unique(refinery.make_unique());
711 return "MeshPartNode<...>";
728 for(; it != jt; ++it)
730 refined_node.add_mesh_part_node(it->first, it->second.node->refine(*this->_mesh));
745 template<
typename RootMesh_>
747 :
public MeshNode<RootMesh_, RootMesh_>
766 std::map<int, std::unique_ptr<MeshPartType>>
_halos;
768 std::map<int, std::unique_ptr<MeshPartType>>
_patches;
776 if(other.
_mesh !=
nullptr)
777 this->set_mesh(std::unique_ptr<MeshType>(
new MeshType(
other._mesh->clone())));
779 for(
auto it =
other._mesh_part_nodes.begin(); it !=
other._mesh_part_nodes.end(); ++it)
781 this->
add_mesh_part_node(it->first, it->second.node->clone_unique(), it->second.chart_name, it->second.chart);
784 this->_atlas =
other._atlas;
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())));
789 for(
auto it =
other._patches.begin(); it !=
other._patches.end(); ++it)
839 return std::unique_ptr<RootMeshNode>(
new RootMeshNode(std::move(mesh), atlas));
849 std::unique_ptr<RootMeshNode> node(
new RootMeshNode(
nullptr,
nullptr));
858 for(
const auto& x :
_halos)
859 s += x.second->bytes();
861 s += x.second->bytes();
874 void add_halo(
int rank, std::unique_ptr<MeshPartType> halo_part)
876 XASSERTM(
bool(halo_part),
"cannot add empty halos");
877 _halos.emplace(rank, std::move(halo_part));
891 auto it =
_halos.find(rank);
892 return (it !=
_halos.end() ? it->second.get() :
nullptr);
896 const std::map<int, std::unique_ptr<MeshPartType>>&
get_halo_map()
const
921 std::map<int, std::unique_ptr<MeshPartType>> new_halos;
925 auto it = ranks.find(v.first);
926 if(it == ranks.end())
927 new_halos.emplace(v.first, std::move(v.second));
929 new_halos.emplace(it->second, std::move(v.second));
932 _halos = std::move(new_halos);
949 XASSERT(patch_part !=
nullptr);
950 return _patches.emplace(rank, std::move(patch_part)).first->second.get();
965 return (it !=
_patches.end() ? it->second.get() :
nullptr);
995 std::unique_ptr<RootMeshNode> fine_node =
make_unique(refinery.make_unique(), this->_atlas);
1001 for(
const auto& v :
_halos)
1006 fine_node->add_halo(v.first, halo_refinery.make_unique());
1009 fine_node->add_halo(v.first,
nullptr);
1018 fine_node->add_patch(v.first, patch_refinery.make_unique());
1021 fine_node->add_patch(v.first,
nullptr);
1025 if((adapt_mode & AdaptMode::chart) != AdaptMode::none)
1027 fine_node->adapt(
true);
1031 if((adapt_mode & AdaptMode::dual) != AdaptMode::none)
1033 Intern::DualAdaptor<MeshType>::adapt(*fine_node->get_mesh(), *this->get_mesh());
1049 template<
typename TemplateSet_,
typename VertexMarker_>
1055 const Index num_vertices = this->
_mesh->get_num_vertices();
1058 for(
Index i(0); i < num_vertices; ++i)
1060 sdls[i] = marker(i);
1063 AdaptiveMeshType adaptive_mesh(*this->
_mesh);
1064 adaptive_mesh.adapt(sdls, AdaptiveMeshType::ImportBehaviour::All);
1066 Layer top_layer{adaptive_mesh.num_layers() - 1};
1069 std::unique_ptr<RootMeshNode> fine_node =
make_unique(
1070 std::make_unique<MeshType>(adaptive_mesh.to_conformal_mesh(top_layer)),
1077 for(; it != jt; ++it)
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));
1083 fine_node->add_mesh_part_node(
1085 std::move(new_mesh_part_node),
1086 it->second.chart_name,
1091 for(
const auto& v :
_halos)
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));
1099 fine_node->add_halo(v.first,
nullptr);
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));
1111 fine_node->add_patch(v.first,
nullptr);
1115 if((adapt_mode & AdaptMode::chart) != AdaptMode::none)
1117 fine_node->adapt(
true);
1121 if((adapt_mode & AdaptMode::dual) != AdaptMode::none)
1123 Intern::DualAdaptor<MeshType>::adapt(*fine_node->get_mesh(), *this->get_mesh());
1152 bool split_meshparts,
bool split_halos,
bool split_patches)
1154 XASSERTM(!elements.empty(),
"cannot create empty patch!");
1158 XASSERTM(base_root_mesh !=
nullptr,
"mesh node has no mesh");
1170 patch_mesh_part->template deduct_target_sets_from_top<MeshType::shape_dim>(
1171 base_root_mesh->get_index_set_holder());
1175 std::unique_ptr<RootMeshNode> patch_node;
1192 for(
auto it = part_names.begin(); it != part_names.end(); ++it)
1196 XASSERTM(base_part_node !=
nullptr,
String(
"base-mesh part '") + (*it) +
"' not found!");
1199 std::unique_ptr<MeshPartType> split_part;
1205 if((base_part !=
nullptr) && part_splitter.build(*base_part))
1208 split_part = part_splitter.make_unique();
1223 for(
auto it = this->_halos.begin(); it != this->_halos.end(); ++it)
1226 std::unique_ptr<MeshPartType> split_halo;
1232 if((base_halo !=
nullptr) && part_splitter.build(*base_halo))
1235 split_halo = part_splitter.make_unique();
1239 patch_node->add_halo(it->first, std::move(split_halo));
1250 for(
auto it = this->_patches.begin(); it != this->_patches.end(); ++it)
1257 std::unique_ptr<MeshPartType> split_patch;
1263 if((base_patch !=
nullptr) && part_splitter.build(*base_patch))
1266 split_patch = part_splitter.make_unique();
1270 patch_node->add_patch(it->first, std::move(split_patch));
1297 std::vector<int>& comm_ranks,
1302 const Index num_elems = elems_at_rank.get_num_nodes_image();
1306 XASSERTM(base_root_mesh !=
nullptr,
"mesh node has no mesh");
1309 XASSERTM(num_elems == base_root_mesh->get_num_elements(),
"mesh vs partition: element count mismatch");
1317 const auto& verts_at_elem = base_root_mesh->template get_index_set<MeshType::shape_dim, 0>();
1362 if(
int(*it) != rank)
1363 comm_ranks.push_back(
int(*it));
1374 if(part_factory.
empty())
1378 msg +=
" received empty patch from partitioner!";
1386 patch_mesh_part->template deduct_target_sets_from_top<MeshType::shape_dim>(
1387 base_root_mesh->get_index_set_holder());
1391 std::unique_ptr<RootMeshNode> patch_node;
1407 for(
auto it = part_names.begin(); it != part_names.end(); ++it)
1411 XASSERTM(base_part_node !=
nullptr,
String(
"base-mesh part '") + (*it) +
"' not found!");
1414 std::unique_ptr<MeshPartType> split_part;
1420 if((base_part !=
nullptr) && part_splitter.build(*base_part))
1423 split_part = part_splitter.make_unique();
1437 for(
auto it = comm_ranks.begin(); it != comm_ranks.end(); ++it)
1440 halo_factory.build(
Index(*it));
1443 patch_node->add_halo(*it, halo_factory.make_unique());
1469 std::vector<int>& comm_ranks,
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());
1496 this->
add_patch(rank, std::move(patch_mesh_part));
1513 XASSERTM(this->
_mesh !=
nullptr,
"mesh node has no mesh yet and therefore cannot be permuted!");
1516 this->
_mesh->create_permutation(strategy);
1532 XASSERTM(this->
_mesh !=
nullptr,
"mesh node has no mesh yet and therefore cannot be permuted!");
1548 return "RootMeshNode<...>";
1556 if(!this->
_mesh->is_permuted())
1560 const auto& mesh_perm = this->
_mesh->get_mesh_permutation();
1563 for(
auto it = this->
_mesh_part_nodes.begin(); it != this->_mesh_part_nodes.end(); ++it)
1566 if(mpart !=
nullptr)
1567 mpart->permute(mesh_perm);
1571 for(
auto it =
_halos.begin(); it !=
_halos.end(); ++it)
1573 if(it->second !=
nullptr)
1574 it->second->permute(mesh_perm);
1580 if(it->second !=
nullptr)
1581 it->second->permute(mesh_perm);
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>>;
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>>>;
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>>;
#define XABORTM(msg)
Abortion macro definition with custom message.
#define XASSERT(expr)
Assertion macro definition.
#define XASSERTM(expr, msg)
Assertion macro definition with custom message.
Adjacency Graph implementation.
ImageIterator image_begin(Index domain_node) const
Returns an iterator for the first adjacent image node.
ImageIterator image_end(Index domain_node) const
Returns an iterator for the first position past the last adjacent image node.
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.
Mesh Atlas class template.
Container class for bundling MeshPartNodes with their corresponding charts.
MeshPartNodeBin(std::unique_ptr< MeshPartNodeType > node_, String chart_name_, const MeshChartType *chart_)
Constructor.
const MeshChartType * chart
Chart belonging to node.
std::unique_ptr< MeshPartNodeType > node
This container's MeshPartNode.
String chart_name
Name of the chart.
virtual ~MeshNode()
Virtual destructor.
bool set_mesh_part_chart(const String &part_name, const String &chart_name, const MeshChartType *chart)
Sets the chart for a particular mesh part.
std::size_t bytes() const
const MeshPartType * find_mesh_part(const String &part_name) const
Searches this container for a MeshPart.
void rename_mesh_parts(const std::map< String, String > &renames)
Renames a set of mesh-parts.
MeshPartNodeContainer::reverse_iterator MeshPartNodeReverseIterator
submesh node reverse-iterator type
MeshPartNodeContainer::const_iterator MeshPartNodeConstIterator
submesh node const-iterator type
const MeshPartNodeType * find_mesh_part_node(const String &part_name) const
Searches this container for a MeshPartNode.
void remove_all_mesh_parts()
Removes all mesh parts from this mesh node.
MeshPartNodeContainer::iterator MeshPartNodeIterator
submesh node iterator type
const MeshChartType * find_mesh_part_chart(const String &part_name) const
Searches for a chart belonging to a MeshPart by name.
void refine_children(MeshNode &refined_node) const
Refines all child nodes of this node.
RootMesh_ RootMeshType
the root mesh type, has to be a Mesh
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.
MeshNode(std::unique_ptr< MeshType > mesh)
Constructor.
ThisMesh_ MeshType
mesh type of this node, can be a Mesh or MeshPart
void adapt(bool recursive=true)
Adapts this mesh node.
void refine_mesh_parts(MeshNode &refined_node) const
Refines all child MeshPart nodes of this node.
MeshPartNodeContainer _mesh_part_nodes
child submesh nodes
MeshPartNode< RootMeshType > MeshPartNodeType
the mesh part node type
static String name()
Returns the name of the class.
bool adapt_by_name(const String &part_name, bool recursive=false)
Adapts this mesh node.
MeshAtlas< RootMeshType > MeshAtlasType
the mesh atlas type
MeshPartType * find_mesh_part(const String &part_name)
Searches this container for a MeshPart.
String find_mesh_part_chart_name(const String &part_name) const
Searches for a chart name belonging to a MeshPart by name.
std::map< String, MeshPartNodeBin > MeshPartNodeContainer
submesh node bin container type
std::deque< String > get_mesh_part_names(bool no_internals=false) const
Returns the names of all mesh parts of this node.
MeshType * get_mesh()
Returns the mesh of this node.
std::unique_ptr< MeshType > _mesh
a pointer to the mesh of this node
Atlas::ChartBase< RootMeshType > MeshChartType
the mesh chart type
MeshPartNodeType * find_mesh_part_node(const String &part_name)
Searches this container for a MeshPartNode.
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.
MeshPart< RootMeshType > MeshPartType
the mesh part type
bool remove_mesh_part(const String &part_name)
Removes a mesh-part and its corresponding node.
const MeshType * get_mesh() const
Returns the mesh of this node.
Class template for partial meshes.
MeshPart mesh tree node class template.
BaseClass::MeshAtlasType MeshAtlasType
mesh atlas type
MeshPartNode(std::unique_ptr< MeshPartType > mesh_part)
Constructor.
BaseClass::MeshType MeshType
this mesh type
static String name()
Returns the name of the class.
std::unique_ptr< MeshPartNode > clone_unique() const
Creates an independent clone of this object and returns a unique pointer to it.
std::unique_ptr< MeshPartNode > refine(const ParentType_ &parent) const
Refines this node and its sub-tree.
virtual ~MeshPartNode()
virtual destructor
void refine_mesh_parts(MeshPartNode &refined_node) const
Refines this node's child nodes.
MeshNode< RootMesh_, MeshPart< RootMesh_ > > BaseClass
base class typedef
BaseClass::MeshPartType MeshPartType
mesh part type
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.
BaseClass::MeshChartType MeshChartType
mesh chart type
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.
void clear_patches()
Deletes all patch meshparts from this mesh node.
virtual ~RootMeshNode()
Virtual destructor.
const MeshPartType * get_halo(int rank) const
Returns a halo meshpart for a given neighbor.
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.
MeshNode< RootMesh_, RootMesh_ > BaseClass
base class typedef
const MeshPartType * get_patch(int rank) const
Returns a patch meshpart for a given child.
MeshPartType * add_patch(int rank, std::unique_ptr< MeshPartType > patch_part)
Adds a patch mesh part to this mesh node.
const std::map< int, std::unique_ptr< MeshPartType > > & get_patch_map() const
void clear_halos()
Deletes all halo meshparts from this mesh node.
std::unique_ptr< RootMeshNode > extract_patch(std::vector< int > &comm_ranks, const Partition &partition, const int rank)
Extracts a patch from a manual partition.
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.
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.
std::unique_ptr< RootMeshNode > clone_unique() const
Creates an independent clone of this object and returns a unique pointer to it.
void _apply_mesh_perm_to_parts()
helper function: applies the mesh permutation to all mesh parts, halos and patches
std::size_t bytes() const
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.
void create_permutation(PermutationStrategy strategy)
Creates a mesh permutation.
std::map< int, std::unique_ptr< MeshPartType > > _patches
a map of our patch mesh-parts
std::unique_ptr< RootMeshNode > refine_unique(AdaptMode adapt_mode=AdaptMode::chart) const
Refines this node and its sub-tree.
BaseClass::MeshType MeshType
this mesh type
const MeshAtlasType * get_atlas() const
RootMeshNode(std::unique_ptr< MeshType > mesh, MeshAtlasType *atlas=nullptr)
Constructor.
void set_permutation(MeshPermutation< typename MeshType::ShapeType > &&mesh_perm)
Creates a mesh permutation.
std::unique_ptr< RootMeshNode > refine_partial_unique(const VertexMarker_ &marker, AdaptMode adapt_mode=AdaptMode::chart) const
Refines this node and its sub-tree partially.
BaseClass::MeshPartType MeshPartType
mesh part type
const std::map< int, std::unique_ptr< MeshPartType > > & get_halo_map() const
BaseClass::MeshChartType MeshChartType
mesh chart type
static String name()
Returns the name of the class.
BaseClass::MeshAtlasType MeshAtlasType
mesh atlas type
MeshAtlasType * _atlas
our atlas pointer
void add_halo(int rank, std::unique_ptr< MeshPartType > halo_part)
Adds a halo mesh part to this mesh node.
std::map< int, std::unique_ptr< MeshPartType > > _halos
a map of our halo mesh-parts
void rename_halos(const std::map< int, int > &ranks)
Renames the halo meshparts.
Standard Refinery class template.
Subdivision level markings for meshes.
String class implementation.
@ transpose
Render-Transpose mode.
@ injectify
Render-Injectified mode.
AdaptMode
Adapt mode enumeration.
PermutationStrategy
Mesh permutation strategy enumeration.
@ other
generic/other permutation strategy
double Real
Real data type.
String stringify(const T_ &item)
Converts an item into a String.
static constexpr TrafoTags operator|(TrafoTags a, TrafoTags b)
Binary OR operator for TrafoTags values.
static constexpr TrafoTags operator&(TrafoTags a, TrafoTags b)
Binary AND operator for TrafoTags values.
std::uint64_t Index
Index data type.
Newtype wrapper for mesh layers.