6#include <kernel/geometry/parti_zoltan.hpp>
12using namespace Geometry;
27extern "C" int feat_zoltan_num_elems(
void* data,
int* ierr)
30 const Adjacency::Graph& grp =
reinterpret_cast<const PartiZoltan::Hypergraph*
>(data)->sub_graph;
31 return int(grp.get_num_nodes_domain());
45extern "C" void feat_zoltan_elem_list(
void* data,
int size_gid,
int size_lid,
46 ZOLTAN_ID_PTR global_id, ZOLTAN_ID_PTR DOXY(local_id),
int wgt_dim,
float* obj_wgts,
int* ierr)
51 const PartiZoltan::Hypergraph& hyg = *
reinterpret_cast<const PartiZoltan::Hypergraph*
>(data);
52 const Index n = hyg.sub_graph.get_num_nodes_domain();
53 for(
Index i(0); i < n; ++i)
54 global_id[i] = ZOLTAN_ID_TYPE(hyg.first_elem + i);
57 for(
Index i(0); i < n; ++i)
58 obj_wgts[i] = hyg.weights[i];
72extern "C" void feat_zoltan_hypergraph_size(
void* data,
int* num_lists,
int* num_nonzeroes,
int* format,
int* ierr)
75 const Adjacency::Graph& grp =
reinterpret_cast<const PartiZoltan::Hypergraph*
>(data)->sub_graph;
76 *num_lists = int(grp.get_num_nodes_domain());
78 *format = ZOLTAN_COMPRESSED_EDGE;
91extern "C" void feat_zoltan_hypergraph_data(
void* data,
int size_gid,
int num_edges,
int num_nonzeroes,
92 int format, ZOLTAN_ID_PTR edgeGID,
int* vtxPtr, ZOLTAN_ID_PTR vtxGID,
int* ierr)
94 const Adjacency::Graph& grp =
reinterpret_cast<const PartiZoltan::Hypergraph*
>(data)->sub_graph;
96 XASSERT(num_edges ==
int(grp.get_num_nodes_domain()));
98 XASSERT(format == ZOLTAN_COMPRESSED_EDGE);
104 for(
int i(0); i < num_edges; ++i)
106 edgeGID[i] = ZOLTAN_ID_TYPE(i);
107 vtxPtr[i] = int(dom_ptr[i]);
111 for(
int i(0); i < num_nonzeroes; ++i)
113 vtxGID[i] = ZOLTAN_ID_TYPE(img_idx[i]);
124 _zoltan_comm(Dist::Comm::null()),
125 _max_procs(max_procs),
126 _min_elems(min_elems),
135 PartiZoltan::~PartiZoltan()
139 Zoltan_Destroy(
reinterpret_cast<Zoltan_Struct**
>(&_zz));
144 bool PartiZoltan::execute(
const Adjacency::Graph& faces_at_elem,
const Index num_parts,
const std::vector<Real>& weights)
147 this->_num_parts = num_parts;
148 this->_num_elems = faces_at_elem.get_num_nodes_domain();
151 int num_procs = Math::max(1,
int(faces_at_elem.get_num_nodes_domain() / _min_elems));
153 Math::mini(num_procs, _max_procs);
154 Math::mini(num_procs,
int(num_parts));
155 Math::mini(num_procs, _comm.size());
158 if(num_procs < _comm.size())
159 _zoltan_comm = _comm.comm_create_range_incl(num_procs);
161 _zoltan_comm = _comm.comm_dup();
165 const int z_size = _zoltan_comm.size();
168 XASSERTM(
Index(z_size) <= num_parts,
"thou shall not create less partitions than thou hast ranks");
176 this->_create_hypergraph(faces_at_elem, weights);
179 is_ok = this->_apply_zoltan();
183 return this->_broadcast_coloring(is_ok);
186 void PartiZoltan::_create_hypergraph(
const Adjacency::Graph& faces_at_elem,
const std::vector<Real>& weights)
189 const Index num_elems = faces_at_elem.get_num_nodes_domain();
190 const Index num_faces = faces_at_elem.get_num_nodes_image();
193 const int z_rank = _zoltan_comm.rank();
194 const int z_size = _zoltan_comm.size();
202 Index my_num_elems = end_elem - first_elem;
208 const Index first_ptr = dom_ptr[first_elem];
209 const Index my_num_idx = dom_ptr[end_elem] - first_ptr;
212 Index* my_dom_ptr = faces_at_my_elem.get_domain_ptr();
213 Index* my_img_idx = faces_at_my_elem.get_image_idx();
214 for(
Index i(0); i <= my_num_elems; ++i)
215 my_dom_ptr[i] = dom_ptr[first_elem + i] - first_ptr;
216 for(
Index i(0); i < my_num_idx; ++i)
217 my_img_idx[i] = img_idx[first_ptr + i];
220 Adjacency::Graph elems_at_faces(Adjacency::RenderType::transpose, faces_at_elem);
223 this->_hypergraph.first_elem = first_elem;
224 this->_hypergraph.sub_graph =
Adjacency::Graph(Adjacency::RenderType::injectify_sorted, faces_at_my_elem, elems_at_faces);
229 XASSERT(end_elem <= weights.size());
230 this->_hypergraph.weights.resize(my_num_elems);
231 for(
Index i(0); i < my_num_elems; ++i)
232 this->_hypergraph.weights[i] =
float(weights[first_elem + i]);
236 bool PartiZoltan::_apply_zoltan()
239 Zoltan_Struct* zz = Zoltan_Create(_zoltan_comm.mpi_comm());
243 Zoltan_Set_Param(zz,
"DEBUG_LEVEL",
"0");
244 Zoltan_Set_Param(zz,
"LB_METHOD",
"HYPERGRAPH");
245 Zoltan_Set_Param(zz,
"HYPERGRAPH_PACKAGE",
"PHG");
246 Zoltan_Set_Param(zz,
"LB_APPROACH",
"PARTITION");
247 Zoltan_Set_Param(zz,
"NUM_GID_ENTRIES",
"1");
248 Zoltan_Set_Param(zz,
"NUM_LID_ENTRIES",
"0");
249 Zoltan_Set_Param(zz,
"RETURN_LISTS",
"PARTS");
250 Zoltan_Set_Param(zz,
"NUM_GLOBAL_PARTS",
stringify(this->_num_parts).c_str());
251 Zoltan_Set_Param(zz,
"OBJ_WEIGHT_DIM", this->_hypergraph.weights.empty() ?
"0" :
"1");
252 Zoltan_Set_Param(zz,
"EDGE_WEIGHT_DIM",
"0");
254 Zoltan_Set_Param(zz,
"PHG_EDGE_SIZE_THRESHOLD",
"1.0");
257 Zoltan_Set_Num_Obj_Fn(zz, feat_zoltan_num_elems, &this->_hypergraph);
258 Zoltan_Set_Obj_List_Fn(zz, feat_zoltan_elem_list, &this->_hypergraph);
259 Zoltan_Set_HG_Size_CS_Fn(zz, feat_zoltan_hypergraph_size, &this->_hypergraph);
260 Zoltan_Set_HG_CS_Fn(zz, feat_zoltan_hypergraph_data, &this->_hypergraph);
262 int changes(0), num_gid_entries(0), num_lid_entries(0), num_import(0), num_export(0);
263 ZOLTAN_ID_PTR import_global_ids(
nullptr);
264 ZOLTAN_ID_PTR import_local_ids(
nullptr);
265 int* import_procs(
nullptr);
266 int* import_parts(
nullptr);
267 ZOLTAN_ID_PTR export_global_ids(
nullptr);
268 ZOLTAN_ID_PTR export_local_ids(
nullptr);
269 int* export_procs(
nullptr);
270 int* export_parts(
nullptr);
272 int rtn = Zoltan_LB_Partition(zz, &changes, &num_gid_entries, &num_lid_entries,
273 &num_import, &import_global_ids, &import_local_ids, &import_procs, &import_parts,
274 &num_export, &export_global_ids, &export_local_ids, &export_procs, &export_parts);
277 bool gather_ok =
true;
279 gather_ok = this->_gather_coloring(num_export, export_parts);
281 Zoltan_LB_Free_Part(&import_global_ids, &import_local_ids, &import_procs, &import_parts);
282 Zoltan_LB_Free_Part(&export_global_ids, &export_local_ids, &export_procs, &export_parts);
287 return gather_ok && (rtn == ZOLTAN_OK);
290 bool PartiZoltan::_gather_coloring(
const int num_export,
const int* export_parts)
293 const Index z_rank =
Index(_zoltan_comm.rank());
294 const Index z_size =
Index(_zoltan_comm.size());
298 _zoltan_comm.allreduce(&max_export, &max_export, 1u, Dist::op_max);
302 std::vector<int> send_buf(max_export);
303 send_buf[0] = num_export;
305 send_buf[i+1] = export_parts[i];
308 std::vector<int> recv_buf(z_rank == 0 ? max_export * z_size :
Index(0));
309 _zoltan_comm.gather(send_buf.data(), max_export, recv_buf.data(), max_export, 0);
317 for(
Index i(0); i < z_size; ++i)
318 num_elems +=
Index(recv_buf[i*max_export]);
322 Index* col = this->_coloring.get_coloring();
325 for(
Index i(0), k(0); i < z_size; ++i)
327 Index off = i*max_export;
329 for(
Index j(1); j <= n; ++j, ++k)
330 col[k] =
Index(recv_buf[off+j]);
334 std::vector<int> color_counts(this->_num_parts, 0);
335 for(
Index i(0); i < this->_num_elems; ++i)
336 ++color_counts[col[i]];
339 for(
Index i(0); i < this->_num_parts; ++i)
341 if(color_counts[i] == 0)
349 bool PartiZoltan::_broadcast_coloring(
bool zoltan_ok)
353 int was_ok(zoltan_ok ? 0 : 1), was_all_ok(0);
354 this->_comm.allreduce(&was_ok, &was_all_ok, std::size_t(1), Dist::op_sum);
359 if(this->_comm.rank() > 0)
363 this->_comm.bcast(this->_coloring.get_coloring(), this->_num_elems, 0);
374void zoltan_did_not_make_it_to_the_feat_parti() {}
#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.
Index get_num_indices() const
Returns the total number indices.
PartiZoltan(const Dist::Comm &comm, Index min_elems=1000u, int max_procs=1000)
Constructor.
String stringify(const T_ &item)
Converts an item into a String.
std::uint64_t Index
Index data type.