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;
215 auto it = args.
query(
"parti-type");
222 for(
const auto& t : it->second)
227 this->_comm.
print(
"ERROR: unknown partitioner type '" + t +
"'");
257 auto parti_type_p = pmap.
query(
"parti-type");
258 if(parti_type_p.second)
263 std::deque<String> allowed_partitioners = parti_type_p.first.split_by_whitespaces();
265 for(
const auto& t : allowed_partitioners)
269 this->_comm.
print(
"ERROR: unknown partitioner type '" + t +
"'");
275 auto parti_rank_elems_p = pmap.
query(
"parti-rank-elems");
276 if(parti_rank_elems_p.second)
280 this->_comm.
print(
"ERROR: Failed to parse 'parti-rank-elems'");
285 auto genetic_time_init_p = pmap.
query(
"parti-genetic-time-init");
286 if(genetic_time_init_p.second)
290 this->_comm.
print(
"ERROR: Failed to parse 'parti-genetic-time-init'");
295 auto genetic_time_mutate_p = pmap.
query(
"parti-genetic-time-mutate");
296 if(genetic_time_mutate_p.second)
300 this->_comm.
print(
"ERROR: Failed to parse 'parti-genetic-time-mutate'");
355 const int nranks = this->_comm.
size();
356 std::deque<String> sv;
358 for(std::size_t i(0); i < slvls.size(); ++i)
360 int ilvl = -1, nprocs = -1;
361 sv = slvls.at(i).split_by_string(
":");
363 if((sv.size() < std::size_t(1)) || (sv.size() > std::size_t(2)))
364 throw ParseError(
"Invalid input format", slvls.at(i),
"an int-pair 'level:patches'");
366 if(!sv.front().parse(ilvl))
367 throw ParseError(
"Failed to parse level index", slvls.at(i),
"an integer");
368 if((sv.size() > std::size_t(1)) && !sv.back().parse(nprocs))
369 throw ParseError(
"Failed to parse process count" , slvls.at(i),
"an integer");
373 throw ParseError(
"Invalid negative level index", slvls.at(i),
"a non-negative level index");
376 if(i == std::size_t(0))
379 if((nprocs >= 0) && (nprocs != this->_comm.
size()))
380 throw ParseError(
"Invalid number of processes for global level: '" + slvls.at(i) +
388 throw ParseError(
"Invalid non-descending level index: '" + slvls.at(i) +
392 if((i + 1) == slvls.size())
399 throw ParseError(
"Invalid non-descending process count: '" + slvls.at(i) +
403 throw ParseError(
"Invalid indivisible process count: '" + slvls.at(i) +
426 int _desired_level_max = lvl_max;
427 int _desired_level_min = (lvl_min >= 0 ? lvl_min : lvl_max + lvl_min + 1);
429 XASSERTM(_desired_level_max >= 0,
"Invalid level-max");
430 XASSERTM(_desired_level_min >= 0,
"Invalid level-min");
431 XASSERTM(_desired_level_max >= _desired_level_min,
"Invalid level-min/max combination");
456 int _desired_level_max = lvl_max;
457 int _desired_level_med = (lvl_med >= 0 ? lvl_med : lvl_max + lvl_med + 1);
458 int _desired_level_min = (lvl_min >= 0 ? lvl_min : lvl_med + lvl_min + 1);
460 XASSERTM(_desired_level_max >= 0,
"Invalid level-max");
461 XASSERTM(_desired_level_med >= 0,
"Invalid level-med");
462 XASSERTM(_desired_level_min >= 0,
"Invalid level-min");
465 XASSERTM(_desired_level_max > _desired_level_med,
"Invalid level-max/med combination");
468 XASSERTM(_desired_level_med >= _desired_level_min,
"Invalid level-med/min combination");
553 for(
auto it = this->_ancestry.rbegin(); it != this->_ancestry.rend(); ++it)
555 if(it != this->_ancestry.rbegin())
562 s += (it->num_parts > 1 ?
" patches on " :
" patch on ");
564 s += (it->num_procs > 1 ?
" processes" :
" process");
596 for(
auto it = this->_ancestry.begin(); it != this->_ancestry.end(); ++it)
598 if(it != this->_ancestry.begin())
612 s +=
stringify((*it).progeny_comm.rank());
619 s += ((*it).layer >= 0 ?
"*" :
" ");
620 s += ((*it).layer_p >= 0 ?
">" :
" ");
639 typedef std::uint64_t u64;
642 const std::uint64_t magic = 0x6F436F4461503346;
644 XASSERT(this->_num_global_layers >= this->_ancestry.size());
646 if(this->_comm.
rank() == 0)
649 bs.write((
const char*)&magic, 8u);
652 const u64 lev = u64(this->_virt_levels.front()->get_level_index());
653 bs.write((
const char*)&lev, 8u);
656 const u64 na = u64(this->_ancestry.size());
657 bs.write((
const char*)&na, 8u);
660 for(
auto it = this->_ancestry.rbegin(); it != this->_ancestry.rend(); ++it)
663 const u64 np = u64(it->num_procs);
664 const u64 pl = u64(it->parti_level);
665 bs.write((
const char*)&np, 8u);
666 bs.write((
const char*)&pl, 8u);
671 for(
auto it = this->_ancestry.rbegin(); it != this->_ancestry.rend(); ++it)
673 if(it == this->_ancestry.rbegin())
675 std::vector<char> buf = it->parti_graph.serialize();
676 bs.write(buf.data(), std::streamsize(buf.size()));
685 const std::size_t ilp = std::size_t(it->layer_p);
686 XASSERT(ilp < this->_layers.size());
687 const Dist::Comm& comm_p = this->_layers.at(ilp)->comm();
690 std::vector<char> buf = it->parti_graph.serialize();
693 u64 buf_size = buf.size();
696 std::vector<u64> all_sizes;
697 if(comm_p.
rank() == 0)
698 all_sizes.resize(std::size_t(comm_p.
size()));
699 comm_p.
gather(&buf_size, 1u, all_sizes.data(), 1u, 0);
705 if(buf_size > u64(buf.size()))
706 buf.resize(buf_size);
709 std::vector<char> com_buf;
710 if(comm_p.
rank() == 0)
711 com_buf.resize(std::size_t(buf_size * u64(comm_p.
size())));
714 comm_p.
gather(buf.data(), buf_size, com_buf.data(), buf_size, 0);
717 if(comm_p.
rank() == 0)
719 char* x = com_buf.data();
720 for(u64 k(0); k < u64(comm_p.
size()); ++k)
721 bs.write(&x[k*buf_size], std::streamsize(all_sizes[k]));
775 return std::vector<WeightType>();
784 XASSERTM(this->_desired_levels.size() <= std::size_t(2),
"multi-layered control is desired here");
787 this->_ancestry.resize(std::size_t(1));
788 Ancestor& ancestor = this->_ancestry.front();
806 ancestor.desired_level_min = this->_desired_levels.back().first;
821#if defined(FEAT_HAVE_MPI) || defined(DOXYGEN)
829 this->push_layer(std::make_shared<LayerType>(this->_comm.
comm_dup(), 0));
832 for(std::size_t ilay(1u); (ilay+1u) < this->_desired_levels.size(); ++ilay)
835 std::shared_ptr<LayerType> layer_c = this->_layers.back();
841 const int nprocs_c = comm_c.
size();
844 const int nprocs_p = this->_desired_levels.at(ilay).second;
847 XASSERT(nprocs_c % nprocs_p == 0);
850 const int num_sibs = nprocs_c / nprocs_p;
853 const int my_rank_c = comm_c.
rank();
856 const int parent_rank_c = (my_rank_c / num_sibs) * num_sibs;
865 if(parent_rank_c == my_rank_c)
871 this->push_layer(std::make_shared<LayerType>(std::move(comm_p),
int(ilay)));
890 XASSERT(!this->_layers.empty());
893 std::deque<int> num_procs;
894 for(
auto it = this->_desired_levels.begin(); it != this->_desired_levels.end(); ++it)
897 num_procs.push_back(it->second);
900 num_procs.push_back(1);
903 this->_ancestry.resize(num_procs.size()-std::size_t(1));
906 const int main_rank = this->_comm.
rank();
907 const int main_size = this->_comm.
size();
908 for(std::size_t i(0); i < this->_ancestry.size(); ++i)
911 Ancestor& ancestor = this->_ancestry.at(i);
914 ancestor.
layer = (i < this->_layers.size() ? int(i) : -1);
917 ancestor.
layer_p = ((i+1u) < this->_layers.size() ? int(i)+1 : -1);
923 ancestor.
num_parts = num_procs.at(i) / num_procs.at(i+1u);
930 if((i+1u) < this->_desired_levels.size())
931 ancestor.desired_level_min = this->_desired_levels.at(i+1).first;
967 std::vector<int>& neighbor_ranks)
970 const std::map<int, std::unique_ptr<MeshPartType>>& base_halo_map = base_mesh_node.
get_halo_map();
973 if(base_halo_map.empty())
977 const std::size_t num_halos = base_halo_map.size();
984 std::vector<int> halo_ranks;
985 std::vector<std::size_t> halo_sizes;
986 for(
auto it = base_halo_map.begin(); it != base_halo_map.end(); ++it)
989 halo_ranks.push_back(it->first);
992 halo_sizes.push_back(halo_splitter.add_halo(it->first, *it->second));
996 std::vector<Index> halo_recv_data;
997 std::vector<std::vector<Index>> halo_send_data;
1004 if(ancestor.
layer >= 0)
1006 XASSERT(this->_layers.size() > std::size_t(ancestor.
layer));
1007 const LayerType& layer = *this->_layers.at(std::size_t(ancestor.
layer));
1008 const Dist::Comm& sibling_comm = *layer.sibling_comm_ptr();
1010 const std::size_t num_sibls = std::size_t(sibling_comm.
size());
1013 const int sibl_rank = sibling_comm.
rank();
1014 const int layer_rank = layer.comm().
rank();
1017 std::vector<std::size_t> sibl_halo_sizes(sibl_rank == 0 ? num_halos*num_sibls : 0u);
1018 sibling_comm.
gather(halo_sizes.data(), halo_sizes.size(), sibl_halo_sizes.data(), halo_sizes.size(), 0);
1022 std::vector<std::vector<Index>> halo_split_data(num_halos);
1026 for(std::size_t i(0); i < num_halos; ++i)
1029 if(halo_sizes.at(i) ==
Index(0))
1033 halo_split_data.at(i) = halo_splitter.serialize_split_halo(halo_ranks[i], layer_rank);
1034 XASSERT(halo_split_data.at(i).size() == halo_sizes.at(i));
1037 send_reqs[i] = sibling_comm.
isend(halo_split_data.at(i).data(), halo_sizes.at(i), 0);
1045 halo_send_data.resize(num_halos);
1048 for(std::size_t i(0); i < num_halos; ++i)
1052 Index num_halo_childs = 0u;
1053 std::size_t buffer_size = 0u, offset = 0u;
1054 for(std::size_t j(0); j < num_sibls; ++j)
1057 buffer_size += sibl_halo_sizes.at(j*num_halos + i);
1060 if(sibl_halo_sizes.at(j*num_halos + i) > std::size_t(0))
1065 buffer_size += num_halo_childs +
Index(1);
1068 halo_send_data.at(i).resize(buffer_size);
1069 Index* halo_buffer = halo_send_data.at(i).data();
1072 halo_buffer[0u] = num_halo_childs;
1075 offset = num_halo_childs +
Index(1);
1079 if(sibl_halo_sizes.at(i) >
Index(0))
1081 std::vector<Index> my_data(halo_splitter.serialize_split_halo(halo_ranks[i], layer_rank));
1082 std::size_t data_size = sibl_halo_sizes.at(i);
1083 halo_buffer[++coi] =
Index(offset);
1084 for(std::size_t k(0); k < data_size; ++k)
1085 halo_buffer[offset+k] = my_data[k];
1086 offset += my_data.size();
1092 for(std::size_t j(1); j < num_sibls; ++j)
1095 std::size_t data_size = sibl_halo_sizes.at(j*num_halos + i);
1096 if(data_size == std::size_t(0))
1098 XASSERT(offset+data_size <= buffer_size);
1101 halo_buffer[++coi] =
Index(offset);
1104 sibl_recv_reqs[j] = sibling_comm.
irecv(&halo_buffer[offset], data_size,
int(j));
1105 offset += data_size;
1107 XASSERT(offset == buffer_size);
1123 XASSERT(!halo_send_data.empty());
1126 const Dist::Comm& parent_comm = this->_layers.at(std::size_t(ancestor.
layer_p))->comm();
1128 std::vector<std::size_t> halo_recv_sizes(num_halos), halo_send_sizes(num_halos);
1132 for(std::size_t i(0); i < num_halos; ++i)
1135 halo_send_sizes.at(i) = halo_send_data.at(i).size();
1138 halo_recv_reqs[i] = parent_comm.
irecv(&halo_recv_sizes[i], std::size_t(1), halo_ranks[i]);
1141 halo_send_reqs[i] = parent_comm.
isend(&halo_send_sizes[i], std::size_t(1), halo_ranks[i]);
1145 halo_recv_reqs.wait_all();
1149 std::size_t recv_buf_size = num_halos + std::size_t(1);
1150 for(std::size_t i(0); i < num_halos; ++i)
1151 recv_buf_size += halo_recv_sizes[i];
1154 halo_recv_data.resize(recv_buf_size);
1157 halo_recv_data[0] =
Index(num_halos) +
Index(1);
1158 for(std::size_t i(0); i < num_halos; ++i)
1159 halo_recv_data[i+1u] =
Index(halo_recv_data[i] + halo_recv_sizes[i]);
1162 for(std::size_t i(0); i < num_halos; ++i)
1165 halo_recv_reqs[i] = parent_comm.
irecv(&halo_recv_data[halo_recv_data[i]], halo_recv_sizes.at(i), halo_ranks[i]);
1168 halo_send_reqs[i] = parent_comm.
isend(halo_send_data.at(i).data(), halo_send_sizes.at(i), halo_ranks[i]);
1172 halo_recv_reqs.wait_all();
1184 std::size_t recv_data_size = halo_recv_data.size();
1190 XASSERT(halo_recv_data.empty());
1191 halo_recv_data.resize(recv_data_size);
1195 XASSERT(!halo_recv_data.empty());
1221 for(std::size_t i(0); i < num_halos; ++i)
1224 const Index offset = halo_recv_data.at(i);
1227 const Index num_childs = halo_recv_data.at(offset);
1230 for(
Index j(0); j < num_childs; ++j)
1233 const Index buffer_offset = offset + halo_recv_data.at(offset+j+1u);
1236 if(!halo_splitter.intersect_split_halo(halo_ranks[i], halo_recv_data, buffer_offset))
1240 const int neighbor_rank = int(halo_recv_data.at(buffer_offset));
1243 neighbor_ranks.push_back(neighbor_rank);
1246 patch_mesh_node.
add_halo(neighbor_rank, halo_splitter.make_unique());
1280 const Index factor =
Index(Geometry::Intern::StandardRefinementTraits<typename BaseClass::ShapeType, BaseClass::ShapeType::dimension>::count);
1290 for(; num_elems < min_elems; ++level)
1292 num_elems *= factor;
1320 std::vector<WeightType> weights = this->
_compute_weights(ancestor, base_mesh_node);
1363#ifdef FEAT_HAVE_ZOLTAN
1365 if(!this->_allow_parti_zoltan)
1372 constexpr int shape_dim = MeshNodeType::MeshType::ShapeType::dimension;
1373 const auto& faces_at_elem = base_mesh_node.
get_mesh()->template get_index_set<shape_dim, 0>();
1392 (void)base_mesh_node;
1415#ifdef FEAT_HAVE_PARMETIS
1417 if(!this->_allow_parti_metis)
1424 constexpr int shape_dim = MeshNodeType::MeshType::ShapeType::dimension;
1425 const auto& faces_at_elem = base_mesh_node.
get_mesh()->template get_index_set<shape_dim, 0>();
1428 const auto& verts_at_elem = base_mesh_node.
get_mesh()->template get_index_set<shape_dim, 0>();
1429 const auto& vertex_set = base_mesh_node.
get_mesh()->get_vertex_set();
1432 if(!partitioner.
execute(faces_at_elem, verts_at_elem, vertex_set,
Index(ancestor.
num_parts), weights))
1448 (void)base_mesh_node;
1469 if(!this->_allow_parti_genetic || !weights.empty())
1477 this->_genetic_time_init,
1478 this->_genetic_time_mutate);
1481 ancestor.
parti_graph = partitioner.build_elems_at_rank();
1511 if(!this->_allow_parti_naive)
1515 const Index num_elems = mesh_node.
get_mesh()->get_num_elements();
1516 XASSERTM(num_parts <= num_elems,
"Base-Mesh does not have enough elements");
1525 if(!weights.empty() && num_elems > num_parts)
1529 for(
auto w : weights)
1536 for(
Index i(1), last(0); i < num_parts; ++i)
1542 for(; (weight_count <= target_weight) && (last < num_elems); ++last)
1543 weight_count += weights[last];
1547 ptr[num_parts] = num_elems;
1553 for(
Index i(1); i < num_parts; ++i)
1554 ptr[i] = (i*num_elems) / num_parts;
1555 ptr[num_parts] = num_elems;
1558 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.
Dist::Comm progeny_comm
Progeny communicator.
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
int progeny_first
First process of the progeny group of this process. Numbered w.r.t. the DomainControllers communicato...
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
int progeny_count
Size of the progeny group of this process.
Adjacency::Graph parti_graph
this is the actual elements-at-rank partitioning graph
int progeny_group
Progeny group of this process.
int layer_p
the index of the parent layer or -1, if this process is not part of the parent layer
int layer
the index of the layer that this ancestor object belongs to
int num_parts
the number of partitions for each patch of the parent layer
int progeny_child
Which direct child this process belongs to in its progeny group.
Base-Class for Hierarchical Domain Control implementations.
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.