10#include <kernel/util/dist.hpp>
11#include <kernel/util/dist_file_io.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/partition_set.hpp>
18#include <kernel/geometry/parti_2lvl.hpp>
19#include <kernel/geometry/parti_iterative.hpp>
20#include <kernel/geometry/parti_parmetis.hpp>
21#include <kernel/geometry/parti_zoltan.hpp>
23#include <control/domain/domain_control.hpp>
40 template<
typename DomainLevel_>
48 using typename BaseClass::LevelType;
52 using typename BaseClass::MeshType;
80 int progeny_group, progeny_child;
81 int progeny_first, progeny_count;
98 progeny_group(0), progeny_child(0),
99 progeny_first(0), progeny_count(0),
193 auto it = args.
query(
"parti-type");
200 for(
const auto& t : it->second)
205 this->_comm.
print(
"ERROR: unknown partitioner type '" + t +
"'");
235 auto parti_type_p = pmap.
query(
"parti-type");
236 if(parti_type_p.second)
241 std::deque<String> allowed_partitioners = parti_type_p.first.split_by_whitespaces();
243 for(
const auto& t : allowed_partitioners)
247 this->_comm.
print(
"ERROR: unknown partitioner type '" + t +
"'");
253 auto parti_rank_elems_p = pmap.
query(
"parti-rank-elems");
254 if(parti_rank_elems_p.second)
258 this->_comm.
print(
"ERROR: Failed to parse 'parti-rank-elems'");
263 auto genetic_time_init_p = pmap.
query(
"parti-genetic-time-init");
264 if(genetic_time_init_p.second)
268 this->_comm.
print(
"ERROR: Failed to parse 'parti-genetic-time-init'");
273 auto genetic_time_mutate_p = pmap.
query(
"parti-genetic-time-mutate");
274 if(genetic_time_mutate_p.second)
278 this->_comm.
print(
"ERROR: Failed to parse 'parti-genetic-time-mutate'");
333 const int nranks = this->_comm.
size();
334 std::deque<String> sv;
336 for(std::size_t i(0); i < slvls.size(); ++i)
338 int ilvl = -1, nprocs = -1;
339 sv = slvls.at(i).split_by_string(
":");
341 if((sv.size() < std::size_t(1)) || (sv.size() > std::size_t(2)))
342 throw ParseError(
"Invalid input format", slvls.at(i),
"an int-pair 'level:patches'");
344 if(!sv.front().parse(ilvl))
345 throw ParseError(
"Failed to parse level index", slvls.at(i),
"an integer");
346 if((sv.size() > std::size_t(1)) && !sv.back().parse(nprocs))
347 throw ParseError(
"Failed to parse process count" , slvls.at(i),
"an integer");
351 throw ParseError(
"Invalid negative level index", slvls.at(i),
"a non-negative level index");
354 if(i == std::size_t(0))
357 if((nprocs >= 0) && (nprocs != this->_comm.
size()))
358 throw ParseError(
"Invalid number of processes for global level: '" + slvls.at(i) +
366 throw ParseError(
"Invalid non-descending level index: '" + slvls.at(i) +
370 if((i + 1) == slvls.size())
377 throw ParseError(
"Invalid non-descending process count: '" + slvls.at(i) +
381 throw ParseError(
"Invalid indivisible process count: '" + slvls.at(i) +
404 int _desired_level_max = lvl_max;
405 int _desired_level_min = (lvl_min >= 0 ? lvl_min : lvl_max + lvl_min + 1);
407 XASSERTM(_desired_level_max >= 0,
"Invalid level-max");
408 XASSERTM(_desired_level_min >= 0,
"Invalid level-min");
409 XASSERTM(_desired_level_max >= _desired_level_min,
"Invalid level-min/max combination");
434 int _desired_level_max = lvl_max;
435 int _desired_level_med = (lvl_med >= 0 ? lvl_med : lvl_max + lvl_med + 1);
436 int _desired_level_min = (lvl_min >= 0 ? lvl_min : lvl_med + lvl_min + 1);
438 XASSERTM(_desired_level_max >= 0,
"Invalid level-max");
439 XASSERTM(_desired_level_med >= 0,
"Invalid level-med");
440 XASSERTM(_desired_level_min >= 0,
"Invalid level-min");
443 XASSERTM(_desired_level_max > _desired_level_med,
"Invalid level-max/med combination");
446 XASSERTM(_desired_level_med >= _desired_level_min,
"Invalid level-med/min combination");
531 for(
auto it = this->_ancestry.rbegin(); it != this->_ancestry.rend(); ++it)
533 if(it != this->_ancestry.rbegin())
540 s += (it->num_parts > 1 ?
" patches on " :
" patch on ");
542 s += (it->num_procs > 1 ?
" processes" :
" process");
574 for(
auto it = this->_ancestry.begin(); it != this->_ancestry.end(); ++it)
576 if(it != this->_ancestry.begin())
590 s +=
stringify((*it).progeny_comm.rank());
597 s += ((*it).layer >= 0 ?
"*" :
" ");
598 s += ((*it).layer_p >= 0 ?
">" :
" ");
617 typedef std::uint64_t u64;
620 const std::uint64_t magic = 0x6F436F4461503346;
622 XASSERT(this->_num_global_layers >= this->_ancestry.size());
624 if(this->_comm.
rank() == 0)
627 bs.write((
const char*)&magic, 8u);
630 const u64 lev = u64(this->_virt_levels.front()->get_level_index());
631 bs.write((
const char*)&lev, 8u);
634 const u64 na = u64(this->_ancestry.size());
635 bs.write((
const char*)&na, 8u);
638 for(
auto it = this->_ancestry.rbegin(); it != this->_ancestry.rend(); ++it)
641 const u64 np = u64(it->num_procs);
642 const u64 pl = u64(it->parti_level);
643 bs.write((
const char*)&np, 8u);
644 bs.write((
const char*)&pl, 8u);
649 for(
auto it = this->_ancestry.rbegin(); it != this->_ancestry.rend(); ++it)
651 if(it == this->_ancestry.rbegin())
653 std::vector<char> buf = it->parti_graph.serialize();
654 bs.write(buf.data(), std::streamsize(buf.size()));
663 const std::size_t ilp = std::size_t(it->layer_p);
664 XASSERT(ilp < this->_layers.size());
665 const Dist::Comm& comm_p = this->_layers.at(ilp)->comm();
668 std::vector<char> buf = it->parti_graph.serialize();
671 u64 buf_size = buf.size();
674 std::vector<u64> all_sizes;
675 if(comm_p.
rank() == 0)
676 all_sizes.resize(std::size_t(comm_p.
size()));
677 comm_p.
gather(&buf_size, 1u, all_sizes.data(), 1u, 0);
683 if(buf_size > u64(buf.size()))
684 buf.resize(buf_size);
687 std::vector<char> com_buf;
688 if(comm_p.
rank() == 0)
689 com_buf.resize(std::size_t(buf_size * u64(comm_p.
size())));
692 comm_p.
gather(buf.data(), buf_size, com_buf.data(), buf_size, 0);
695 if(comm_p.
rank() == 0)
697 char* x = com_buf.data();
698 for(u64 k(0); k < u64(comm_p.
size()); ++k)
699 bs.write(&x[k*buf_size], std::streamsize(all_sizes[k]));
753 return std::vector<WeightType>();
762 XASSERTM(this->_desired_levels.size() <= std::size_t(2),
"multi-layered control is desired here");
765 this->_ancestry.resize(std::size_t(1));
766 Ancestor& ancestor = this->_ancestry.front();
784 ancestor.desired_level_min = this->_desired_levels.back().first;
787 ancestor.progeny_group = 0;
788 ancestor.progeny_child = this->_comm.
rank();
791 ancestor.progeny_count = this->_comm.
size();
792 ancestor.progeny_first = 0;
793 ancestor.progeny_comm = this->_comm.
comm_dup();
799#if defined(FEAT_HAVE_MPI) || defined(DOXYGEN)
807 this->push_layer(std::make_shared<LayerType>(this->_comm.
comm_dup(), 0));
810 for(std::size_t ilay(1u); (ilay+1u) < this->_desired_levels.size(); ++ilay)
813 std::shared_ptr<LayerType> layer_c = this->_layers.back();
819 const int nprocs_c = comm_c.
size();
822 const int nprocs_p = this->_desired_levels.at(ilay).second;
825 XASSERT(nprocs_c % nprocs_p == 0);
828 const int num_sibs = nprocs_c / nprocs_p;
831 const int my_rank_c = comm_c.
rank();
834 const int parent_rank_c = (my_rank_c / num_sibs) * num_sibs;
843 if(parent_rank_c == my_rank_c)
849 this->push_layer(std::make_shared<LayerType>(std::move(comm_p),
int(ilay)));
868 XASSERT(!this->_layers.empty());
871 std::deque<int> num_procs;
872 for(
auto it = this->_desired_levels.begin(); it != this->_desired_levels.end(); ++it)
875 num_procs.push_back(it->second);
878 num_procs.push_back(1);
881 this->_ancestry.resize(num_procs.size()-std::size_t(1));
884 const int main_rank = this->_comm.
rank();
885 const int main_size = this->_comm.
size();
886 for(std::size_t i(0); i < this->_ancestry.size(); ++i)
889 Ancestor& ancestor = this->_ancestry.at(i);
892 ancestor.
layer = (i < this->_layers.size() ? int(i) : -1);
895 ancestor.
layer_p = ((i+1u) < this->_layers.size() ? int(i)+1 : -1);
901 ancestor.
num_parts = num_procs.at(i) / num_procs.at(i+1u);
908 if((i+1u) < this->_desired_levels.size())
909 ancestor.desired_level_min = this->_desired_levels.at(i+1).first;
914 ancestor.progeny_group = ((main_rank * num_procs.at(i+1u)) / main_size) * ancestor.
num_parts;
915 ancestor.progeny_child = ((main_rank * num_procs.at(i)) / main_size) % ancestor.
num_parts;
918 ancestor.progeny_count = main_size / num_procs.at(i+1u);
919 ancestor.progeny_first = (main_rank / ancestor.progeny_count) * ancestor.progeny_count;
920 ancestor.progeny_comm = this->_comm.
comm_create_range_incl(ancestor.progeny_count, ancestor.progeny_first);
945 std::vector<int>& neighbor_ranks)
948 const std::map<int, std::unique_ptr<MeshPartType>>& base_halo_map = base_mesh_node.
get_halo_map();
951 if(base_halo_map.empty())
955 const std::size_t num_halos = base_halo_map.size();
959 *base_mesh_node.
get_patch(ancestor.progeny_child));
962 std::vector<int> halo_ranks;
963 std::vector<std::size_t> halo_sizes;
964 for(
auto it = base_halo_map.begin(); it != base_halo_map.end(); ++it)
967 halo_ranks.push_back(it->first);
970 halo_sizes.push_back(halo_splitter.add_halo(it->first, *it->second));
974 std::vector<Index> halo_recv_data;
975 std::vector<std::vector<Index>> halo_send_data;
982 if(ancestor.
layer >= 0)
984 XASSERT(this->_layers.size() > std::size_t(ancestor.
layer));
985 const LayerType& layer = *this->_layers.at(std::size_t(ancestor.
layer));
986 const Dist::Comm& sibling_comm = *layer.sibling_comm_ptr();
988 const std::size_t num_sibls = std::size_t(sibling_comm.
size());
991 const int sibl_rank = sibling_comm.
rank();
992 const int layer_rank = layer.comm().
rank();
995 std::vector<std::size_t> sibl_halo_sizes(sibl_rank == 0 ? num_halos*num_sibls : 0u);
996 sibling_comm.
gather(halo_sizes.data(), halo_sizes.size(), sibl_halo_sizes.data(), halo_sizes.size(), 0);
1000 std::vector<std::vector<Index>> halo_split_data(num_halos);
1004 for(std::size_t i(0); i < num_halos; ++i)
1007 if(halo_sizes.at(i) ==
Index(0))
1011 halo_split_data.at(i) = halo_splitter.serialize_split_halo(halo_ranks[i], layer_rank);
1012 XASSERT(halo_split_data.at(i).size() == halo_sizes.at(i));
1015 send_reqs[i] = sibling_comm.
isend(halo_split_data.at(i).data(), halo_sizes.at(i), 0);
1023 halo_send_data.resize(num_halos);
1026 for(std::size_t i(0); i < num_halos; ++i)
1030 Index num_halo_childs = 0u;
1031 std::size_t buffer_size = 0u, offset = 0u;
1032 for(std::size_t j(0); j < num_sibls; ++j)
1035 buffer_size += sibl_halo_sizes.at(j*num_halos + i);
1038 if(sibl_halo_sizes.at(j*num_halos + i) > std::size_t(0))
1043 buffer_size += num_halo_childs +
Index(1);
1046 halo_send_data.at(i).resize(buffer_size);
1047 Index* halo_buffer = halo_send_data.at(i).data();
1050 halo_buffer[0u] = num_halo_childs;
1053 offset = num_halo_childs +
Index(1);
1057 if(sibl_halo_sizes.at(i) >
Index(0))
1059 std::vector<Index> my_data(halo_splitter.serialize_split_halo(halo_ranks[i], layer_rank));
1060 std::size_t data_size = sibl_halo_sizes.at(i);
1061 halo_buffer[++coi] =
Index(offset);
1062 for(std::size_t k(0); k < data_size; ++k)
1063 halo_buffer[offset+k] = my_data[k];
1064 offset += my_data.size();
1070 for(std::size_t j(1); j < num_sibls; ++j)
1073 std::size_t data_size = sibl_halo_sizes.at(j*num_halos + i);
1074 if(data_size == std::size_t(0))
1076 XASSERT(offset+data_size <= buffer_size);
1079 halo_buffer[++coi] =
Index(offset);
1082 sibl_recv_reqs[j] = sibling_comm.
irecv(&halo_buffer[offset], data_size,
int(j));
1083 offset += data_size;
1085 XASSERT(offset == buffer_size);
1101 XASSERT(!halo_send_data.empty());
1104 const Dist::Comm& parent_comm = this->_layers.at(std::size_t(ancestor.
layer_p))->comm();
1106 std::vector<std::size_t> halo_recv_sizes(num_halos), halo_send_sizes(num_halos);
1110 for(std::size_t i(0); i < num_halos; ++i)
1113 halo_send_sizes.at(i) = halo_send_data.at(i).size();
1116 halo_recv_reqs[i] = parent_comm.
irecv(&halo_recv_sizes[i], std::size_t(1), halo_ranks[i]);
1119 halo_send_reqs[i] = parent_comm.
isend(&halo_send_sizes[i], std::size_t(1), halo_ranks[i]);
1123 halo_recv_reqs.wait_all();
1127 std::size_t recv_buf_size = num_halos + std::size_t(1);
1128 for(std::size_t i(0); i < num_halos; ++i)
1129 recv_buf_size += halo_recv_sizes[i];
1132 halo_recv_data.resize(recv_buf_size);
1135 halo_recv_data[0] =
Index(num_halos) +
Index(1);
1136 for(std::size_t i(0); i < num_halos; ++i)
1137 halo_recv_data[i+1u] =
Index(halo_recv_data[i] + halo_recv_sizes[i]);
1140 for(std::size_t i(0); i < num_halos; ++i)
1143 halo_recv_reqs[i] = parent_comm.
irecv(&halo_recv_data[halo_recv_data[i]], halo_recv_sizes.at(i), halo_ranks[i]);
1146 halo_send_reqs[i] = parent_comm.
isend(halo_send_data.at(i).data(), halo_send_sizes.at(i), halo_ranks[i]);
1150 halo_recv_reqs.wait_all();
1162 std::size_t recv_data_size = halo_recv_data.size();
1163 ancestor.progeny_comm.
bcast(&recv_data_size, std::size_t(1), 0);
1166 if(ancestor.progeny_comm.
rank() != 0)
1168 XASSERT(halo_recv_data.empty());
1169 halo_recv_data.resize(recv_data_size);
1173 XASSERT(!halo_recv_data.empty());
1177 ancestor.progeny_comm.
bcast(halo_recv_data.data(), recv_data_size, 0);
1199 for(std::size_t i(0); i < num_halos; ++i)
1202 const Index offset = halo_recv_data.at(i);
1205 const Index num_childs = halo_recv_data.at(offset);
1208 for(
Index j(0); j < num_childs; ++j)
1211 const Index buffer_offset = offset + halo_recv_data.at(offset+j+1u);
1214 if(!halo_splitter.intersect_split_halo(halo_ranks[i], halo_recv_data, buffer_offset))
1218 const int neighbor_rank = int(halo_recv_data.at(buffer_offset));
1221 neighbor_ranks.push_back(neighbor_rank);
1224 patch_mesh_node.
add_halo(neighbor_rank, halo_splitter.make_unique());
1258 const Index factor =
Index(Geometry::Intern::StandardRefinementTraits<typename BaseClass::ShapeType, BaseClass::ShapeType::dimension>::count);
1268 for(; num_elems < min_elems; ++level)
1270 num_elems *= factor;
1298 std::vector<WeightType> weights = this->
_compute_weights(ancestor, base_mesh_node);
1341#ifdef FEAT_HAVE_ZOLTAN
1343 if(!this->_allow_parti_zoltan)
1350 constexpr int shape_dim = MeshNodeType::MeshType::ShapeType::dimension;
1351 const auto& faces_at_elem = base_mesh_node.
get_mesh()->template get_index_set<shape_dim, 0>();
1370 (void)base_mesh_node;
1393#ifdef FEAT_HAVE_PARMETIS
1395 if(!this->_allow_parti_metis)
1402 constexpr int shape_dim = MeshNodeType::MeshType::ShapeType::dimension;
1403 const auto& faces_at_elem = base_mesh_node.
get_mesh()->template get_index_set<shape_dim, 0>();
1406 const auto& verts_at_elem = base_mesh_node.
get_mesh()->template get_index_set<shape_dim, 0>();
1407 const auto& vertex_set = base_mesh_node.
get_mesh()->get_vertex_set();
1410 if(!partitioner.
execute(faces_at_elem, verts_at_elem, vertex_set, ancestor.
num_parts, weights))
1426 (void)base_mesh_node;
1447 if(!this->_allow_parti_genetic || !weights.empty())
1453 ancestor.progeny_comm,
1455 this->_genetic_time_init,
1456 this->_genetic_time_mutate);
1459 ancestor.
parti_graph = partitioner.build_elems_at_rank();
1489 if(!this->_allow_parti_naive)
1493 const Index num_elems = mesh_node.
get_mesh()->get_num_elements();
1494 XASSERTM(num_parts <= num_elems,
"Base-Mesh does not have enough elements");
1502 if(!weights.empty())
1506 for(
auto w : weights)
1513 for(
Index i(1), last(0); i < num_parts; ++i)
1517 for(; (weight_count < target_weight) && (last < num_elems); ++last)
1518 weight_count += weights[last];
1522 ptr[num_parts] = num_elems;
1528 for(
Index i(1); i < num_parts; ++i)
1529 ptr[i] = (i*num_elems) / num_parts;
1530 ptr[num_parts] = num_elems;
1533 for(
Index j(0); j < num_elems; ++j)
#define XASSERT(expr)
Assertion macro definition.
#define XASSERTM(expr, msg)
Assertion macro definition with custom message.
Adjacency Graph implementation.
Index * get_domain_ptr()
Returns the domain pointer array.
Index * get_image_idx()
Returns the image node index array.
std::vector< char > & container()
Returns a reference to the internal vector container.
Domain control base-class template.
bool parti_apriori
specifies whether the chosen partitioning is an a-priori partitioning strategy
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
Base-Class for Hierarchical Domain Control implementations.
const std::deque< std::pair< int, int > > get_chosen_levels() const
Returns the deque of chosen refinement levels.
virtual String format_desired_levels() const
Returns the desired levels formatted as a parsable string.
bool _allow_parti_naive
allow naive partitioner?
int get_desired_level_min() const
Returns the desired minimum refinement level.
PartiDomainControlBase(const Dist::Comm &comm_, bool support_multi_layered)
Constructor.
virtual std::vector< WeightType > _compute_weights(Ancestor &ancestor, const MeshNodeType &base_mesh_node)
Computes the element partitioning weights.
virtual void _reset_parti_types()
Resets/disables all partitioner types.
void set_adapt_mode(Geometry::AdaptMode adapt_mode)
Sets the adapt-mode for refinement.
String dump_ancestry() const
Debugging function: Returns a string containing encoded ancestry information.
void set_desired_levels(const String &slvls)
Sets the desired levels for the partitioned hierarchy.
const std::deque< std::pair< int, int > > get_desired_levels() const
Returns the deque of desired refinement levels.
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
double _genetic_time_mutate
time for genetic partitioner mutation
std::deque< Ancestor > _ancestry
the partition ancestry deque
bool _apply_parti_zoltan(Ancestor &ancestor, const MeshNodeType &base_mesh_node, const std::vector< WeightType > &weights)
Applies the Zoltan partitioner onto the base-mesh.
bool _apply_parti_naive(Ancestor &ancestor, const MeshNodeType &mesh_node, const std::vector< WeightType > &weights)
Applies the naive partitioner onto the base-mesh.
bool _apply_parti_metis(Ancestor &ancestor, const MeshNodeType &base_mesh_node, const std::vector< WeightType > &weights)
Applies the METIS partitioner onto the base-mesh.
virtual bool parse_args(SimpleArgParser &args)
Parses the partitioner options from an argument parser.
bool _apply_parti_genetic(Ancestor &ancestor, MeshNodeType &base_mesh_node, const std::vector< WeightType > &weights)
Applies the genetic partitioner onto the base-mesh.
Geometry::RootMeshNode< MeshType > MeshNodeType
our root mesh node type
const std::deque< Ancestor > & get_ancestry() const
Returns a const reference to the ancestry.
std::vector< char > serialize_partitioning() const
Serializes the partitioning information into a binary buffer.
virtual bool _parse_parti_type(const String &type)
Parses a partitioner type.
virtual String format_chosen_levels() const
Returns the chosen levels formatted as a parsable string.
virtual void set_desired_levels(int lvl_max, int lvl_med, int lvl_min)
Sets the desired refinement levels for a double-layered hierarchy.
LevelType::PartType MeshPartType
our mesh-part type
Geometry::AdaptMode get_adapt_mode() const
Gets the adapt-mode for refinement.
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
bool _allow_parti_metis
allow metis partitioner?
int get_desired_level_max() const
Returns the desired maximum refinement level.
virtual ~PartiDomainControlBase()
virtual destructor
virtual void set_desired_levels(const std::deque< String > &slvls)
Sets the desired levels for the partitioned hierarchy.
bool _was_created
specifies whether the domain control was already created
virtual String get_chosen_parti_info() const
Returns an informative string about the chosen partitioning.
virtual bool parse_property_map(const PropertyMap &pmap)
Parses the partitioner options from a PropertyMap.
double _genetic_time_init
time for genetic partitioner initialization
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.
Control::Domain::DomainControl< DomainLevel_ > BaseClass
Our base class.
virtual void set_desired_levels(int lvl_max, int lvl_min=-1)
Sets the desired refinement levels for a single-layered hierarchy.
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.
bool _allow_parti_genetic
allow genetic partitioner?
bool _allow_parti_zoltan
allow Zoltan partitioner?
void bcast(void *buffer, std::size_t count, const Datatype &datatype, int root) const
Blocking broadcast.
Comm comm_create_range_incl(int count, int first=0, int stride=1) const
Creates a new sub-communicator from a strided range of ranks.
void allreduce(const void *sendbuf, void *recvbuf, std::size_t count, const Datatype &datatype, const Operation &op) const
Blocking All-Reduce.
int size() const
Returns the size of this communicator.
Request irecv(void *buffer, std::size_t count, const Datatype &datatype, int source, int tag=0) const
Nonblocking Receive.
Request isend(const void *buffer, std::size_t count, const Datatype &datatype, int dest, int tag=0) const
Nonblocking Send.
MPI_Comm comm
our MPI communicator handle
void gather(const void *sendbuf, std::size_t sendcount, const Datatype &sendtype, void *recvbuf, std::size_t recvcount, const Datatype &recvtype, int root) const
Blocking gather.
Comm comm_dup() const
Creates a copy of this communicator.
int rank() const
Returns the rank of this process in this communicator.
bool is_null() const
Checks whether this communicator is a null communicator.
void print(std::ostream &os, const String &msg, int root=0) const
Prints a message line to an output stream.
Communication Request vector class.
void wait_all()
Blocks until all active requests are fulfilled.
MeshType * get_mesh()
Returns the mesh of this node.
Iterative-Partitioner class template declaration.
ParMETIS mesh/graph partitioner backend.
bool execute(const IndexSet< nf_ > &faces_at_elem, const IndexSet< nv_ > &verts_at_elem, const VertexSet_ &vertices, const Index num_parts, const std::vector< Real > &weights)
Executes the ParMETIS graph partitioner.
Adjacency::Graph build_elems_at_rank() const
Builds and returns the elements-at-rank graph representing the partitioning.
Zoltan hypergraph partitioner backend.
bool execute(const IndexSet< n_ > &faces_at_elem, const Index num_parts, const std::vector< Real > &weights)
Executes the Zoltan partitioner.
Adjacency::Graph build_elems_at_rank() const
Builds and returns the elements-at-rank graph representing the partitioning.
Base-Mesh Patch Halo splitter.
Root mesh node class template.
const MeshPartType * get_patch(int rank) const
Returns a patch meshpart for a given child.
const std::map< int, std::unique_ptr< MeshPartType > > & get_halo_map() const
void add_halo(int rank, std::unique_ptr< MeshPartType > halo_part)
Adds a halo mesh part to this mesh node.
Class for parser related errors.
A class organizing a tree of key-value pairs.
std::pair< String, bool > query(String key_path) const
Queries a value by its key path.
Simple argument parser implementation.
const std::pair< int, std::deque< String > > * query(const String &option) const
Query the parameters of an option.
int parse(const String &option, Prms_ &&... prms) const
Parses the parameters of an option.
String class implementation.
std::deque< String > split_by_whitespaces() const
Splits the string by white-spaces.
int compare_no_case(const String &other) const
Compares two strings without regard to case.
String pad_front(size_type len, char c=' ') const
Pads the front of the string up to a desired length.
const Operation op_max(MPI_MAX)
Operation wrapper for MPI_MAX.
AdaptMode
Adapt mode enumeration.
T_ max(T_ a, T_ b)
Returns the maximum of two values.
double Real
Real data type.
String stringify(const T_ &item)
Converts an item into a String.
std::uint64_t Index
Index data type.