45 #ifndef _ZOLTAN2_ALGPARMA_HPP_
46 #define _ZOLTAN2_ALGPARMA_HPP_
73 #ifndef HAVE_ZOLTAN2_PARMA
79 template <
typename Adapter>
86 const RCP<
const Comm<int> > &,
89 throw std::runtime_error(
90 "BUILD ERROR: ParMA requested but not compiled into Zoltan2.\n"
91 "Please set CMake flag Zoltan2_ENABLE_ParMA:BOOL=ON.");
98 #ifdef HAVE_ZOLTAN2_PARMA
102 #include <gmi_null.h>
104 #include <apfMesh2.h>
105 #include <apfNumbering.h>
108 #include <apfConvert.h>
109 #include <apfShape.h>
115 template <
typename Adapter>
116 class AlgParMA :
public Algorithm<Adapter>
121 typedef typename Adapter::lno_t
lno_t;
122 typedef typename Adapter::gno_t
gno_t;
123 typedef typename Adapter::scalar_t
scalar_t;
124 typedef typename Adapter::offset_t offset_t;
127 typedef typename Adapter::userCoord_t userCoord_t;
129 const RCP<const Environment> env;
130 const RCP<const Comm<int> > problemComm;
131 const RCP<const MeshAdapter<user_t> > adapter;
134 apf::Numbering* gids;
135 apf::Numbering* origin_part_ids;
136 std::map<gno_t, lno_t> mapping_elm_gids_index;
141 void setMPIComm(
const RCP<
const Comm<int> > &problemComm__) {
142 # ifdef HAVE_ZOLTAN2_MPI
143 mpicomm = Teuchos::getRawMpiComm(*problemComm__);
145 mpicomm = MPI_COMM_WORLD;
155 return apf::Mesh::VERTEX;
157 return apf::Mesh::EDGE;
161 return apf::Mesh::QUAD;
163 return apf::Mesh::TET;
165 return apf::Mesh::HEX;
166 else if (ttype==
PRISM)
171 throw std::runtime_error(
"APF does not support this topology type");
177 void setEntWeights(
int dim, apf::MeshTag* tag) {
179 for (
int i=0;i<m->getTagSize(tag);i++) {
180 apf::MeshIterator* itr = m->begin(dim);
181 apf::MeshEntity* ent;
184 if (i<adapter->getNumWeightsPerOf(etype))
185 adapter->getWeightsViewOf(etype,ws,stride,i);
187 while ((ent= m->iterate(itr))) {
190 w =
static_cast<double>(ws[j]);
191 m->setDoubleTag(ent,tag,&w);
199 apf::MeshTag* setWeights(
bool vtx,
bool edge,
bool face,
bool elm) {
202 num_ws = std::max(num_ws,adapter->getNumWeightsPerOf(
MESH_VERTEX));
204 num_ws = std::max(num_ws,adapter->getNumWeightsPerOf(
MESH_EDGE));
206 num_ws = std::max(num_ws,adapter->getNumWeightsPerOf(
MESH_FACE));
208 num_ws = std::max(num_ws,adapter->getNumWeightsPerOf(entityAPFtoZ2(m->getDimension())));
209 apf::MeshTag* tag = m->createDoubleTag(
"parma_weight",num_ws);
211 setEntWeights(0,tag);
213 setEntWeights(1,tag);
215 setEntWeights(2,tag);
217 setEntWeights(m->getDimension(),tag);
224 void constructElements(
const gno_t* conn,
lno_t nelem,
const offset_t* offsets,
227 apf::ModelEntity* interior = m->findModelEntity(m->getDimension(), 0);
228 for (
lno_t i = 0; i < nelem; ++i) {
229 apf::Mesh::Type etype = topologyZ2toAPF(tops[i]);
231 for (offset_t j = offsets[i]; j < offsets[i+1]; ++j)
232 verts[j-offsets[i]] = globalToVert[conn[j]];
233 buildElement(m, interior, etype, verts);
236 int getMax(
const apf::GlobalToVert& globalToVert)
239 APF_CONST_ITERATE(apf::GlobalToVert, globalToVert, it)
240 max = std::max(max, it->first);
241 PCU_Max_Ints(&max, 1);
244 void constructResidence(apf::GlobalToVert& globalToVert)
246 int max = getMax(globalToVert);
248 int peers = PCU_Comm_Peers();
249 int quotient = total / peers;
250 int remainder = total % peers;
251 int mySize = quotient;
252 int self = PCU_Comm_Self();
253 if (
self == (peers - 1))
255 typedef std::vector< std::vector<int> > TmpParts;
256 TmpParts tmpParts(mySize);
260 APF_ITERATE(apf::GlobalToVert, globalToVert, it) {
262 int to = std::min(peers - 1, gid / quotient);
263 PCU_COMM_PACK(to, gid);
266 int myOffset =
self * quotient;
269 while (PCU_Comm_Receive()) {
271 PCU_COMM_UNPACK(gid);
272 int from = PCU_Comm_Sender();
273 tmpParts.at(gid - myOffset).push_back(from);
278 for (
int i = 0; i < mySize; ++i) {
279 std::vector<int>& parts = tmpParts[i];
280 for (
size_t j = 0; j < parts.size(); ++j) {
282 int gid = i + myOffset;
283 int nparts = parts.size();
284 PCU_COMM_PACK(to, gid);
285 PCU_COMM_PACK(to, nparts);
286 for (
size_t k = 0; k < parts.size(); ++k)
287 PCU_COMM_PACK(to, parts[k]);
294 while (PCU_Comm_Receive()) {
296 PCU_COMM_UNPACK(gid);
298 PCU_COMM_UNPACK(nparts);
299 apf::Parts residence;
300 for (
int i = 0; i < nparts; ++i) {
302 PCU_COMM_UNPACK(part);
303 residence.insert(part);
305 apf::MeshEntity* vert = globalToVert[gid];
306 m->setResidence(vert, residence);
313 void constructRemotes(apf::GlobalToVert& globalToVert)
315 int self = PCU_Comm_Self();
317 APF_ITERATE(apf::GlobalToVert, globalToVert, it) {
319 apf::MeshEntity* vert = it->second;
320 apf::Parts residence;
321 m->getResidence(vert, residence);
322 APF_ITERATE(apf::Parts, residence, rit)
324 PCU_COMM_PACK(*rit, gid);
325 PCU_COMM_PACK(*rit, vert);
329 while (PCU_Comm_Receive()) {
331 PCU_COMM_UNPACK(gid);
332 apf::MeshEntity* remote;
333 PCU_COMM_UNPACK(remote);
334 int from = PCU_Comm_Sender();
335 apf::MeshEntity* vert = globalToVert[gid];
336 m->addRemote(vert, from, remote);
347 AlgParMA(
const RCP<const Environment> &env__,
348 const RCP<
const Comm<int> > &problemComm__,
349 const RCP<
const IdentifierAdapter<user_t> > &adapter__)
351 throw std::runtime_error(
"ParMA needs a MeshAdapter but you haven't given it one");
354 AlgParMA(
const RCP<const Environment> &env__,
355 const RCP<
const Comm<int> > &problemComm__,
356 const RCP<
const VectorAdapter<user_t> > &adapter__)
358 throw std::runtime_error(
"ParMA needs a MeshAdapter but you haven't given it one");
361 AlgParMA(
const RCP<const Environment> &env__,
362 const RCP<
const Comm<int> > &problemComm__,
363 const RCP<
const GraphAdapter<user_t,userCoord_t> > &adapter__)
365 throw std::runtime_error(
"ParMA needs a MeshAdapter but you haven't given it one");
368 AlgParMA(
const RCP<const Environment> &env__,
369 const RCP<
const Comm<int> > &problemComm__,
370 const RCP<
const MatrixAdapter<user_t,userCoord_t> > &adapter__)
372 throw std::runtime_error(
"ParMA needs a MeshAdapter but you haven't given it one");
376 AlgParMA(
const RCP<const Environment> &env__,
377 const RCP<
const Comm<int> > &problemComm__,
378 const RCP<
const MeshAdapter<user_t> > &adapter__) :
379 env(env__), problemComm(problemComm__), adapter(adapter__)
381 setMPIComm(problemComm__);
387 if (!PCU_Comm_Initialized())
391 PCU_Switch_Comm(mpicomm);
398 else if (adapter->getLocalNumOf(
MESH_FACE)>0)
402 PCU_Max_Ints(&dim,1);
404 throw std::runtime_error(
"ParMA neeeds faces or region information");
407 if (dim!=adapter->getPrimaryEntityType())
408 throw std::runtime_error(
"ParMA only supports balancing primary type==mesh element");
412 gmi_model* g = gmi_load(
".null");
414 m = apf::makeEmptyMdsMesh(g,dim,
false);
419 adapter->getTopologyViewOf(primary_type,tops);
424 const gno_t* element_gids;
426 adapter->getIDsViewOf(primary_type,element_gids);
427 adapter->getPartsView(part_ids);
428 for (
size_t i =0;i<adapter->getLocalNumOf(primary_type);i++)
429 mapping_elm_gids_index[element_gids[i]] = i;
432 const gno_t* vertex_gids;
436 int c_dim = adapter->getDimension();
438 int* strides =
new int[c_dim];
439 for (
int i=0;i<c_dim;i++)
440 adapter->getCoordinatesViewOf(
MESH_VERTEX,vertex_coords[i],strides[i],i);
444 throw "APF needs adjacency information from elements to vertices";
445 const offset_t* offsets;
446 const gno_t* adjacent_vertex_gids;
447 adapter->getAdjsView(primary_type,
MESH_VERTEX,offsets,adjacent_vertex_gids);
450 apf::GlobalToVert vertex_mapping;
451 apf::ModelEntity* interior = m->findModelEntity(m->getDimension(), 0);
452 for (
size_t i=0;i<adapter->getLocalNumOf(
MESH_VERTEX);i++) {
453 apf::MeshEntity* vtx = m->createVert_(interior);
455 for (
int k=0;k<c_dim&&k<3;k++)
456 temp_coords[k] = vertex_coords[k][i*strides[k]];
458 for (
int k=c_dim;k<3;k++)
460 apf::Vector3 point(temp_coords[0],temp_coords[1],temp_coords[2]);
461 m->setPoint(vtx,0,point);
462 vertex_mapping[vertex_gids[i]] = vtx;
465 constructElements(adjacent_vertex_gids, adapter->getLocalNumOf(primary_type), offsets, tops, vertex_mapping);
466 constructResidence(vertex_mapping);
467 constructRemotes(vertex_mapping);
474 apf::FieldShape* s = apf::getConstant(dim);
475 gids = apf::createNumbering(m,
"global_ids",s,1);
476 origin_part_ids = apf::createNumbering(m,
"origin",s,1);
479 apf::MeshIterator* itr = m->begin(dim);
480 apf::MeshEntity* ent;
482 while ((ent = m->iterate(itr))) {
483 apf::number(gids,ent,0,0,element_gids[i]);
484 apf::number(origin_part_ids,ent,0,0,PCU_Comm_Self());
490 apf::alignMdsRemotes(m);
491 apf::deriveMdsModel(m);
496 delete [] vertex_coords;
499 void partition(
const RCP<PartitioningSolution<Adapter> > &solution);
504 template <
typename Adapter>
506 const RCP<PartitioningSolution<Adapter> > &solution
510 std::string alg_name =
"VtxElm";
511 double imbalance = 1.1;
514 int ghost_bridge=m->getDimension()-1;
517 const Teuchos::ParameterList &pl = env->getParameters();
519 const Teuchos::ParameterList &ppl = pl.sublist(
"parma_parameters");
520 for (ParameterList::ConstIterator iter = ppl.begin();
521 iter != ppl.end(); iter++) {
522 const std::string &zname = pl.name(iter);
523 if (zname ==
"parma_method") {
524 std::string zval = pl.entry(iter).getValue(&zval);
527 else if (zname ==
"step_size") {
528 double zval = pl.entry(iter).getValue(&zval);
531 else if (zname==
"ghost_layers" || zname==
"ghost_bridge") {
532 int zval = pl.entry(iter).getValue(&zval);
533 if (zname==
"ghost_layers")
540 catch (std::exception &e) {
544 const Teuchos::ParameterEntry *pe2 = pl.getEntryPtr(
"imbalance_tolerance");
546 imbalance = pe2->getValue<
double>(&imbalance);
550 bool weightVertex,weightEdge,weightFace,weightElement;
551 weightVertex=weightEdge=weightFace=weightElement=
false;
554 apf::Balancer* balancer;
555 const int verbose = 1;
556 if (alg_name==
"Vertex") {
557 balancer = Parma_MakeVtxBalancer(m, step, verbose);
560 else if (alg_name==
"Element") {
561 balancer = Parma_MakeElmBalancer(m, step, verbose);
564 else if (alg_name==
"VtxElm") {
565 balancer = Parma_MakeVtxElmBalancer(m,step,verbose);
566 weightVertex = weightElement=
true;
568 else if (alg_name==
"VtxEdgeElm") {
569 balancer = Parma_MakeVtxEdgeElmBalancer(m, step, verbose);
570 weightVertex=weightEdge=weightElement=
true;
572 else if (alg_name==
"Ghost") {
573 balancer = Parma_MakeGhostDiffuser(m, ghost_layers, ghost_bridge, step, verbose);
574 weightVertex=weightEdge=weightFace=
true;
575 if (3 == m->getDimension()) {
579 else if (alg_name==
"Shape") {
580 balancer = Parma_MakeShapeOptimizer(m,step,verbose);
583 else if (alg_name==
"Centroid") {
584 balancer = Parma_MakeCentroidDiffuser(m,step,verbose);
588 throw std::runtime_error(
"No such parma method defined");
592 apf::MeshTag*
weights = setWeights(weightVertex,weightEdge,weightFace,weightElement);
595 balancer->balance(weights, imbalance);
599 int num_local = adapter->getLocalNumOf(adapter->getPrimaryEntityType());
600 ArrayRCP<part_t> partList(
new part_t[num_local], 0, num_local,
true);
604 apf::MeshEntity* ent;
605 apf::MeshIterator* itr = m->begin(m->getDimension());
607 while ((ent=m->iterate(itr))) {
608 if (m->isOwned(ent)) {
609 part_t target_part_id = apf::getNumber(origin_part_ids,ent,0,0);
610 gno_t element_gid = apf::getNumber(gids,ent,0,0);
611 PCU_COMM_PACK(target_part_id,element_gid);
620 while (PCU_Comm_Receive()) {
622 PCU_COMM_UNPACK(global_id);
623 lno_t local_id = mapping_elm_gids_index[global_id];
624 part_t new_part_id = PCU_Comm_Sender();
625 partList[local_id] = new_part_id;
628 solution->setParts(partList);
631 apf::destroyNumbering(gids);
632 apf::destroyNumbering(origin_part_ids);
633 apf::removeTagFromDimension(m, weights, m->getDimension());
634 m->destroyTag(weights);
644 #endif // HAVE_ZOLTAN2_PARMA
virtual void partition(const RCP< PartitioningSolution< Adapter > > &)
Partitioning method.
AlgParMA(const RCP< const Environment > &, const RCP< const Comm< int > > &, const RCP< const BaseAdapter< user_t > > &)
#define Z2_FORWARD_EXCEPTIONS
Forward an exception back through call stack.
Defines the PartitioningSolution class.
SparseMatrixAdapter_t::part_t part_t
Adapter::scalar_t scalar_t
Algorithm defines the base class for all algorithms.
EntityTopologyType
Enumerate entity topology types for meshes: points,lines,polygons,triangles,quadrilaterals, polyhedrons, tetrahedrons, hexhedrons, prisms, or pyramids.
Traits class to handle conversions between gno_t/lno_t and TPL data types (e.g., ParMETIS's idx_t...
MeshEntityType
Enumerate entity types for meshes: Regions, Faces, Edges, or Vertices.
A gathering of useful namespace methods.
Zoltan2::BasicUserTypes< zscalar_t, zlno_t, zgno_t > user_t