6#include <kernel/geometry/parti_parmetis.hpp> 
    8#ifdef FEAT_HAVE_PARMETIS 
   12using namespace Geometry;
 
   20      _sub_comm(Dist::Comm::null()),
 
   21      _max_procs(max_procs),
 
   22      _min_elems(min_elems),
 
   36    PartiParMETIS::~PartiParMETIS()
 
   43      this->_num_parts = num_parts;
 
   44      this->_num_elems = faces_at_elem.get_num_nodes_domain();
 
   47      int num_procs = Math::max(1, 
int(faces_at_elem.get_num_nodes_domain() / _min_elems));
 
   49        Math::mini(num_procs, _max_procs);
 
   50      Math::mini(num_procs, 
int(num_parts));
 
   51      Math::mini(num_procs, _comm.size());
 
   54      if(num_procs < _comm.size())
 
   55        _sub_comm = _comm.comm_create_range_incl(num_procs);
 
   57        _sub_comm = _comm.comm_dup();
 
   60      const int z_rank = _sub_comm.rank();
 
   61      const int z_size = _sub_comm.size();
 
   64      XASSERTM(
Index(z_size) <= num_parts, 
"thou shall not create less partitions than thou hast ranks");
 
   69        this->_first_elem = this->_num_local_elems = 
Index(0);
 
   74      const Index num_elems = faces_at_elem.get_num_nodes_domain();
 
   75      const Index num_faces = faces_at_elem.get_num_nodes_image();
 
   80      Index my_num_elems = end_elem - first_elem;
 
   86      const Index first_ptr = dom_ptr[first_elem];
 
   87      const Index my_num_idx = dom_ptr[end_elem] - first_ptr;
 
   90      Index* my_dom_ptr = faces_at_my_elem.get_domain_ptr();
 
   91      Index* my_img_idx = faces_at_my_elem.get_image_idx();
 
   92      for(
Index i(0); i <= my_num_elems; ++i)
 
   93        my_dom_ptr[i] = dom_ptr[first_elem + i] - first_ptr;
 
   94      for(
Index i(0); i < my_num_idx; ++i)
 
   95        my_img_idx[i] = img_idx[first_ptr + i];
 
   98      Adjacency::Graph elems_at_faces(Adjacency::RenderType::transpose, faces_at_elem);
 
  101      this->_first_elem = first_elem;
 
  102      this->_num_local_elems = my_num_elems;
 
  103      this->_subgraph = 
