31 #ifdef LIBMESH_HAVE_PETSC 60 libmesh_parallel_only(
mesh.comm());
69 const unsigned int n_parts =
70 static_cast<unsigned int> 74 mesh.set_n_partitions()=n_parts;
100 MeshTools::libmesh_assert_valid_procids<Elem>(
mesh);
107 MeshTools::libmesh_assert_valid_procids<Elem>(
mesh);
112 mesh.update_post_partitioning();
125 const unsigned int n)
129 const unsigned int n_parts =
130 static_cast<unsigned int> 134 mesh.set_n_partitions()=n_parts;
162 mesh.elements_end());
175 LOG_SCOPE(
"single_partition_range()",
"Partitioner");
179 elem->processor_id() = 0;
182 for (
unsigned int n=0; n<elem->n_nodes(); ++n)
183 elem->node_ptr(n)->processor_id() = 0;
195 const unsigned int n_subdomains)
204 if (!n_unpartitioned_elements)
208 std::vector<dof_id_type> subdomain_bounds(
mesh.n_processors());
215 if (pid < n_subdomains)
217 tgt_subdomain_size = n_unpartitioned_elements/n_subdomains;
219 if (pid < n_unpartitioned_elements%n_subdomains)
220 tgt_subdomain_size++;
226 subdomain_bounds[0] = tgt_subdomain_size;
228 subdomain_bounds[pid] = subdomain_bounds[pid-1] + tgt_subdomain_size;
231 libmesh_assert_equal_to (subdomain_bounds.back(), n_unpartitioned_elements);
235 std::vector<dof_id_type> global_indices;
246 libmesh_assert_less (cnt, global_indices.size());
248 global_indices[cnt++];
250 libmesh_assert_less (global_index, subdomain_bounds.back());
251 libmesh_assert_less (global_index, n_unpartitioned_elements);
254 cast_int<processor_id_type>
255 (std::distance(subdomain_bounds.begin(),
256 std::upper_bound(subdomain_bounds.begin(),
257 subdomain_bounds.end(),
259 libmesh_assert_less (subdomain_id, n_subdomains);
261 elem->processor_id() = subdomain_id;
273 LOG_SCOPE(
"set_parent_processor_ids()",
"Partitioner");
275 #ifdef LIBMESH_ENABLE_AMR 285 if (
mesh.is_serial())
287 for (
auto & elem :
mesh.active_element_ptr_range())
290 std::vector<const Elem *> subactive_family;
291 elem->total_family_tree(subactive_family);
292 for (std::size_t i = 0; i != subactive_family.size(); ++i)
293 const_cast<Elem *>(subactive_family[i])->processor_id() = elem->processor_id();
307 libmesh_assert(!child.is_remote());
310 child.processor_id());
312 parent = parent->
parent();
325 for (
auto & child :
mesh.active_element_ptr_range())
327 std::vector<const Elem *> subactive_family;
329 for (std::size_t i = 0; i != subactive_family.size(); ++i)
330 const_cast<Elem *>(subactive_family[i])->processor_id() = child->processor_id();
342 libmesh_parallel_only(
mesh.comm());
344 mesh.unpartitioned_elements_end()) == 0);
348 std::vector<processor_id_type>
352 for (
dof_id_type blk=0, last_elem_id=0; last_elem_id<max_elem_id; blk++)
359 std::fill (parent_processor_ids.begin(),
360 parent_processor_ids.end(),
364 bool have_parent_in_block =
false;
366 for (
auto & parent :
as_range(
mesh.ancestor_elements_begin(),
367 mesh.ancestor_elements_end()))
370 libmesh_assert_less (parent_idx, max_elem_id);
372 if ((parent_idx >= first_elem_id) &&
373 (parent_idx < last_elem_id))
375 have_parent_in_block =
true;
378 std::vector<const Elem *> active_family;
379 parent->active_family_tree(active_family);
380 for (std::size_t i = 0; i != active_family.size(); ++i)
381 parent_pid =
std::min (parent_pid, active_family[i]->processor_id());
383 const dof_id_type packed_idx = parent_idx - first_elem_id;
384 libmesh_assert_less (packed_idx, parent_processor_ids.size());
386 parent_processor_ids[packed_idx] = parent_pid;
391 mesh.comm().min (parent_processor_ids);
394 if (have_parent_in_block)
395 for (
auto & parent :
as_range(
mesh.ancestor_elements_begin(),
396 mesh.ancestor_elements_end()))
400 if ((parent_idx >= first_elem_id) &&
401 (parent_idx < last_elem_id))
403 const dof_id_type packed_idx = parent_idx - first_elem_id;
404 libmesh_assert_less (packed_idx, parent_processor_ids.size());
407 parent_processor_ids[packed_idx];
411 parent->processor_id() = parent_pid;
417 #endif // LIBMESH_ENABLE_AMR 422 std::map<std::pair<processor_id_type, processor_id_type>, std::set<dof_id_type>> & processor_pair_to_nodes)
425 libmesh_parallel_only(
mesh.comm());
427 processor_pair_to_nodes.clear();
429 std::set<dof_id_type> mynodes;
430 std::set<dof_id_type> neighbor_nodes;
431 std::vector<dof_id_type> common_nodes;
434 for (
auto & elem :
mesh.active_element_ptr_range())
436 libmesh_assert(elem);
440 auto n_nodes = elem->n_nodes();
444 neighbor_nodes.clear();
445 common_nodes.clear();
447 for (
unsigned int inode = 0; inode <
n_nodes; inode++)
448 mynodes.insert(elem->node_id(inode));
450 for (
auto i : elem->side_index_range())
452 auto neigh = elem->neighbor_ptr(i);
453 if (neigh && !neigh->is_remote() && neigh->processor_id() != elem->processor_id())
455 neighbor_nodes.clear();
456 common_nodes.clear();
457 auto neigh_n_nodes = neigh->n_nodes();
458 for (
unsigned int inode = 0; inode < neigh_n_nodes; inode++)
459 neighbor_nodes.insert(neigh->node_id(inode));
461 std::set_intersection(mynodes.begin(), mynodes.end(),
462 neighbor_nodes.begin(), neighbor_nodes.end(),
463 std::back_inserter(common_nodes));
465 auto & map_set = processor_pair_to_nodes[std::make_pair(
std::min(elem->processor_id(), neigh->processor_id()),
466 std::max(elem->processor_id(), neigh->processor_id()))];
467 for (
auto global_node_id : common_nodes)
468 map_set.insert(global_node_id);
477 libmesh_parallel_only(
mesh.comm());
479 std::map<std::pair<processor_id_type, processor_id_type>, std::set<dof_id_type>> processor_pair_to_nodes;
483 for (
auto & pmap : processor_pair_to_nodes)
485 std::size_t n_own_nodes = pmap.second.size()/2, i = 0;
487 for (
auto it = pmap.second.begin(); it != pmap.second.end(); it++, i++)
489 auto & node =
mesh.node_ref(*it);
490 if (i <= n_own_nodes)
491 node.processor_id() = pmap.first.first;
493 node.processor_id() = pmap.first.second;
501 libmesh_parallel_only(
mesh.comm());
503 std::map<std::pair<processor_id_type, processor_id_type>, std::set<dof_id_type>> processor_pair_to_nodes;
507 std::unordered_map<dof_id_type, std::vector<const Elem *>> nodes_to_elem_map;
511 std::vector<const Node *> neighbors;
512 std::set<dof_id_type> neighbors_order;
513 std::vector<dof_id_type> common_nodes;
514 std::queue<dof_id_type> nodes_queue;
515 std::set<dof_id_type> visted_nodes;
517 for (
auto & pmap : processor_pair_to_nodes)
519 std::size_t n_own_nodes = pmap.second.size()/2;
522 for (
auto it = pmap.second.begin(); it != pmap.second.end(); it++)
523 mesh.node_ref(*it).processor_id() = pmap.first.second;
525 visted_nodes.clear();
526 for (
auto it = pmap.second.begin(); it != pmap.second.end(); it++)
528 mesh.node_ref(*it).processor_id() = pmap.first.second;
530 if (visted_nodes.find(*it) != visted_nodes.end())
534 nodes_queue.push(*it);
535 visted_nodes.insert(*it);
536 if (visted_nodes.size() >= n_own_nodes)
540 while (!nodes_queue.empty())
542 auto & node =
mesh.node_ref(nodes_queue.front());
547 neighbors_order.clear();
548 for (
auto & neighbor : neighbors)
549 neighbors_order.insert(neighbor->id());
551 common_nodes.clear();
552 std::set_intersection(pmap.second.begin(), pmap.second.end(),
553 neighbors_order.begin(), neighbors_order.end(),
554 std::back_inserter(common_nodes));
556 for (
auto c_node : common_nodes)
557 if (visted_nodes.find(c_node) == visted_nodes.end())
559 nodes_queue.push(c_node);
560 visted_nodes.insert(c_node);
561 if (visted_nodes.size() >= n_own_nodes)
565 if (visted_nodes.size() >= n_own_nodes)
570 for (
auto node : visted_nodes)
571 mesh.node_ref(node).processor_id() = pmap.first.first;
580 libmesh_parallel_only(
mesh.comm());
582 #if LIBMESH_HAVE_PETSC 583 std::map<std::pair<processor_id_type, processor_id_type>, std::set<dof_id_type>> processor_pair_to_nodes;
587 std::vector<std::vector<const Elem *>> nodes_to_elem_map;
591 std::vector<const Node *> neighbors;
592 std::set<dof_id_type> neighbors_order;
593 std::vector<dof_id_type> common_nodes;
595 std::vector<dof_id_type> rows;
596 std::vector<dof_id_type> cols;
598 std::map<dof_id_type, dof_id_type> global_to_local;
600 for (
auto & pmap : processor_pair_to_nodes)
605 rows.resize(pmap.second.size()+1);
607 for (
auto it = pmap.second.begin(); it != pmap.second.end(); it++)
608 global_to_local[*it] = i++;
611 for (
auto it = pmap.second.begin(); it != pmap.second.end(); it++, i++)
613 auto & node =
mesh.node_ref(*it);
616 neighbors_order.clear();
617 for (
auto & neighbor : neighbors)
618 neighbors_order.insert(neighbor->id());
620 common_nodes.clear();
621 std::set_intersection(pmap.second.begin(), pmap.second.end(),
622 neighbors_order.begin(), neighbors_order.end(),
623 std::back_inserter(common_nodes));
625 rows[i+1] = rows[i] + cast_int<dof_id_type>(common_nodes.size());
627 for (
auto c_node : common_nodes)
628 cols.push_back(global_to_local[c_node]);
632 MatPartitioning part;
634 PetscInt local_size, rows_size, cols_size;
635 PetscInt *adj_i, *adj_j;
636 const PetscInt *indices;
637 PetscCalloc1(rows.size(), &adj_i);
638 PetscCalloc1(cols.size(), &adj_j);
639 rows_size = cast_int<PetscInt>(rows.size());
640 for (PetscInt ii=0; ii<rows_size; ii++)
641 adj_i[ii] = rows[ii];
643 cols_size = cast_int<PetscInt>(cols.size());
644 for (PetscInt ii=0; ii<cols_size; ii++)
645 adj_j[ii] = cols[ii];
647 const PetscInt sz = cast_int<PetscInt>(pmap.second.size());
648 MatCreateMPIAdj(PETSC_COMM_SELF, sz, sz, adj_i, adj_j,
nullptr,&adj);
649 MatPartitioningCreate(PETSC_COMM_SELF,&part);
650 MatPartitioningSetAdjacency(part,adj);
651 MatPartitioningSetNParts(part,2);
652 PetscObjectSetOptionsPrefix((PetscObject)part,
"balance_");
653 MatPartitioningSetFromOptions(part);
654 MatPartitioningApply(part,&is);
657 MatPartitioningDestroy(&part);
659 ISGetLocalSize(is, &local_size);
660 ISGetIndices(is, &indices);
662 for (
auto it = pmap.second.begin(); it != pmap.second.end(); it++, i++)
664 auto & node =
mesh.node_ref(*it);
666 node.processor_id() = pmap.first.second;
668 node.processor_id() = pmap.first.first;
670 ISRestoreIndices(is, &indices);
674 libmesh_error_msg(
"PETSc is required");
681 LOG_SCOPE(
"set_node_processor_ids()",
"Partitioner");
684 libmesh_parallel_only(
mesh.comm());
689 mesh.unpartitioned_elements_end()) == 0);
706 std::map<processor_id_type, std::vector<dof_id_type>>
710 std::vector<dof_id_type> ghost_nodes_from_proc(
mesh.n_processors(), 0);
712 for (
auto & node :
mesh.node_ptr_range())
714 libmesh_assert(node);
716 if (current_pid !=
mesh.processor_id() &&
719 libmesh_assert_less (current_pid, ghost_nodes_from_proc.size());
720 ghost_nodes_from_proc[current_pid]++;
727 if (ghost_nodes_from_proc[pid])
728 requested_node_ids[pid].reserve(ghost_nodes_from_proc[pid]);
732 for (
auto & node :
mesh.node_ptr_range())
734 libmesh_assert(node);
736 if (current_pid !=
mesh.processor_id() &&
739 libmesh_assert_less (requested_node_ids[current_pid].size(),
740 ghost_nodes_from_proc[current_pid]);
741 requested_node_ids[current_pid].push_back(node->id());
745 node->invalidate_processor_id();
749 for (
auto & elem :
mesh.active_element_ptr_range())
751 libmesh_assert(elem);
756 for (
unsigned int n=0; n<elem->n_nodes(); ++n)
758 Node & node = elem->node_ref(n);
764 bool load_balanced_nodes_linear =
767 if (load_balanced_nodes_linear)
770 bool load_balanced_nodes_bfs =
773 if (load_balanced_nodes_bfs)
776 bool load_balanced_nodes_petscpartition =
779 if (load_balanced_nodes_petscpartition)
784 for (
auto & elem :
as_range(
mesh.subactive_elements_begin(),
785 mesh.subactive_elements_end()))
787 libmesh_assert(elem);
791 for (
unsigned int n=0; n<elem->n_nodes(); ++n)
793 elem->node_ptr(n)->processor_id() = elem->processor_id();
800 for (
auto & elem :
as_range(
mesh.not_active_elements_begin(),
801 mesh.not_active_elements_end()))
803 libmesh_assert(elem);
807 for (
unsigned int n=0; n<elem->n_nodes(); ++n)
809 elem->node_ptr(n)->processor_id() = elem->processor_id();
821 auto gather_functor =
824 std::vector<processor_id_type> & new_pids)
826 const std::size_t ids_size = ids.size();
827 new_pids.resize(ids_size);
830 for (std::size_t i=0; i != ids_size; ++i)
832 Node & node =
mesh.node_ref(ids[i]);
840 new_pids[i] = new_pid;
844 auto action_functor =
847 const std::vector<dof_id_type> & ids,
848 const std::vector<processor_id_type> & new_pids)
850 const std::size_t ids_size = ids.size();
852 for (std::size_t i=0; i != ids_size; ++i)
854 Node & node =
mesh.node_ref(ids[i]);
870 (
mesh.comm(), requested_node_ids, gather_functor, action_functor, ex);
873 MeshTools::libmesh_assert_valid_procids<Node>(
mesh);
884 typedef std::unordered_map<dof_id_type, dof_id_type>
map_type;
891 std::vector<datum> & local_ids)
const 893 local_ids.resize(ids.size());
895 for (std::size_t i=0, imax = ids.size(); i != imax; ++i)
896 local_ids[i] =
id_map[ids[i]];
900 const std::vector<datum> & local_ids)
902 for (std::size_t i=0, imax = local_ids.size(); i != imax; ++i)
903 id_map[ids[i]] = local_ids[i];
926 mesh.active_local_elements_begin(),
927 mesh.active_local_elements_end(),
933 (
mesh.comm(),
mesh.active_elements_begin(),
mesh.active_elements_end(), sync);
938 for (
const auto & elem :
as_range(
mesh.active_pid_elements_begin(pid),
939 mesh.active_pid_elements_end(pid)))
952 LOG_SCOPE(
"build_graph()",
"ParmetisPartitioner");
959 typedef std::unordered_multimap<const Elem *, const Elem *> map_type;
960 map_type interior_to_boundary_map;
962 for (
const auto & elem :
mesh.active_element_ptr_range())
966 if ((elem->dim() >= LIBMESH_DIM) ||
967 !elem->interior_parent())
971 std::set<const Elem *> neighbor_set;
972 elem->find_interior_neighbors(neighbor_set);
974 for (
const auto & neighbor : neighbor_set)
975 interior_to_boundary_map.insert(std::make_pair(neighbor, elem));
978 #ifdef LIBMESH_ENABLE_AMR 979 std::vector<const Elem *> neighbors_offspring;
996 for (
const auto & elem :
mesh.active_local_element_ptr_range())
1003 global_index_by_pid - first_local_elem;
1004 libmesh_assert_less (local_index, n_active_local_elem);
1006 std::vector<dof_id_type> & graph_row =
_dual_graph[local_index];
1013 for (
auto neighbor : elem->neighbor_ptr_range())
1015 if (neighbor !=
nullptr)
1019 if (neighbor->active())
1025 graph_row.push_back(neighbor_global_index_by_pid);
1028 #ifdef LIBMESH_ENABLE_AMR 1037 const unsigned int ns =
1038 neighbor->which_neighbor_am_i (elem);
1039 libmesh_assert_less (ns, neighbor->n_neighbors());
1052 neighbor->active_family_tree (neighbors_offspring);
1057 for (std::size_t nc=0; nc<neighbors_offspring.size(); nc++)
1059 const Elem * child =
1060 neighbors_offspring[nc];
1067 libmesh_assert (child->
active());
1072 graph_row.push_back(child_global_index_by_pid);
1083 if ((elem->dim() < LIBMESH_DIM) &&
1084 elem->interior_parent())
1087 std::set<const Elem *> neighbor_set;
1088 elem->find_interior_neighbors(neighbor_set);
1090 for (
const auto & neighbor : neighbor_set)
1095 graph_row.push_back(neighbor_global_index_by_pid);
1100 for (
const auto & pr :
as_range(interior_to_boundary_map.equal_range(elem)))
1102 const Elem * neighbor = pr.second;
1107 graph_row.push_back(neighbor_global_index_by_pid);
1115 LOG_SCOPE(
"assign_partitioning()",
"ParmetisPartitioner");
1118 libmesh_parallel_only(
mesh.comm());
1128 std::map<processor_id_type, std::vector<dof_id_type>>
1133 std::map<processor_id_type, std::vector<processor_id_type>>
1136 for (
auto & elem :
mesh.active_element_ptr_range())
1141 requested_ids[elem->processor_id()].push_back(elem->id());
1144 auto gather_functor =
1149 n_active_local_elem,
1153 std::vector<processor_id_type> &
data)
1155 const std::size_t ids_size = ids.size();
1156 data.resize(ids.size());
1158 for (std::size_t i=0; i != ids_size; i++)
1168 global_index_by_pid - first_local_elem;
1170 libmesh_assert_less (local_index, parts.size());
1171 libmesh_assert_less (local_index, n_active_local_elem);
1174 cast_int<processor_id_type>(parts[local_index]);
1176 libmesh_assert_less (elem_procid,
mesh.n_partitions());
1178 data[i] = elem_procid;
1182 auto action_functor =
1185 const std::vector<dof_id_type> &,
1186 const std::vector<processor_id_type> & new_procids)
1188 filled_request[pid] = new_procids;
1194 (
mesh.comm(), requested_ids, gather_functor, action_functor, ex);
1200 std::vector<unsigned int> counters(
mesh.n_processors(), 0);
1201 for (
auto & elem :
mesh.active_element_ptr_range())
1205 libmesh_assert_less (counters[current_pid], requested_ids[current_pid].size());
1208 filled_request[current_pid][counters[current_pid]++];
1210 libmesh_assert_less (elem_procid,
mesh.n_partitions());
1211 elem->processor_id() = elem_procid;
void find_global_indices(const Parallel::Communicator &communicator, const libMesh::BoundingBox &, const ForwardIterator &, const ForwardIterator &, std::vector< dof_id_type > &) const
void single_partition(MeshBase &mesh)
const Elem * parent() const
static void set_interface_node_processor_ids_petscpartitioner(MeshBase &mesh)
A geometric point in (x,y,z) space associated with a DOF.
std::unordered_map< dof_id_type, dof_id_type > _global_index_by_pid_map
static void set_interface_node_processor_ids_BFS(MeshBase &mesh)
static void set_node_processor_ids(MeshBase &mesh)
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)
The base class for all geometric element types.
uint8_t processor_id_type
void assign_partitioning(const MeshBase &mesh, const std::vector< dof_id_type > &parts)
virtual void build_graph(const MeshBase &mesh)
long double max(long double a, double b)
void total_family_tree(std::vector< const Elem *> &active_family, const bool reset=true) const
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
std::vector< Elem * > _local_id_to_elem
SimpleRange< ChildRefIter > child_ref_range()
virtual void _do_repartition(MeshBase &mesh, const unsigned int n)
virtual element_iterator elements_begin()=0
void repartition(MeshBase &mesh, const unsigned int n)
void libmesh_ignore(const Args &...)
const dof_id_type n_nodes
void single_partition_range(MeshBase::element_iterator it, MeshBase::element_iterator end)
void pull_parallel_vector_data(const Communicator &comm, const MapToVectors &queries, RequestContainer &reqs, GatherFunctor &gather_data, ActionFunctor &act_on_data, const datum *example)
static const processor_id_type invalid_processor_id
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)
SimpleRange< I > as_range(const std::pair< I, I > &p)
void find_local_indices(const libMesh::BoundingBox &, const ForwardIterator &, const ForwardIterator &, std::unordered_map< dof_id_type, dof_id_type > &) const
virtual void _find_global_index_by_pid_map(const MeshBase &mesh)
void sync_dofobject_data_by_id(const Communicator &comm, const Iterator &range_begin, const Iterator &range_end, SyncFunctor &sync)
void invalidate_processor_id()
virtual void _do_partition(MeshBase &mesh, const unsigned int n)=0
static void partition_unpartitioned_elements(MeshBase &mesh)
const Elem * neighbor_ptr(unsigned int i) const
static const dof_id_type communication_blocksize
virtual void partition(MeshBase &mesh, const unsigned int n)
void gather_data(const std::vector< dof_id_type > &ids, std::vector< datum > &local_ids) const
static void set_parent_processor_ids(MeshBase &mesh)
bool on_command_line(std::string arg)
processor_id_type processor_id() const
long double min(long double a, double b)
std::vector< std::vector< dof_id_type > > _dual_graph
std::vector< dof_id_type > _n_active_elem_on_proc
SyncLocalIDs(map_type &_id_map)