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)*idx_t(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 Index* col = this->_coloring.get_coloring();
252 for(
Index i(0), k(0); i < z_size; ++i)
254 Index off = i*max_local_elems;
255 Index n = recv_buf[off];
256 for(
Index j(1); j <= n; ++j, ++k)
257 col[k] = recv_buf[off+j];
261 std::vector<int> color_counts(this->_num_parts, 0);
262 for(
Index i(0); i < this->_num_elems; ++i)
263 ++color_counts[col[i]];
266 for(
Index i(0); i < this->_num_parts; ++i)
268 if(color_counts[i] == 0)
276 bool PartiParMETIS::_broadcast_coloring(
bool metis_ok)
280 int was_ok(metis_ok ? 0 : 1), was_all_ok(0);
281 this->_comm.allreduce(&was_ok, &was_all_ok, std::size_t(1), Dist::op_sum);
286 if(this->_comm.rank() > 0)
290 this->_comm.bcast(this->_coloring.get_coloring(), this->_num_elems, 0);
302void 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.