Adjacency::Graph(Adjacency::RenderType::injectify_sorted, faces_at_my_elem, elems_at_faces);
 
  104      this->_parts.resize(my_num_elems);
 
  107    bool PartiParMETIS::_execute()
 
  112      if(this->_sub_comm.size() > 0)
 
  115        is_ok = this->_apply_parmetis();
 
  119      return this->_broadcast_coloring(is_ok);
 
  122    bool PartiParMETIS::_apply_parmetis()
 
  125      idx_t wgtflag(0), numflag(0), ncon(1), edgecut(0);
 
  126      idx_t nparts = idx_t(_num_parts);
 
  127      idx_t ndims = idx_t(_midpoints.size() / _num_local_elems);
 
  128      std::vector<idx_t> options(4, 0);
 
  129      std::vector<real_t> tpwgts(_num_parts, real_t(1) / real_t(_num_parts));
 
  130      std::vector<real_t> ubvec(1, real_t(1.05));
 
  131      std::vector<idx_t> vwgt;
 
  132      std::vector<idx_t> part(_num_local_elems, 0);
 
  135      std::vector<real_t> xyz;
 
  136      if(!_midpoints.empty())
 
  138        xyz.resize(_midpoints.size());
 
  139        for(std::size_t i(0); i < _midpoints.size(); ++i)
 
  140          xyz[i] = real_t(_midpoints[i]);
 
  144      const int z_size = this->_sub_comm.size();
 
  145      std::vector<idx_t> vtxdist;
 
  146      for(
int i(0); i <= z_size; ++i)
 
  147        vtxdist.push_back(idx_t(_num_elems*i) / idx_t(z_size));
 
  150      std::vector<idx_t> xadj, adjncy;
 
  151      const Index nv = _subgraph.get_num_nodes_domain();
 
  152      const Index ne = _subgraph.get_num_indices();
 
  153      xadj.reserve(nv + 1u);
 
  154      adjncy.reserve(ne - nv);
 
  155      const Index* dom_ptr = _subgraph.get_domain_ptr();
 
  156      const Index* img_idx = _subgraph.get_image_idx();
 
  157      for(
Index i(0); i < _subgraph.get_num_nodes_domain(); ++i)
 
  159        xadj.push_back(idx_t(adjncy.size()));
 
  160        for(
Index k(dom_ptr[i]); k < dom_ptr[i+1]; ++k)
 
  162          if(img_idx[k] != _first_elem + i)
 
  163            adjncy.push_back(idx_t(img_idx[k]));
 
  166      xadj.push_back(idx_t(adjncy.size()));
 
  169      if(!this->_weights.empty())
 
  171        std::size_t n = this->_weights.size();
 
  182        for(std::size_t i(0); i < n; ++i)
 
  183          wsum += this->_weights[i];
 
  184        XASSERTM(wsum > 1e-3, 
"weight sum appears to be zero");
 
  187        Real scale = 1E+9 / wsum;
 
  188        for(std::size_t i(0); i < n; ++i)
 
  189          vwgt[i] = idx_t(scale * this->_weights[i]);
 
  193      int rtn = ParMETIS_V3_PartGeomKway(
 
  210        &_sub_comm.mpi_comm() 
 
  214      _parts.resize(_num_local_elems);
 
  215      for(
Index i(0); i < _num_local_elems; ++i)
 
  216        _parts[i] = 
Index(part[i]);
 
  219      return _gather_coloring() && (rtn == METIS_OK);
 
  222    bool PartiParMETIS::_gather_coloring()
 
  225      const int z_rank = _sub_comm.rank();
 
  229      Index max_local_elems(0);
 
  230      _sub_comm.allreduce(&this->_num_local_elems, &max_local_elems, 1u, Dist::op_max);
 
  231      max_local_elems += 1; 
 
  234      std::vector<Index> send_buf(max_local_elems);
 
  235      send_buf[0] = _num_local_elems;
 
  236      for(
Index i(0); i < _num_local_elems; ++i)
 
  237        send_buf[i+1] = this->_parts[i];
 
  240      std::vector<Index> recv_buf(z_rank == 0 ? max_local_elems * z_size : std::size_t(0));
 
  241      _sub_comm.gather(send_buf.data(), max_local_elems, recv_buf.data(), max_local_elems, 0);
 
  249      for(
Index i(0); i < z_size; ++i)
 
  250        num_elems += recv_buf[i*max_local_elems];
 
  254      Index* col = this->_coloring.get_coloring();
 
  257      for(
Index i(0), k(0); i < z_size; ++i)
 
  259        Index off = i*max_local_elems;
 
  260        Index n = recv_buf[off];
 
  261        for(
Index  j(1); j <= n; ++j, ++k)
 
  262          col[k] = recv_buf[off+j];
 
  266      std::vector<int> color_counts(this->_num_parts, 0);
 
  267      for(
Index i(0); i < this->_num_elems; ++i)
 
  268        ++color_counts[col[i]];
 
  271      for(
Index i(0); i < this->_num_parts; ++i)
 
  273        if(color_counts[i] == 0)
 
  281    bool PartiParMETIS::_broadcast_coloring(
bool metis_ok)
 
  285      int was_ok(metis_ok ? 0 : 1),  was_all_ok(0);
 
  286      this->_comm.allreduce(&was_ok, &was_all_ok, std::size_t(1), Dist::op_sum);
 
  291      if(this->_comm.rank() > 0)
 
  295      this->_comm.bcast(this->_coloring.get_coloring(), this->_num_elems, 0);
 
  307void parmetis_not_linked() {}
 
#define XASSERT(expr)
Assertion macro definition.
#define XASSERTM(expr, msg)
Assertion macro definition with custom message.
Coloring object implementation.
Adjacency Graph implementation.
Index * get_domain_ptr()
Returns the domain pointer array.
Index * get_image_idx()
Returns the image node index array.
PartiParMETIS(const Dist::Comm &comm, Index min_elems=1000u, int max_procs=1000)
Constructor.
double Real
Real data type.
std::uint64_t Index
Index data type.