21 #include "libmesh/metis_partitioner.h"    23 #include "libmesh/libmesh_config.h"    24 #include "libmesh/elem.h"    25 #include "libmesh/enum_partitioner_type.h"    26 #include "libmesh/error_vector.h"    27 #include "libmesh/libmesh_logging.h"    28 #include "libmesh/mesh_base.h"    29 #include "libmesh/mesh_communication.h"    30 #include "libmesh/mesh_tools.h"    31 #include "libmesh/metis_csr_graph.h"    32 #include "libmesh/parallel.h"    33 #include "libmesh/utility.h"    34 #include "libmesh/vectormap.h"    36 #ifdef LIBMESH_HAVE_METIS    43 #     include "libmesh/ignore_warnings.h"    45 #     include "libmesh/restore_warnings.h"    49 #  include "libmesh/sfc_partitioner.h"    55 #include <unordered_map>    72                                        unsigned int n_pieces)
    84   libmesh_assert_greater (n_pieces, 0);
    87   if (!
mesh.is_serial())
    89       libMesh::out << 
"WARNING: Forced to gather a distributed mesh for METIS" << std::endl;
    94 #ifndef LIBMESH_HAVE_METIS    97   libMesh::out << 
"ERROR: The library has been built without"    << std::endl
    98                << 
"Metis support.  Using a space-filling curve"  << std::endl
    99                << 
"partitioner instead!"                         << std::endl;);
   107   LOG_SCOPE(
"partition_range()", 
"MetisPartitioner");
   118   global_index_map.reserve (n_range_elem);
   121     std::vector<dof_id_type> global_index;
   125                                              beg, end, global_index);
   127     libmesh_assert_equal_to (global_index.size(), n_range_elem);
   131 #ifdef LIBMESH_ENABLE_UNIQUE_ID   133     for (
const auto & elem : 
as_range(beg, end))
   134       global_index_map.emplace(elem->id(), global_index[cnt++]);
   141     std::unordered_map<dof_id_type, std::vector<dof_id_type>>
   142       global_index_inverses;
   143     bool found_duplicate_indices = 
false;
   146         for (
const auto & elem : 
as_range(beg, end))
   148             auto & vec = global_index_inverses[global_index[cnt++]];
   150               found_duplicate_indices = 
true;
   151             vec.push_back(elem->id());
   158     if (found_duplicate_indices)
   160         const std::map<dof_id_type, std::vector<dof_id_type>>
   161           sorted_inverses(global_index_inverses.begin(),
   162                           global_index_inverses.end());
   163         std::size_t new_global_index=0;
   164         for (
const auto & [index, elem_ids] : sorted_inverses)
   166             global_index_map.emplace(elem_id, new_global_index++);
   171         for (
const auto & elem : 
as_range(beg, end))
   172           global_index_map.emplace(elem->id(), global_index[cnt++]);
   176     libmesh_assert_equal_to (global_index_map.size(), n_range_elem);
   179     std::unordered_set<dof_id_type> distinct_global_indices, distinct_ids;
   180     for (
const auto & [elem_id, index] : global_index_map)
   182         distinct_ids.insert(elem_id);
   183         distinct_global_indices.insert(index);
   185     libmesh_assert_equal_to (distinct_global_indices.size(), n_range_elem);
   186     libmesh_assert_equal_to (distinct_ids.size(), n_range_elem);
   194   typedef std::unordered_multimap<const Elem *, const Elem *> map_type;
   195   map_type interior_to_boundary_map;
   197   for (
const auto & elem : 
as_range(beg, end))
   201       if ((elem->dim() >= LIBMESH_DIM) ||
   202           !elem->interior_parent())
   206       std::set<Elem *> neighbor_set;
   207       elem->find_interior_neighbors(neighbor_set);
   209       for (
auto & neighbor : neighbor_set)
   210         interior_to_boundary_map.emplace(neighbor, elem);
   214   std::vector<Metis::idx_t> part(n_range_elem);
   218   if (
mesh.processor_id() == 0)
   222       std::vector<Metis::idx_t> vwgt(n_range_elem);
   225         n = 
static_cast<Metis::idx_t
>(n_range_elem),   
   228         nparts  = static_cast<Metis::idx_t>(n_pieces), 
   237       csr_graph.
offsets.resize(n_range_elem + 1, 0);
   245 #ifdef LIBMESH_ENABLE_AMR   246         std::vector<const Elem *> neighbors_offspring;
   250         std::size_t graph_size=0;
   255         for (
const auto & elem : 
as_range(beg, end))
   258               global_index_map[elem->id()];
   260             libmesh_assert_less (elem_global_index, vwgt.size());
   272                   vwgt[elem_global_index] = 50;
   274                   vwgt[elem_global_index] = elem->n_nodes();
   277               vwgt[elem_global_index] = 
