20 #include "libmesh/partitioner.h" 23 #include "libmesh/compare_elems_by_level.h" 24 #include "libmesh/elem.h" 25 #include "libmesh/enum_to_string.h" 26 #include "libmesh/int_range.h" 27 #include "libmesh/libmesh_logging.h" 28 #include "libmesh/mesh_base.h" 29 #include "libmesh/mesh_tools.h" 30 #include "libmesh/mesh_communication.h" 31 #include "libmesh/parallel_ghost_sync.h" 32 #include "libmesh/wrapped_petsc.h" 33 #include "libmesh/boundary_info.h" 36 #include "libmesh/enum_partitioner_type.h" 37 #include "libmesh/centroid_partitioner.h" 38 #include "libmesh/hilbert_sfc_partitioner.h" 39 #include "libmesh/linear_partitioner.h" 40 #include "libmesh/mapped_subdomain_partitioner.h" 41 #include "libmesh/metis_partitioner.h" 42 #include "libmesh/morton_sfc_partitioner.h" 43 #include "libmesh/parmetis_partitioner.h" 44 #include "libmesh/sfc_partitioner.h" 45 #include "libmesh/subdomain_partitioner.h" 52 #ifdef LIBMESH_HAVE_PETSC 53 #include "libmesh/ignore_warnings.h" 55 #include "libmesh/restore_warnings.h" 56 #include "libmesh/petsc_solver_exception.h" 69 std::unordered_set<dof_id_type> & _bad_pids) :
70 mesh(_mesh), bad_pids(_bad_pids) {}
73 std::unordered_set<dof_id_type> & bad_pids;
76 void gather_data (
const std::vector<dof_id_type> & ids,
77 std::vector<datum> & data)
80 data.resize(ids.size());
87 !bad_pids.count(ids[i]))
100 bool act_on_data (
const std::vector<dof_id_type> & ids,
101 const std::vector<datum> proc_ids)
103 bool data_changed =
false;
113 if (
const auto it = bad_pids.find(ids[i]);
114 (new_proc_id != proc_id || it != bad_pids.end()) &&
117 if (it != bad_pids.end())
119 proc_id = new_proc_id;
125 if (proc_id == new_proc_id)
158 std::unique_ptr<Partitioner>
161 switch (partitioner_type)
164 return std::make_unique<CentroidPartitioner>();
166 return std::make_unique<LinearPartitioner>();
168 return std::make_unique<MappedSubdomainPartitioner>();
170 return std::make_unique<MetisPartitioner>();
172 return std::make_unique<ParmetisPartitioner>();
174 return std::make_unique<HilbertSFCPartitioner>();
176 return std::make_unique<MortonSFCPartitioner>();
178 return std::make_unique<SFCPartitioner>();
180 return std::make_unique<SubdomainPartitioner>();
182 libmesh_error_msg(
"Invalid partitioner type: " <<
197 const unsigned int n)
208 const unsigned int n_parts =
209 static_cast<unsigned int> 239 MeshTools::libmesh_assert_valid_procids<Elem>(
mesh);
246 MeshTools::libmesh_assert_valid_procids<Elem>(
mesh);
264 const unsigned int n)
268 const unsigned int n_parts =
269 static_cast<unsigned int> 302 mesh.elements_end());
323 LOG_SCOPE(
"single_partition_range()",
"Partitioner");
325 bool changed_pid =
false;
327 for (
auto & elem :
as_range(it, end))
329 if (elem->processor_id())
331 elem->processor_id() = 0;
334 for (
Node & node : elem->node_ref_range())
353 const unsigned int n_subdomains)
362 if (!n_unpartitioned_elements)
373 if (pid < n_subdomains)
375 tgt_subdomain_size = n_unpartitioned_elements/n_subdomains;
377 if (pid < n_unpartitioned_elements%n_subdomains)
378 tgt_subdomain_size++;
384 subdomain_bounds[0] = tgt_subdomain_size;
386 subdomain_bounds[pid] = subdomain_bounds[pid-1] + tgt_subdomain_size;
389 libmesh_assert_equal_to (subdomain_bounds.back(), n_unpartitioned_elements);
393 std::vector<dof_id_type> global_indices;
402 for (
auto & elem :
as_range(it, end))
404 libmesh_assert_less (cnt, global_indices.size());
406 global_indices[cnt++];
408 libmesh_assert_less (global_index, subdomain_bounds.back());
409 libmesh_assert_less (global_index, n_unpartitioned_elements);
412 cast_int<processor_id_type>
414 std::upper_bound(subdomain_bounds.begin(),
415 subdomain_bounds.end(),
417 libmesh_assert_less (subdomain_id, n_subdomains);
419 elem->processor_id() = subdomain_id;
431 LOG_SCOPE(
"set_parent_processor_ids()",
"Partitioner");
433 #ifdef LIBMESH_ENABLE_AMR 445 for (
auto & elem :
mesh.active_element_ptr_range())
448 std::vector<Elem *> subactive_family;
449 elem->total_family_tree(subactive_family);
450 for (
const auto & f : subactive_family)
451 f->processor_id() = elem->processor_id();
468 child.processor_id());
470 parent = parent->
parent();
483 for (
auto & child :
mesh.active_element_ptr_range())
485 std::vector<Elem *> subactive_family;
487 for (
const auto & f : subactive_family)
488 f->processor_id() = child->processor_id();
502 mesh.unpartitioned_elements_end()) == 0);
506 std::vector<processor_id_type>
510 for (
dof_id_type blk=0, last_elem_id=0; last_elem_id<max_elem_id; blk++)
517 std::fill (parent_processor_ids.begin(),
518 parent_processor_ids.end(),
522 bool have_parent_in_block =
false;
524 for (
auto & parent :
as_range(
mesh.ancestor_elements_begin(),
525 mesh.ancestor_elements_end()))
528 libmesh_assert_less (parent_idx, max_elem_id);
530 if ((parent_idx >= first_elem_id) &&
531 (parent_idx < last_elem_id))
533 have_parent_in_block =
true;
536 std::vector<const Elem *> active_family;
537 parent->active_family_tree(active_family);
538 for (
const auto & f : active_family)
539 parent_pid = std::min (parent_pid, f->processor_id());
541 const dof_id_type packed_idx = parent_idx - first_elem_id;
542 libmesh_assert_less (packed_idx, parent_processor_ids.size());
544 parent_processor_ids[packed_idx] = parent_pid;
552 if (have_parent_in_block)
553 for (
auto & parent :
as_range(
mesh.ancestor_elements_begin(),
554 mesh.ancestor_elements_end()))
558 if ((parent_idx >= first_elem_id) &&
559 (parent_idx < last_elem_id))
561 const dof_id_type packed_idx = parent_idx - first_elem_id;
562 libmesh_assert_less (packed_idx, parent_processor_ids.size());
565 parent_processor_ids[packed_idx];
569 parent->processor_id() = parent_pid;
575 #endif // LIBMESH_ENABLE_AMR 580 std::map<std::pair<processor_id_type, processor_id_type>, std::set<dof_id_type>> & processor_pair_to_nodes)
585 processor_pair_to_nodes.clear();
587 std::set<dof_id_type> mynodes;
588 std::set<dof_id_type> neighbor_nodes;
589 std::vector<dof_id_type> common_nodes;
592 for (
auto & elem :
mesh.active_element_ptr_range())
598 auto n_nodes = elem->n_nodes();
602 neighbor_nodes.clear();
603 common_nodes.clear();
605 for (
unsigned int inode = 0; inode <
n_nodes; inode++)
606 mynodes.insert(elem->node_id(inode));
608 for (
auto i : elem->side_index_range())
610 auto neigh = elem->neighbor_ptr(i);
611 if (neigh && !neigh->is_remote() && neigh->processor_id() != elem->processor_id())
613 neighbor_nodes.clear();
614 common_nodes.clear();
615 auto neigh_n_nodes = neigh->n_nodes();
616 for (
unsigned int inode = 0; inode < neigh_n_nodes; inode++)
617 neighbor_nodes.insert(neigh->node_id(inode));
619 std::set_intersection(mynodes.begin(), mynodes.end(),
620 neighbor_nodes.begin(), neighbor_nodes.end(),
621 std::back_inserter(common_nodes));
623 auto & map_set = processor_pair_to_nodes[std::make_pair(std::min(elem->processor_id(), neigh->processor_id()),
624 std::max(elem->processor_id(), neigh->processor_id()))];
625 for (
auto global_node_id : common_nodes)
626 map_set.insert(global_node_id);
637 std::map<std::pair<processor_id_type, processor_id_type>, std::set<dof_id_type>> processor_pair_to_nodes;
641 for (
auto & pmap : processor_pair_to_nodes)
643 std::size_t n_own_nodes = pmap.second.size()/2, i = 0;
648 if (i <= n_own_nodes)
664 libmesh_experimental();
666 std::map<std::pair<processor_id_type, processor_id_type>, std::set<dof_id_type>> processor_pair_to_nodes;
670 std::unordered_map<dof_id_type, std::vector<const Elem *>> nodes_to_elem_map;
674 std::vector<const Node *> neighbors;
675 std::set<dof_id_type> neighbors_order;
676 std::vector<dof_id_type> common_nodes;
677 std::queue<dof_id_type> nodes_queue;
678 std::set<dof_id_type> visted_nodes;
680 for (
auto & pmap : processor_pair_to_nodes)
682 std::size_t n_own_nodes = pmap.second.size()/2;
688 visted_nodes.clear();
693 if (visted_nodes.count(
id))
697 nodes_queue.push(
id);
698 visted_nodes.insert(
id);
699 if (visted_nodes.size() >= n_own_nodes)
703 while (!nodes_queue.empty())
710 neighbors_order.clear();
711 for (
auto & neighbor : neighbors)
712 neighbors_order.insert(neighbor->id());
714 common_nodes.clear();
715 std::set_intersection(pmap.second.begin(), pmap.second.end(),
716 neighbors_order.begin(), neighbors_order.end(),
717 std::back_inserter(common_nodes));
719 for (
auto c_node : common_nodes)
720 if (!visted_nodes.count(c_node))
722 nodes_queue.push(c_node);
723 visted_nodes.insert(c_node);
724 if (visted_nodes.size() >= n_own_nodes)
728 if (visted_nodes.size() >= n_own_nodes)
733 for (
auto node : visted_nodes)
745 #if LIBMESH_HAVE_PETSC 746 std::map<std::pair<processor_id_type, processor_id_type>, std::set<dof_id_type>> processor_pair_to_nodes;
750 std::vector<std::vector<const Elem *>> nodes_to_elem_map;
754 std::vector<const Node *> neighbors;
755 std::set<dof_id_type> neighbors_order;
756 std::vector<dof_id_type> common_nodes;
758 std::vector<dof_id_type> rows;
759 std::vector<dof_id_type> cols;
761 std::map<dof_id_type, dof_id_type> global_to_local;
763 for (
auto & pmap : processor_pair_to_nodes)
768 rows.resize(pmap.second.size()+1);
771 global_to_local[id] = i++;
774 for (
auto id : pmap.second)
779 neighbors_order.clear();
780 for (
auto & neighbor : neighbors)
781 neighbors_order.insert(neighbor->id());
783 common_nodes.clear();
784 std::set_intersection(pmap.second.begin(), pmap.second.end(),
785 neighbors_order.begin(), neighbors_order.end(),
786 std::back_inserter(common_nodes));
788 rows[i+1] = rows[i] + cast_int<dof_id_type>(common_nodes.size());
790 for (
auto c_node : common_nodes)
791 cols.push_back(global_to_local[c_node]);
799 PetscInt *adj_i, *adj_j;
800 LibmeshPetscCall2(
mesh.
comm(), PetscCalloc1(rows.size(), &adj_i));
801 LibmeshPetscCall2(
mesh.
comm(), PetscCalloc1(cols.size(), &adj_j));
802 PetscInt rows_size = cast_int<PetscInt>(rows.size());
803 for (PetscInt ii=0; ii<rows_size; ii++)
804 adj_i[ii] = rows[ii];
806 PetscInt cols_size = cast_int<PetscInt>(cols.size());
807 for (PetscInt ii=0; ii<cols_size; ii++)
808 adj_j[ii] = cols[ii];
810 const PetscInt sz = cast_int<PetscInt>(pmap.second.size());
814 LibmeshPetscCall2(
mesh.
comm(), MatCreateMPIAdj(PETSC_COMM_SELF, sz, sz, adj_i, adj_j,
nullptr, adj.get()));
818 LibmeshPetscCall2(
mesh.
comm(), MatPartitioningCreate(PETSC_COMM_SELF, part.
get()));
821 LibmeshPetscCall2(
mesh.
comm(), MatPartitioningSetAdjacency(part, adj));
822 LibmeshPetscCall2(
mesh.
comm(), MatPartitioningSetNParts(part, 2));
823 LibmeshPetscCall2(
mesh.
comm(), PetscObjectSetOptionsPrefix((PetscObject)(*part),
"balance_"));
824 LibmeshPetscCall2(
mesh.
comm(), MatPartitioningSetFromOptions(part));
825 LibmeshPetscCall2(
mesh.
comm(), MatPartitioningApply(part,
is.get()));
829 const PetscInt *indices;
830 LibmeshPetscCall2(
mesh.
comm(), ISGetLocalSize(
is, &local_size));
831 LibmeshPetscCall2(
mesh.
comm(), ISGetIndices(
is, &indices));
834 for (
auto id : pmap.second)
844 LibmeshPetscCall2(
mesh.
comm(), ISRestoreIndices(
is, &indices));
847 libmesh_error_msg(
"PETSc is required");
854 LOG_SCOPE(
"set_node_processor_ids()",
"Partitioner");
862 mesh.unpartitioned_elements_end()) == 0);
866 for (
auto & node :
mesh.node_ptr_range())
872 for (
auto & elem :
mesh.active_element_ptr_range())
879 for (
Node & node : elem->node_ref_range())
889 const bool load_balanced_nodes_linear =
892 const bool load_balanced_nodes_bfs =
895 const bool load_balanced_nodes_petscpartition =
898 unsigned int n_load_balance_options = load_balanced_nodes_linear;
899 n_load_balance_options += load_balanced_nodes_bfs;
900 n_load_balance_options += load_balanced_nodes_petscpartition;
901 libmesh_error_msg_if(n_load_balance_options > 1,
902 "Cannot perform more than one load balancing type at a time");
904 if (load_balanced_nodes_linear)
906 else if (load_balanced_nodes_bfs)
908 else if (load_balanced_nodes_petscpartition)
928 std::unordered_set<dof_id_type> bad_pids;
930 for (
auto & node :
mesh.node_ptr_range())
932 bad_pids.insert(node->
id());
946 std::unordered_map<dof_id_type, processor_id_type>>
950 for (
unsigned int level =
n_levels; level > 0; --level)
952 for (
auto & elem :
as_range(
mesh.level_elements_begin(level-1),
953 mesh.level_elements_end(level-1)))
955 libmesh_assert_not_equal_to (elem->processor_id(),
961 for (
Node & node : elem->node_ref_range())
964 if (bad_pids.count(node.
id()))
967 potential_pids[elem_pid][node.
id()] = pid;
976 std::vector<std::pair<dof_id_type, processor_id_type>>>
979 for (
auto & pair : potential_pids)
980 potential_pids_vecs[pair.first].assign(pair.second.begin(), pair.second.end());
982 auto pids_action_functor =
985 const std::vector<std::pair<dof_id_type, processor_id_type>> & data)
987 for (
auto pair : data)
991 if (
const auto it = bad_pids.find(pair.first);
992 it != bad_pids.end())
1002 Parallel::push_parallel_vector_data
1003 (
mesh.
comm(), potential_pids_vecs, pids_action_functor);
1009 CorrectProcIds correct_pids(
mesh, bad_pids);
1022 mesh.elements_begin(),
mesh.elements_end(),
1034 MeshTools::libmesh_assert_valid_procids<Node>(
mesh);
1045 typedef std::unordered_map<dof_id_type, dof_id_type>
map_type;
1052 std::vector<datum> & local_ids)
const 1054 local_ids.resize(ids.size());
1057 local_ids[i] =
id_map[ids[i]];
1061 const std::vector<datum> & local_ids)
1064 id_map[ids[i]] = local_ids[i];
1084 n_active_elem_before_proc[i+1] =
1094 mesh.active_local_elements_begin(),
1095 mesh.active_local_elements_end(),
1101 (
mesh.
comm(),
mesh.active_elements_begin(),
mesh.active_elements_end(), sync);
1103 for (
const auto & elem :
mesh.active_element_ptr_range())
1114 LOG_SCOPE(
"build_graph()",
"Partitioner");
1122 typedef std::unordered_multimap<const Elem *, const Elem *> map_type;
1123 map_type interior_to_boundary_map;
1129 map_type elems_constrained_by;
1133 for (
const Elem * elem :
mesh.active_element_ptr_range())
1135 if (!mesh_constrained_nodes.empty())
1137 const auto end_it = mesh_constrained_nodes.end();
1141 std::set<const Elem *, CompareElemIdsByLevel> constraining_elems;
1142 for (
const Node & node : elem->node_ref_range())
1144 if (
const auto row_it = mesh_constrained_nodes.find(&node);
1146 for (
const auto & [pr, coef] : row_it->second)
1149 constraining_elems.insert(pr.first);
1152 for (
const Elem * constraining_elem : constraining_elems)
1153 elems_constrained_by.emplace(constraining_elem, elem);
1158 if (elem->interior_parent())
1161 std::set<const Elem *> neighbor_set;
1162 elem->find_interior_neighbors(neighbor_set);
1164 for (
const auto & neighbor : neighbor_set)
1165 interior_to_boundary_map.emplace(neighbor, elem);
1169 #ifdef LIBMESH_ENABLE_AMR 1170 std::vector<const Elem *> neighbors_offspring;
1190 std::vector<std::pair<dof_id_type, dof_id_type>>> connections_to_push;
1192 for (
const auto & elem :
mesh.active_local_element_ptr_range())
1199 global_index_by_pid - first_local_elem;
1200 libmesh_assert_less (local_index, n_active_local_elem);
1202 std::vector<dof_id_type> & graph_row =
_dual_graph[local_index];
1209 for (
auto neighbor : elem->neighbor_ptr_range())
1211 if (neighbor !=
nullptr)
1215 if (neighbor->active())
1221 graph_row.push_back(neighbor_global_index_by_pid);
1224 #ifdef LIBMESH_ENABLE_AMR 1233 const unsigned int ns =
1234 neighbor->which_neighbor_am_i (elem);
1235 libmesh_assert_less (ns, neighbor->n_neighbors());
1248 neighbor->active_family_tree (neighbors_offspring);
1253 for (
const auto & child : neighbors_offspring)
1258 if (child->neighbor_ptr(ns) == elem)
1265 graph_row.push_back(child_global_index_by_pid);
1276 if ((elem->dim() < LIBMESH_DIM) &&
1277 elem->interior_parent())
1280 std::set<const Elem *> neighbor_set;
1281 elem->find_interior_neighbors(neighbor_set);
1283 for (
const auto & neighbor : neighbor_set)
1288 graph_row.push_back(neighbor_global_index_by_pid);
1293 for (
const auto & pr :
as_range(interior_to_boundary_map.equal_range(elem)))
1295 const Elem * neighbor = pr.second;
1300 graph_row.push_back(neighbor_global_index_by_pid);
1304 if (!mesh_constrained_nodes.empty())
1306 const auto end_it = mesh_constrained_nodes.end();
1310 std::set<const Elem *, CompareElemIdsByLevel> constraining_elems;
1311 for (
const Node & node : elem->node_ref_range())
1313 if (
const auto row_it = mesh_constrained_nodes.find(&node);
1315 for (
const auto & [pr, coef] : row_it->second)
1318 constraining_elems.insert(pr.first);
1321 for (
const Elem * constraining_elem : constraining_elems)
1323 const dof_id_type constraining_global_index_by_pid =
1326 graph_row.push_back(constraining_global_index_by_pid);
1332 connections_to_push[constraining_elem->processor_id()].emplace_back
1333 (global_index_by_pid, constraining_global_index_by_pid);
1338 for (
const auto & pr :
as_range(elems_constrained_by.equal_range(elem)))
1340 const Elem * constrained = pr.second;
1341 const dof_id_type constrained_global_index_by_pid =
1344 graph_row.push_back(constrained_global_index_by_pid);
1350 connections_to_push[constrained->
processor_id()].emplace_back
1351 (global_index_by_pid, constrained_global_index_by_pid);
1360 auto symmetrize_entries =
1361 [
this, first_local_elem]
1363 const std::vector<std::pair<dof_id_type, dof_id_type>> & incoming_entries)
1365 for (
auto [i, j] : incoming_entries)
1367 libmesh_assert_greater_equal(j, first_local_elem);
1368 const std::size_t jl = j - first_local_elem;
1370 std::vector<dof_id_type> & graph_row =
_dual_graph[jl];
1371 if (std::find(graph_row.begin(), graph_row.end(), i) == graph_row.end())
1374 graph_row.push_back(i);
1379 Parallel::push_parallel_vector_data(
mesh.
comm(),
1380 connections_to_push,
1381 symmetrize_entries);
1389 std::vector<dof_id_type> first_local_index_on_proc(n_proc, 0);
1396 std::unordered_map<processor_id_type, std::vector<std::pair<dof_id_type, dof_id_type>>> entries_to_send;
1399 const std::vector<dof_id_type> & graph_row =
_dual_graph[il];
1401 const auto i = il + first_local_elem;
1403 for (
auto j : graph_row)
1407 while (target_pid+1 < n_proc &&
1408 j >= first_local_index_on_proc[target_pid+1])
1411 entries_to_send[target_pid].emplace_back(i,j);
1415 std::vector<std::tuple<processor_id_type, dof_id_type, dof_id_type>> bad_entries;
1417 auto check_incoming_entries =
1418 [
this, first_local_elem, &bad_entries]
1420 const std::vector<std::pair<dof_id_type, dof_id_type>> & incoming_entries)
1422 for (
auto [i, j] : incoming_entries)
1424 if (j < first_local_elem)
1426 bad_entries.emplace_back(src_pid,i,j);
1429 const std::size_t jl = j - first_local_elem;
1432 bad_entries.emplace_back(src_pid,i,j);
1435 const std::vector<dof_id_type> & graph_row =
_dual_graph[jl];
1436 if (std::find(graph_row.begin(), graph_row.end(), i) ==
1439 bad_entries.emplace_back(src_pid,i,j);
1447 Parallel::push_parallel_vector_data
1448 (
mesh.
comm(), entries_to_send, check_incoming_entries);
1449 bool bad_entries_exist = !bad_entries.empty();
1451 if (bad_entries_exist)
1453 #if 0 // Optional verbosity for if this breaks again... 1454 if (!bad_entries.empty())
1457 for (
auto [p, i, j] : bad_entries)
1458 std::cerr <<
'(' << p <<
", " << i <<
", " << j <<
"), ";
1459 std::cerr << std::endl;
1462 libmesh_error_msg(
"Asymmetric partitioner graph detected");
1469 LOG_SCOPE(
"assign_partitioning()",
"Partitioner");
1472 libmesh_parallel_only(
mesh.
comm());
1482 std::map<processor_id_type, std::vector<dof_id_type>>
1487 std::map<processor_id_type, std::vector<processor_id_type>>
1490 for (
auto & elem :
mesh.active_element_ptr_range())
1495 requested_ids[elem->processor_id()].push_back(elem->id());
1498 auto gather_functor =
1503 n_active_local_elem,
1507 std::vector<processor_id_type> & data)
1509 const std::size_t ids_size = ids.size();
1510 data.resize(ids.size());
1512 for (std::size_t i=0; i != ids_size; i++)
1522 global_index_by_pid - first_local_elem;
1524 libmesh_assert_less (local_index, parts.size());
1525 libmesh_assert_less (local_index, n_active_local_elem);
1528 cast_int<processor_id_type>(parts[local_index]);
1532 data[i] = elem_procid;
1536 auto action_functor =
1539 const std::vector<dof_id_type> &,
1540 const std::vector<processor_id_type> & new_procids)
1542 filled_request[pid] = new_procids;
1547 Parallel::pull_parallel_vector_data
1548 (
mesh.
comm(), requested_ids, gather_functor, action_functor, ex);
1555 for (
auto & elem :
mesh.active_element_ptr_range())
1559 libmesh_assert_less (counters[current_pid], requested_ids[current_pid].size());
1562 filled_request[current_pid][counters[current_pid]++];
1565 elem->processor_id() = elem_procid;
The definition of the element_iterator struct.
void allgather(const T &send_data, std::vector< T, A > &recv_data) const
void find_global_indices(const Parallel::Communicator &communicator, const libMesh::BoundingBox &, const ForwardIterator &, const ForwardIterator &, std::vector< dof_id_type > &) const
This method determines a globally unique, partition-agnostic index for each object in the input range...
const Elem * parent() const
constraint_rows_type & get_constraint_rows()
Constraint rows accessors.
static void set_interface_node_processor_ids_petscpartitioner(MeshBase &mesh)
Nodes on the partitioning interface is partitioned into two groups using a PETSc partitioner for each...
virtual dof_id_type n_active_elem() const =0
A Node is like a Point, but with more information.
std::unordered_map< dof_id_type, dof_id_type > _global_index_by_pid_map
Maps active element ids into a contiguous range, as needed by parallel partitioner.
bool single_partition(MeshBase &mesh)
Trivially "partitions" the mesh for one processor.
static void set_interface_node_processor_ids_BFS(MeshBase &mesh)
Nodes on the partitioning interface is clustered into two groups BFS (Breadth First Search)scheme for...
bool single_partition_range(MeshBase::element_iterator it, MeshBase::element_iterator end)
Slightly generalized version of single_partition which acts on a range of elements defined by the pai...
static void set_node_processor_ids(MeshBase &mesh)
This function is called after partitioning to set the processor IDs for the nodes.
void act_on_data(const std::vector< dof_id_type > &ids, const std::vector< datum > &local_ids)
static void set_interface_node_processor_ids_linear(MeshBase &mesh)
Nodes on the partitioning interface is linearly assigned to each pair of processors.
This is the base class from which all geometric element types are derived.
const Parallel::Communicator & comm() const
void assign_partitioning(MeshBase &mesh, const std::vector< dof_id_type > &parts)
Assign the computed partitioning to the mesh.
The libMesh namespace provides an interface to certain functionality in the library.
virtual void build_graph(const MeshBase &mesh)
Build a dual graph for partitioner.
Real distance(const Point &p)
std::unordered_map< dof_id_type, dof_id_type > map_type
processor_id_type choose_processor_id(processor_id_type pid1, processor_id_type pid2) const
Return which of pid1 and pid2 would be preferred by the current load-balancing heuristic applied to t...
std::vector< Elem * > _local_id_to_elem
uint8_t processor_id_type
This is the MeshBase class.
SimpleRange< ChildRefIter > child_ref_range()
Returns a range with all children of a parent element, usable in range-based for loops.
virtual void _do_repartition(MeshBase &mesh, const unsigned int n)
This is the actual re-partitioning method which can be overridden in derived classes.
void repartition(MeshBase &mesh, const unsigned int n)
Repartitions the MeshBase into n parts.
uint8_t processor_id_type
PartitionerType
Defines an enum for mesh partitioner types.
dof_id_type n_active_local_elem() const
processor_id_type n_processors() const
virtual bool is_serial() const
void libmesh_ignore(const Args &...)
const dof_id_type n_nodes
This is the MeshCommunication class.
static std::unique_ptr< Partitioner > build(const PartitionerType solver_package)
Builds a Partitioner of the type specified by partitioner_type.
void min(const T &r, T &o, Request &req) const
static const processor_id_type invalid_processor_id
An invalid processor_id to distinguish DoFs that have not been assigned to a processor.
static void processor_pairs_to_interface_nodes(MeshBase &mesh, std::map< std::pair< processor_id_type, processor_id_type >, std::set< dof_id_type >> &processor_pair_to_nodes)
On the partitioning interface, a surface is shared by two and only two processors.
void sync_node_data_by_element_id(MeshBase &mesh, const MeshBase::const_element_iterator &range_begin, const MeshBase::const_element_iterator &range_end, const ElemCheckFunctor &elem_check, const NodeCheckFunctor &node_check, SyncFunctor &sync)
Synchronize data about a range of ghost nodes uniquely identified by an element id and local node id...
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
Helper function that allows us to treat a homogenous pair as a range.
virtual dof_id_type max_elem_id() const =0
void find_local_indices(const libMesh::BoundingBox &, const ForwardIterator &, const ForwardIterator &, std::unordered_map< dof_id_type, dof_id_type > &) const
This method determines a locally unique, contiguous index for each object in the input range...
static const dof_id_type invalid_id
An invalid id to distinguish an uninitialized DofObject.
PetscErrorCode PetscInt const PetscInt IS * is
virtual void _find_global_index_by_pid_map(const MeshBase &mesh)
Construct contiguous global indices for the current partitioning.
void sync_dofobject_data_by_id(const Communicator &comm, const Iterator &range_begin, const Iterator &range_end, SyncFunctor &sync)
Request data about a range of ghost dofobjects uniquely identified by their id.
void invalidate_processor_id()
Sets the processor id to invalid_processor_id.
virtual void _do_partition(MeshBase &mesh, const unsigned int n)=0
This is the actual partitioning method which must be overridden in derived classes.
std::string enum_to_string(const T e)
static void partition_unpartitioned_elements(MeshBase &mesh)
These functions assign processor IDs to newly-created elements (in parallel) which are currently assi...
unsigned int n_partitions() const
Defines a Cartesian bounding box by the two corner extremum.
void max(const T &r, T &o, Request &req) const
static const dof_id_type communication_blocksize
The blocksize to use when doing blocked parallel communication.
virtual void partition(MeshBase &mesh, const unsigned int n)
Partitions the MeshBase into n parts by setting processor_id() on Nodes and Elems.
void gather_data(const std::vector< dof_id_type > &ids, std::vector< datum > &local_ids) const
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
virtual PartitionerType type() const
virtual const Node & node_ref(const dof_id_type i) const
static void set_parent_processor_ids(MeshBase &mesh)
This function is called after partitioning to set the processor IDs for the inactive parent elements...
bool on_command_line(std::string arg)
void total_family_tree(std::vector< const Elem *> &family, bool reset=true) const
Same as the family_tree() member, but also adds any subactive descendants.
virtual void update_post_partitioning()
Recalculate any cached data after elements and nodes have been repartitioned.
processor_id_type processor_id() const
virtual void redistribute()
Redistribute elements between processors.
processor_id_type processor_id() const
std::vector< std::vector< dof_id_type > > _dual_graph
A dual graph corresponds to the mesh, and it is typically used in paritioner.
unsigned int & set_n_partitions()
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
std::vector< dof_id_type > _n_active_elem_on_proc
The number of active elements on each processor.
SyncLocalIDs(map_type &_id_map)