10 #ifndef _ZOLTAN2_ALGPARMA_HPP_
11 #define _ZOLTAN2_ALGPARMA_HPP_
38 #ifndef HAVE_ZOLTAN2_PARMA
44 template <
typename Adapter>
51 const RCP<
const Comm<int> > &,
54 throw std::runtime_error(
55 "BUILD ERROR: ParMA requested but not compiled into Zoltan2.\n"
56 "Please set CMake flag Zoltan2_ENABLE_ParMA:BOOL=ON.");
63 #ifdef HAVE_ZOLTAN2_PARMA
70 #include <apfNumbering.h>
73 #include <apfConvert.h>
80 template <
typename Adapter>
81 class AlgParMA :
public Algorithm<Adapter>
88 typedef typename Adapter::scalar_t
scalar_t;
89 typedef typename Adapter::offset_t offset_t;
92 typedef typename Adapter::userCoord_t userCoord_t;
94 const RCP<const Environment> env;
95 const RCP<const Comm<int> > problemComm;
96 const RCP<const MeshAdapter<user_t> > adapter;
100 apf::Numbering* origin_part_ids;
101 std::map<gno_t, lno_t> mapping_elm_gids_index;
106 void setMPIComm(
const RCP<
const Comm<int> > &problemComm__) {
107 # ifdef HAVE_ZOLTAN2_MPI
108 mpicomm = Teuchos::getRawMpiComm(*problemComm__);
110 mpicomm = MPI_COMM_WORLD;
120 return apf::Mesh::VERTEX;
122 return apf::Mesh::EDGE;
126 return apf::Mesh::QUAD;
128 return apf::Mesh::TET;
130 return apf::Mesh::HEX;
131 else if (ttype==
PRISM)
136 throw std::runtime_error(
"APF does not support this topology type");
142 void setEntWeights(
int dim, apf::MeshTag* tag) {
144 for (
int i=0;i<m->getTagSize(tag);i++) {
145 apf::MeshIterator* itr = m->begin(dim);
146 apf::MeshEntity* ent;
149 if (i<adapter->getNumWeightsPerOf(etype))
150 adapter->getWeightsViewOf(etype,ws,stride,i);
152 while ((ent= m->iterate(itr))) {
155 w =
static_cast<double>(ws[j]);
156 m->setDoubleTag(ent,tag,&w);
164 apf::MeshTag* setWeights(
bool vtx,
bool edge,
bool face,
bool elm) {
167 num_ws = std::max(num_ws,adapter->getNumWeightsPerOf(
MESH_VERTEX));
169 num_ws = std::max(num_ws,adapter->getNumWeightsPerOf(
MESH_EDGE));
171 num_ws = std::max(num_ws,adapter->getNumWeightsPerOf(
MESH_FACE));
173 num_ws = std::max(num_ws,adapter->getNumWeightsPerOf(entityAPFtoZ2(m->getDimension())));
174 apf::MeshTag* tag = m->createDoubleTag(
"parma_weight",num_ws);
176 setEntWeights(0,tag);
178 setEntWeights(1,tag);
180 setEntWeights(2,tag);
182 setEntWeights(m->getDimension(),tag);
189 void constructElements(
const gno_t* conn,
lno_t nelem,
const offset_t* offsets,
192 apf::ModelEntity* interior = m->findModelEntity(m->getDimension(), 0);
193 for (
lno_t i = 0; i < nelem; ++i) {
194 apf::Mesh::Type etype = topologyZ2toAPF(tops[i]);
196 for (offset_t j = offsets[i]; j < offsets[i+1]; ++j)
197 verts[j-offsets[i]] = globalToVert[conn[j]];
198 buildElement(m, interior, etype, verts);
201 int getMax(
const apf::GlobalToVert& globalToVert)
204 APF_CONST_ITERATE(apf::GlobalToVert, globalToVert, it)
205 max = std::max(max, it->first);
206 PCU_Max_Ints(&max, 1);
209 void constructResidence(apf::GlobalToVert& globalToVert)
211 int max = getMax(globalToVert);
213 int peers = PCU_Comm_Peers();
214 int quotient = total / peers;
215 int remainder = total % peers;
216 int mySize = quotient;
217 int self = PCU_Comm_Self();
218 if (
self == (peers - 1))
220 typedef std::vector< std::vector<int> > TmpParts;
221 TmpParts tmpParts(mySize);
225 APF_ITERATE(apf::GlobalToVert, globalToVert, it) {
227 int to = std::min(peers - 1, gid / quotient);
228 PCU_COMM_PACK(to, gid);
231 int myOffset =
self * quotient;
234 while (PCU_Comm_Receive()) {
236 PCU_COMM_UNPACK(gid);
237 int from = PCU_Comm_Sender();
238 tmpParts.at(gid - myOffset).push_back(from);
243 for (
int i = 0; i < mySize; ++i) {
244 std::vector<int>& parts = tmpParts[i];
245 for (
size_t j = 0; j < parts.size(); ++j) {
247 int gid = i + myOffset;
248 int nparts = parts.size();
249 PCU_COMM_PACK(to, gid);
250 PCU_COMM_PACK(to, nparts);
251 for (
size_t k = 0; k < parts.size(); ++k)
252 PCU_COMM_PACK(to, parts[k]);
259 while (PCU_Comm_Receive()) {
261 PCU_COMM_UNPACK(gid);
263 PCU_COMM_UNPACK(nparts);
264 apf::Parts residence;
265 for (
int i = 0; i < nparts; ++i) {
267 PCU_COMM_UNPACK(part);
268 residence.insert(part);
270 apf::MeshEntity* vert = globalToVert[gid];
271 m->setResidence(vert, residence);
278 void constructRemotes(apf::GlobalToVert& globalToVert)
280 int self = PCU_Comm_Self();
282 APF_ITERATE(apf::GlobalToVert, globalToVert, it) {
284 apf::MeshEntity* vert = it->second;
285 apf::Parts residence;
286 m->getResidence(vert, residence);
287 APF_ITERATE(apf::Parts, residence, rit)
289 PCU_COMM_PACK(*rit, gid);
290 PCU_COMM_PACK(*rit, vert);
294 while (PCU_Comm_Receive()) {
296 PCU_COMM_UNPACK(gid);
297 apf::MeshEntity* remote;
298 PCU_COMM_UNPACK(remote);
299 int from = PCU_Comm_Sender();
300 apf::MeshEntity* vert = globalToVert[gid];
301 m->addRemote(vert, from, remote);
312 AlgParMA(
const RCP<const Environment> &env__,
313 const RCP<
const Comm<int> > &problemComm__,
314 const RCP<
const IdentifierAdapter<user_t> > &adapter__)
316 throw std::runtime_error(
"ParMA needs a MeshAdapter but you haven't given it one");
319 AlgParMA(
const RCP<const Environment> &env__,
320 const RCP<
const Comm<int> > &problemComm__,
321 const RCP<
const VectorAdapter<user_t> > &adapter__)
323 throw std::runtime_error(
"ParMA needs a MeshAdapter but you haven't given it one");
326 AlgParMA(
const RCP<const Environment> &env__,
327 const RCP<
const Comm<int> > &problemComm__,
328 const RCP<
const GraphAdapter<user_t,userCoord_t> > &adapter__)
330 throw std::runtime_error(
"ParMA needs a MeshAdapter but you haven't given it one");
333 AlgParMA(
const RCP<const Environment> &env__,
334 const RCP<
const Comm<int> > &problemComm__,
335 const RCP<
const MatrixAdapter<user_t,userCoord_t> > &adapter__)
337 throw std::runtime_error(
"ParMA needs a MeshAdapter but you haven't given it one");
341 AlgParMA(
const RCP<const Environment> &env__,
342 const RCP<
const Comm<int> > &problemComm__,
343 const RCP<
const MeshAdapter<user_t> > &adapter__) :
344 env(env__), problemComm(problemComm__), adapter(adapter__)
346 setMPIComm(problemComm__);
352 if (!PCU_Comm_Initialized())
356 PCU_Switch_Comm(mpicomm);
363 else if (adapter->getLocalNumOf(
MESH_FACE)>0)
367 PCU_Max_Ints(&dim,1);
369 throw std::runtime_error(
"ParMA neeeds faces or region information");
372 if (dim!=adapter->getPrimaryEntityType())
373 throw std::runtime_error(
"ParMA only supports balancing primary type==mesh element");
377 gmi_model* g = gmi_load(
".null");
379 m = apf::makeEmptyMdsMesh(g,dim,
false);
384 adapter->getTopologyViewOf(primary_type,tops);
389 const gno_t* element_gids;
391 adapter->getIDsViewOf(primary_type,element_gids);
392 adapter->getPartsView(part_ids);
393 for (
size_t i =0;i<adapter->getLocalNumOf(primary_type);i++)
394 mapping_elm_gids_index[element_gids[i]] = i;
397 const gno_t* vertex_gids;
401 int c_dim = adapter->getDimension();
403 int* strides =
new int[c_dim];
404 for (
int i=0;i<c_dim;i++)
405 adapter->getCoordinatesViewOf(
MESH_VERTEX,vertex_coords[i],strides[i],i);
409 throw "APF needs adjacency information from elements to vertices";
410 const offset_t* offsets;
411 const gno_t* adjacent_vertex_gids;
412 adapter->getAdjsView(primary_type,
MESH_VERTEX,offsets,adjacent_vertex_gids);
415 apf::GlobalToVert vertex_mapping;
416 apf::ModelEntity* interior = m->findModelEntity(m->getDimension(), 0);
417 for (
size_t i=0;i<adapter->getLocalNumOf(
MESH_VERTEX);i++) {
418 apf::MeshEntity* vtx = m->createVert_(interior);
420 for (
int k=0;k<c_dim&&k<3;k++)
421 temp_coords[k] = vertex_coords[k][i*strides[k]];
423 for (
int k=c_dim;k<3;k++)
425 apf::Vector3 point(temp_coords[0],temp_coords[1],temp_coords[2]);
426 m->setPoint(vtx,0,point);
427 vertex_mapping[vertex_gids[i]] = vtx;
430 constructElements(adjacent_vertex_gids, adapter->getLocalNumOf(primary_type), offsets, tops, vertex_mapping);
431 constructResidence(vertex_mapping);
432 constructRemotes(vertex_mapping);
439 apf::FieldShape* s = apf::getConstant(dim);
440 gids = apf::createNumbering(m,
"global_ids",s,1);
441 origin_part_ids = apf::createNumbering(m,
"origin",s,1);
444 apf::MeshIterator* itr = m->begin(dim);
445 apf::MeshEntity* ent;
447 while ((ent = m->iterate(itr))) {
448 apf::number(gids,ent,0,0,element_gids[i]);
449 apf::number(origin_part_ids,ent,0,0,PCU_Comm_Self());
455 apf::alignMdsRemotes(m);
456 apf::deriveMdsModel(m);
461 delete [] vertex_coords;
464 void partition(
const RCP<PartitioningSolution<Adapter> > &solution);
469 template <
typename Adapter>
471 const RCP<PartitioningSolution<Adapter> > &solution
475 std::string alg_name =
"VtxElm";
476 double imbalance = 1.1;
479 int ghost_bridge=m->getDimension()-1;
482 const Teuchos::ParameterList &pl = env->getParameters();
484 const Teuchos::ParameterList &ppl = pl.sublist(
"parma_parameters");
485 for (ParameterList::ConstIterator iter = ppl.begin();
486 iter != ppl.end(); iter++) {
487 const std::string &zname = pl.name(iter);
488 if (zname ==
"parma_method") {
489 std::string zval = pl.entry(iter).getValue(&zval);
492 else if (zname ==
"step_size") {
493 double zval = pl.entry(iter).getValue(&zval);
496 else if (zname==
"ghost_layers" || zname==
"ghost_bridge") {
497 int zval = pl.entry(iter).getValue(&zval);
498 if (zname==
"ghost_layers")
505 catch (std::exception &e) {
509 const Teuchos::ParameterEntry *pe2 = pl.getEntryPtr(
"imbalance_tolerance");
511 imbalance = pe2->getValue<
double>(&imbalance);
515 bool weightVertex,weightEdge,weightFace,weightElement;
516 weightVertex=weightEdge=weightFace=weightElement=
false;
519 apf::Balancer* balancer;
520 const int verbose = 1;
521 if (alg_name==
"Vertex") {
522 balancer = Parma_MakeVtxBalancer(m, step, verbose);
525 else if (alg_name==
"Element") {
526 balancer = Parma_MakeElmBalancer(m, step, verbose);
529 else if (alg_name==
"VtxElm") {
530 balancer = Parma_MakeVtxElmBalancer(m,step,verbose);
531 weightVertex = weightElement=
true;
533 else if (alg_name==
"VtxEdgeElm") {
534 balancer = Parma_MakeVtxEdgeElmBalancer(m, step, verbose);
535 weightVertex=weightEdge=weightElement=
true;
537 else if (alg_name==
"Ghost") {
538 balancer = Parma_MakeGhostDiffuser(m, ghost_layers, ghost_bridge, step, verbose);
539 weightVertex=weightEdge=weightFace=
true;
540 if (3 == m->getDimension()) {
544 else if (alg_name==
"Shape") {
545 balancer = Parma_MakeShapeOptimizer(m,step,verbose);
548 else if (alg_name==
"Centroid") {
549 balancer = Parma_MakeCentroidDiffuser(m,step,verbose);
553 throw std::runtime_error(
"No such parma method defined");
557 apf::MeshTag*
weights = setWeights(weightVertex,weightEdge,weightFace,weightElement);
560 balancer->balance(weights, imbalance);
564 int num_local = adapter->getLocalNumOf(adapter->getPrimaryEntityType());
565 ArrayRCP<part_t> partList(
new part_t[num_local], 0, num_local,
true);
569 apf::MeshEntity* ent;
570 apf::MeshIterator* itr = m->begin(m->getDimension());
572 while ((ent=m->iterate(itr))) {
573 if (m->isOwned(ent)) {
574 part_t target_part_id = apf::getNumber(origin_part_ids,ent,0,0);
575 gno_t element_gid = apf::getNumber(gids,ent,0,0);
576 PCU_COMM_PACK(target_part_id,element_gid);
585 while (PCU_Comm_Receive()) {
587 PCU_COMM_UNPACK(global_id);
588 lno_t local_id = mapping_elm_gids_index[global_id];
589 part_t new_part_id = PCU_Comm_Sender();
590 partList[local_id] = new_part_id;
593 solution->setParts(partList);
596 apf::destroyNumbering(gids);
597 apf::destroyNumbering(origin_part_ids);
598 apf::removeTagFromDimension(m, weights, m->getDimension());
599 m->destroyTag(weights);
609 #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.
map_t::global_ordinal_type gno_t
Defines the PartitioningSolution class.
SparseMatrixAdapter_t::part_t part_t
Adapter::scalar_t scalar_t
Algorithm defines the base class for all algorithms.
map_t::local_ordinal_type lno_t
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