static_cast<Metis::idx_t
>((*_weights)[elem->id()]);
   279             unsigned int num_neighbors = 0;
   283             for (
auto neighbor : elem->neighbor_ptr_range())
   285                 if (neighbor != 
nullptr)
   290                     if (neighbor->active() && !global_index_map.count(neighbor->id()))
   295                     if (neighbor->active())
   298 #ifdef LIBMESH_ENABLE_AMR   307                         const unsigned int ns =
   308                           neighbor->which_neighbor_am_i (elem);
   309                         libmesh_assert_less (ns, neighbor->n_neighbors());
   321                         neighbor->active_family_tree (neighbors_offspring);
   326                         for (
const auto & child : neighbors_offspring)
   329                             if (!global_index_map.count(child->id()))
   335                             if (child->neighbor_ptr(ns) == elem)
   349             if ((elem->dim() < LIBMESH_DIM) && elem->interior_parent())
   352                 std::set<const Elem *> neighbor_set;
   353                 elem->find_interior_neighbors(neighbor_set);
   355                 num_neighbors += cast_int<unsigned int>(neighbor_set.size());
   359             typedef map_type::iterator map_it_type;
   360             std::pair<map_it_type, map_it_type>
   361               bounds = interior_to_boundary_map.equal_range(elem);
   362             num_neighbors += cast_int<unsigned int>
   374             graph_size += num_neighbors;
   381         for (
const auto & elem : 
as_range(beg, end))
   384               global_index_map[elem->id()];
   386             unsigned int connection=0;
   390             for (
auto neighbor : elem->neighbor_ptr_range())
   392                 if (neighbor != 
nullptr)
   397                     if (neighbor->active() && !global_index_map.count(neighbor->id()))
   402                     if (neighbor->active())
   403                       csr_graph(elem_global_index, connection++) = global_index_map[neighbor->id()];
   405 #ifdef LIBMESH_ENABLE_AMR   414                         const unsigned int ns =
   415                           neighbor->which_neighbor_am_i (elem);
   416                         libmesh_assert_less (ns, neighbor->n_neighbors());
   420                         neighbor->active_family_tree (neighbors_offspring);
   425                         for (
const auto & child : neighbors_offspring)
   428                             if (!global_index_map.count(child->id()))
   434                             if (child->neighbor_ptr(ns) == elem)
   438                                 csr_graph(elem_global_index, connection++) = global_index_map[child->id()];
   448             if ((elem->dim() < LIBMESH_DIM) &&
   449                 elem->interior_parent())
   452                 std::set<const Elem *> neighbor_set;
   453                 elem->find_interior_neighbors(neighbor_set);
   455                 for (
const Elem * neighbor : neighbor_set)
   463                     const Elem * queried_elem = 
mesh.query_elem_ptr(neighbor->id());
   467                     if (queried_elem && queried_elem == neighbor)
   468                       csr_graph(elem_global_index, connection++) =
   469                         libmesh_map_find(global_index_map, neighbor->id());
   474             for (
const auto & pr : 
as_range(interior_to_boundary_map.equal_range(elem)))
   476                 const Elem * neighbor = pr.second;
   477                 csr_graph(elem_global_index, connection++) =
   478                   global_index_map[neighbor->
id()];
   484         libmesh_assert_equal_to (csr_graph.
vals.size(),
   485                                  std::max(graph_size, std::size_t(1)));
   488       Metis::idx_t ncon = 1;
   494         Metis::METIS_PartGraphRecursive(&n,
   497                                         csr_graph.
vals.data(),
   510         Metis::METIS_PartGraphKway(&n,
   513                                    csr_graph.
vals.data(),
   527   mesh.comm().broadcast(part);
   532   for (
auto & elem : 
as_range(beg, end))
   537         global_index_map[elem->id()];
   539       libmesh_assert_less (elem_global_index, part.size());
   543       elem->processor_id() = elem_procid;
   551                                       const unsigned int n_pieces)
   554                         mesh.active_elements_begin(),
   555                         mesh.active_elements_end(),
 virtual void partition_range(MeshBase &mesh, MeshBase::element_iterator it, MeshBase::element_iterator end, const unsigned int n) override
Called by the SubdomainPartitioner to partition elements in the range (it, end). 
The definition of the element_iterator struct. 
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...
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...
This utility class provides a convenient implementation for building the compressed-row-storage graph...
virtual void partition_range(MeshBase &mesh, MeshBase::element_iterator it, MeshBase::element_iterator end, const unsigned int n) override
Called by the SubdomainPartitioner to partition elements in the range (it, end). 
This is the base class from which all geometric element types are derived. 
The libMesh namespace provides an interface to certain functionality in the library. 
Real distance(const Point &p)
uint8_t processor_id_type
This is the MeshBase class. 
ErrorVector * _weights
The weights that might be used for partitioning. 
std::vector< IndexType > offsets
PartitionerType
Defines an enum for mesh partitioner types. 
This is the MeshCommunication class. 
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
Helper function that allows us to treat a homogenous pair as a range. 
std::vector< IndexType > vals
virtual void _do_partition(MeshBase &mesh, const unsigned int n) override
Partition the MeshBase into n subdomains. 
The SFCPartitioner uses a Hilbert or Morton-ordered space filling curve to partition the elements...
void prepare_for_use()
Replaces the entries in the offsets vector with their partial sums and resizes the val vector accordi...
void prep_n_nonzeros(const libMesh::dof_id_type row, const libMesh::dof_id_type n_nonzeros_in)
Sets the number of non-zero values in the given row. 
  This vectormap templated class is intended to provide the performance characteristics of a sorted s...
virtual PartitionerType type() const override