Zoltan2
Zoltan2_AlgParMA.hpp
Go to the documentation of this file.
1 // @HEADER
2 //
3 // ***********************************************************************
4 //
5 // Zoltan2: A package of combinatorial algorithms for scientific computing
6 // Copyright 2012 Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact Karen Devine (kddevin@sandia.gov)
39 // Erik Boman (egboman@sandia.gov)
40 // Siva Rajamanickam (srajama@sandia.gov)
41 //
42 // ***********************************************************************
43 //
44 // @HEADER
45 #ifndef _ZOLTAN2_ALGPARMA_HPP_
46 #define _ZOLTAN2_ALGPARMA_HPP_
47 
48 #include <Zoltan2_Algorithm.hpp>
50 #include <Zoltan2_Util.hpp>
51 #include <Zoltan2_TPLTraits.hpp>
52 
56 //
57 // This design creates an apf mesh to run the ParMA algorithms on. The
58 // final solution is determined by changes from beginning to end of the mesh.
59 // This approach allows development closer to that of PUMI setup but at the
60 // cost of creating an extra mesh representation.
61 //
62 // Available ParMA algorithms are given by setting the parma_method parameter
63 // of the sublist parma_paramaters to one of the following:
64 // Vertex - Balances targeting vertex imbalance
65 // Element - Balances targeting element imbalance
66 // VtxElm - Balances targeting vertex and element imbalance
67 // VtxEdgeElm - Balances targeting vertex, edge, and element imbalance
68 // Ghost - Balances using ghost element aware diffusion
69 // Shape - Optimizes shape of parts by increasing the size of small part boundaries
70 // Centroid - Balances using centroid diffusion
72 
73 #ifndef HAVE_ZOLTAN2_PARMA
74 
75 // Error handling for when ParMA is requested
76 // but Zoltan2 not built with ParMA.
77 
78 namespace Zoltan2 {
79 template <typename Adapter>
80 class AlgParMA : public Algorithm<Adapter>
81 {
82 public:
83  typedef typename Adapter::user_t user_t;
84 
85  AlgParMA(const RCP<const Environment> &env,
86  const RCP<const Comm<int> > &problemComm,
87  const RCP<const BaseAdapter<user_t> > &adapter)
88  {
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.");
92  }
93 };
94 }
95 
96 #endif
97 
98 #ifdef HAVE_ZOLTAN2_PARMA
99 
100 
101 #include <apf.h>
102 #include <gmi_null.h>
103 #include <apfMDS.h>
104 #include <apfMesh2.h>
105 #include <apfNumbering.h>
106 #include <PCU.h>
107 #include <parma.h>
108 #include <apfConvert.h>
109 #include <apfShape.h>
110 #include <map>
111 #include <cassert>
112 
113 namespace Zoltan2 {
114 
115 template <typename Adapter>
116 class AlgParMA : public Algorithm<Adapter>
117 {
118 
119 private:
120 
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::part_t part_t;
125  typedef typename Adapter::user_t user_t;
126  typedef typename Adapter::userCoord_t userCoord_t;
127 
128  const RCP<const Environment> env;
129  const RCP<const Comm<int> > problemComm;
130  const RCP<const MeshAdapter<user_t> > adapter;
131 
132  apf::Mesh2* m;
133  apf::Numbering* gids;
134  apf::Numbering* origin_part_ids;
135  std::map<gno_t, lno_t> mapping_elm_gids_index;
136 
137  MPI_Comm mpicomm;
138  bool pcu_outside;
139 
140  void setMPIComm(const RCP<const Comm<int> > &problemComm__) {
141 # ifdef HAVE_ZOLTAN2_MPI
142  mpicomm = Teuchos::getRawMpiComm(*problemComm__);
143 # else
144  mpicomm = MPI_COMM_WORLD; // taken from siMPI
145 # endif
146  }
147  // provides conversion from an APF entity dimension to a Zoltan2 entity type
148  enum MeshEntityType entityAPFtoZ2(int dimension) const {return static_cast<MeshEntityType>(dimension);}
149 
150  //provides a conversion from the Zoltan2 topology type to and APF type
151  // throws an error on topology types not supported by APF
152  enum apf::Mesh::Type topologyZ2toAPF(enum EntityTopologyType ttype) const {
153  if (ttype==POINT)
154  return apf::Mesh::VERTEX;
155  else if (ttype==LINE_SEGMENT)
156  return apf::Mesh::EDGE;
157  else if (ttype==TRIANGLE)
158  return apf::Mesh::TRIANGLE;
159  else if (ttype==QUADRILATERAL)
160  return apf::Mesh::QUAD;
161  else if (ttype==TETRAHEDRON)
162  return apf::Mesh::TET;
163  else if (ttype==HEXAHEDRON)
164  return apf::Mesh::HEX;
165  else if (ttype==PRISM)
166  return apf::Mesh::PRISM;
167  else if (ttype==PYRAMID)
168  return apf::Mesh::PYRAMID;
169  else
170  throw std::runtime_error("APF does not support this topology type");
171 
172  }
173 
174  //Sets the weights of each entity in dimension 'dim' to those provided by the mesh adapter
175  //sets all weights in the mesh adapter but currently only one is considered by ParMA
176  void setEntWeights(int dim, apf::MeshTag* tag) {
177  MeshEntityType etype = entityAPFtoZ2(dim);
178  for (int i=0;i<m->getTagSize(tag);i++) {
179  apf::MeshIterator* itr = m->begin(dim);
180  apf::MeshEntity* ent;
181  const scalar_t* ws=NULL;
182  int stride;
183  if (i<adapter->getNumWeightsPerOf(etype))
184  adapter->getWeightsViewOf(etype,ws,stride,i);
185  int j=0;
186  while ((ent= m->iterate(itr))) {
187  double w = 1.0;
188  if (ws!=NULL)
189  w = static_cast<double>(ws[j]);
190  m->setDoubleTag(ent,tag,&w);
191  j++;
192  }
193  m->end(itr);
194  }
195  }
196 
197  //Helper function to set the weights of each dimension needed by the specific parma algorithm
198  apf::MeshTag* setWeights(bool vtx, bool edge, bool face, bool elm) {
199  int num_ws=1;
200  if (vtx)
201  num_ws = std::max(num_ws,adapter->getNumWeightsPerOf(MESH_VERTEX));
202  if (edge)
203  num_ws = std::max(num_ws,adapter->getNumWeightsPerOf(MESH_EDGE));
204  if (face)
205  num_ws = std::max(num_ws,adapter->getNumWeightsPerOf(MESH_FACE));
206  if (elm)
207  num_ws = std::max(num_ws,adapter->getNumWeightsPerOf(entityAPFtoZ2(m->getDimension())));
208  apf::MeshTag* tag = m->createDoubleTag("parma_weight",num_ws);
209  if (vtx)
210  setEntWeights(0,tag);
211  if (edge)
212  setEntWeights(1,tag);
213  if (face)
214  setEntWeights(2,tag);
215  if (elm) {
216  setEntWeights(m->getDimension(),tag);
217  }
218  return tag;
219  }
220 
221 
222  //APF Mesh construction helper functions modified and placed here to support arbitrary entity types
223  void constructElements(const gno_t* conn, lno_t nelem, const lno_t* offsets,
224  const EntityTopologyType* tops, apf::GlobalToVert& globalToVert)
225  {
226  apf::ModelEntity* interior = m->findModelEntity(m->getDimension(), 0);
227  for (lno_t i = 0; i < nelem; ++i) {
228  apf::Mesh::Type etype = topologyZ2toAPF(tops[i]);
229  apf::Downward verts;
230  for (int j = offsets[i]; j < offsets[i+1]; ++j)
231  verts[j-offsets[i]] = globalToVert[conn[j]];
232  buildElement(m, interior, etype, verts);
233  }
234  }
235  int getMax(const apf::GlobalToVert& globalToVert)
236  {
237  int max = -1;
238  APF_CONST_ITERATE(apf::GlobalToVert, globalToVert, it)
239  max = std::max(max, it->first);
240  PCU_Max_Ints(&max, 1); // this is type-dependent
241  return max;
242  }
243  void constructResidence(apf::GlobalToVert& globalToVert)
244  {
245  int max = getMax(globalToVert);
246  int total = max + 1;
247  int peers = PCU_Comm_Peers();
248  int quotient = total / peers;
249  int remainder = total % peers;
250  int mySize = quotient;
251  int self = PCU_Comm_Self();
252  if (self == (peers - 1))
253  mySize += remainder;
254  typedef std::vector< std::vector<int> > TmpParts;
255  TmpParts tmpParts(mySize);
256  /* if we have a vertex, send its global id to the
257  broker for that global id */
258  PCU_Comm_Begin();
259  APF_ITERATE(apf::GlobalToVert, globalToVert, it) {
260  int gid = it->first;
261  int to = std::min(peers - 1, gid / quotient);
262  PCU_COMM_PACK(to, gid);
263  }
264  PCU_Comm_Send();
265  int myOffset = self * quotient;
266  /* brokers store all the part ids that sent messages
267  for each global id */
268  while (PCU_Comm_Receive()) {
269  int gid;
270  PCU_COMM_UNPACK(gid);
271  int from = PCU_Comm_Sender();
272  tmpParts.at(gid - myOffset).push_back(from);
273  }
274  /* for each global id, send all associated part ids
275  to all associated parts */
276  PCU_Comm_Begin();
277  for (int i = 0; i < mySize; ++i) {
278  std::vector<int>& parts = tmpParts[i];
279  for (size_t j = 0; j < parts.size(); ++j) {
280  int to = parts[j];
281  int gid = i + myOffset;
282  int nparts = parts.size();
283  PCU_COMM_PACK(to, gid);
284  PCU_COMM_PACK(to, nparts);
285  for (size_t k = 0; k < parts.size(); ++k)
286  PCU_COMM_PACK(to, parts[k]);
287  }
288  }
289  PCU_Comm_Send();
290  /* receiving a global id and associated parts,
291  lookup the vertex and classify it on the partition
292  model entity for that set of parts */
293  while (PCU_Comm_Receive()) {
294  int gid;
295  PCU_COMM_UNPACK(gid);
296  int nparts;
297  PCU_COMM_UNPACK(nparts);
298  apf::Parts residence;
299  for (int i = 0; i < nparts; ++i) {
300  int part;
301  PCU_COMM_UNPACK(part);
302  residence.insert(part);
303  }
304  apf::MeshEntity* vert = globalToVert[gid];
305  m->setResidence(vert, residence);
306  }
307  }
308 
309  /* given correct residence from the above algorithm,
310  negotiate remote copies by exchanging (gid,pointer)
311  pairs with parts in the residence of the vertex */
312  void constructRemotes(apf::GlobalToVert& globalToVert)
313  {
314  int self = PCU_Comm_Self();
315  PCU_Comm_Begin();
316  APF_ITERATE(apf::GlobalToVert, globalToVert, it) {
317  int gid = it->first;
318  apf::MeshEntity* vert = it->second;
319  apf::Parts residence;
320  m->getResidence(vert, residence);
321  APF_ITERATE(apf::Parts, residence, rit)
322  if (*rit != self) {
323  PCU_COMM_PACK(*rit, gid);
324  PCU_COMM_PACK(*rit, vert);
325  }
326  }
327  PCU_Comm_Send();
328  while (PCU_Comm_Receive()) {
329  int gid;
330  PCU_COMM_UNPACK(gid);
331  apf::MeshEntity* remote;
332  PCU_COMM_UNPACK(remote);
333  int from = PCU_Comm_Sender();
334  apf::MeshEntity* vert = globalToVert[gid];
335  m->addRemote(vert, from, remote);
336  }
337  }
338 
339 public:
340 
346  AlgParMA(const RCP<const Environment> &env__,
347  const RCP<const Comm<int> > &problemComm__,
348  const RCP<const IdentifierAdapter<user_t> > &adapter__)
349  {
350  throw std::runtime_error("ParMA needs a MeshAdapter but you haven't given it one");
351  }
352 
353  AlgParMA(const RCP<const Environment> &env__,
354  const RCP<const Comm<int> > &problemComm__,
355  const RCP<const VectorAdapter<user_t> > &adapter__)
356  {
357  throw std::runtime_error("ParMA needs a MeshAdapter but you haven't given it one");
358  }
359 
360  AlgParMA(const RCP<const Environment> &env__,
361  const RCP<const Comm<int> > &problemComm__,
362  const RCP<const GraphAdapter<user_t,userCoord_t> > &adapter__)
363  {
364  throw std::runtime_error("ParMA needs a MeshAdapter but you haven't given it one");
365  }
366 
367  AlgParMA(const RCP<const Environment> &env__,
368  const RCP<const Comm<int> > &problemComm__,
369  const RCP<const MatrixAdapter<user_t,userCoord_t> > &adapter__)
370  {
371  throw std::runtime_error("ParMA needs a MeshAdapter but you haven't given it one");
372 
373  }
374 
375  AlgParMA(const RCP<const Environment> &env__,
376  const RCP<const Comm<int> > &problemComm__,
377  const RCP<const MeshAdapter<user_t> > &adapter__) :
378  env(env__), problemComm(problemComm__), adapter(adapter__)
379  {
380  setMPIComm(problemComm__);
381 
382  //Setup PCU communications
383  //If PCU was already initialized outside (EX: for the APFMeshAdapter)
384  // we don't initialize it again.
385  pcu_outside=false;
386  if (!PCU_Comm_Initialized())
387  PCU_Comm_Init();
388  else
389  pcu_outside=true;
390  PCU_Switch_Comm(mpicomm);
391 
392  //Find the mesh dimension based on if there are any regions or faces in the part
393  // an all reduce is needed in case one part is empty (Ex: after hypergraph partitioning)
394  int dim;
395  if (adapter->getLocalNumOf(MESH_REGION)>0)
396  dim=3;
397  else if (adapter->getLocalNumOf(MESH_FACE)>0)
398  dim=2;
399  else
400  dim=0;
401  PCU_Max_Ints(&dim,1);
402  if (dim<2)
403  throw std::runtime_error("ParMA neeeds faces or region information");
404 
405  //GFD Currently not allowing ParMA to balance non element primary types
406  if (dim!=adapter->getPrimaryEntityType())
407  throw std::runtime_error("ParMA only supports balancing primary type==mesh element");
408 
409  //Create empty apf mesh
410  gmi_register_null();
411  gmi_model* g = gmi_load(".null");
412  enum MeshEntityType primary_type = entityAPFtoZ2(dim);
413  m = apf::makeEmptyMdsMesh(g,dim,false);
414 
415  //Get entity topology types
416  const EntityTopologyType* tops;
417  try {
418  adapter->getTopologyViewOf(primary_type,tops);
419  }
421 
422  //Get element global ids and part ids
423  const gno_t* element_gids;
424  const part_t* part_ids;
425  adapter->getIDsViewOf(primary_type,element_gids);
426  adapter->getPartsView(part_ids);
427  for (size_t i =0;i<adapter->getLocalNumOf(primary_type);i++)
428  mapping_elm_gids_index[element_gids[i]] = i;
429 
430  //get vertex global ids
431  const gno_t* vertex_gids;
432  adapter->getIDsViewOf(MESH_VERTEX,vertex_gids);
433 
434  //Get vertex coordinates
435  int c_dim = adapter->getDimension();
436  const scalar_t ** vertex_coords = new const scalar_t*[c_dim];
437  int* strides = new int[c_dim];
438  for (int i=0;i<c_dim;i++)
439  adapter->getCoordinatesViewOf(MESH_VERTEX,vertex_coords[i],strides[i],i);
440 
441  //Get first adjacencies from elements to vertices
442  if (!adapter->availAdjs(primary_type,MESH_VERTEX))
443  throw "APF needs adjacency information from elements to vertices";
444  const lno_t* offsets;
445  const gno_t* adjacent_vertex_gids;
446  adapter->getAdjsView(primary_type, MESH_VERTEX,offsets,adjacent_vertex_gids);
447 
448  //build the apf mesh
449  apf::GlobalToVert vertex_mapping;
450  apf::ModelEntity* interior = m->findModelEntity(m->getDimension(), 0);
451  for (size_t i=0;i<adapter->getLocalNumOf(MESH_VERTEX);i++) {
452  apf::MeshEntity* vtx = m->createVert_(interior);
453  scalar_t temp_coords[3];
454  for (int k=0;k<c_dim&&k<3;k++)
455  temp_coords[k] = vertex_coords[k][i*strides[k]];
456 
457  for (int k=c_dim;k<3;k++)
458  temp_coords[k] = 0;
459  apf::Vector3 point(temp_coords[0],temp_coords[1],temp_coords[2]);
460  m->setPoint(vtx,0,point);
461  vertex_mapping[vertex_gids[i]] = vtx;
462  }
463  //Call modified helper functions to build the mesh from element to vertex adjacency
464  constructElements(adjacent_vertex_gids, adapter->getLocalNumOf(primary_type), offsets, tops, vertex_mapping);
465  constructResidence(vertex_mapping);
466  constructRemotes(vertex_mapping);
467  stitchMesh(m);
468  m->acceptChanges();
469 
470 
471  //Setup numberings of global ids and original part ids
472  // for use after ParMA is run
473  apf::FieldShape* s = apf::getConstant(dim);
474  gids = apf::createNumbering(m,"global_ids",s,1);
475  origin_part_ids = apf::createNumbering(m,"origin",s,1);
476 
477  //number the global ids and original part ids
478  apf::MeshIterator* itr = m->begin(dim);
479  apf::MeshEntity* ent;
480  int i = 0;
481  while ((ent = m->iterate(itr))) {
482  apf::number(gids,ent,0,0,element_gids[i]);
483  apf::number(origin_part_ids,ent,0,0,PCU_Comm_Self());
484  i++;
485  }
486  m->end(itr);
487 
488  //final setup for apf mesh
489  apf::alignMdsRemotes(m);
490  apf::deriveMdsModel(m);
491  m->acceptChanges();
492  m->verify();
493 
494  //cleanup temp storage
495  delete [] vertex_coords;
496  delete [] strides;
497  }
498  void partition(const RCP<PartitioningSolution<Adapter> > &solution);
499 
500 };
501 
503 template <typename Adapter>
505  const RCP<PartitioningSolution<Adapter> > &solution
506 )
507 {
508  //Get parameters
509  std::string alg_name = "VtxElm";
510  double imbalance = 1.1;
511  double step = .5;
512  int ghost_layers=3;
513  int ghost_bridge=m->getDimension()-1;
514 
515  //Get the parameters for ParMA
516  const Teuchos::ParameterList &pl = env->getParameters();
517  try {
518  const Teuchos::ParameterList &ppl = pl.sublist("parma_parameters");
519  for (ParameterList::ConstIterator iter = ppl.begin();
520  iter != ppl.end(); iter++) {
521  const std::string &zname = pl.name(iter);
522  if (zname == "parma_method") {
523  std::string zval = pl.entry(iter).getValue(&zval);
524  alg_name = zval;
525  }
526  else if (zname == "step_size") {
527  double zval = pl.entry(iter).getValue(&zval);
528  step = zval;
529  }
530  else if (zname=="ghost_layers" || zname=="ghost_bridge") {
531  int zval = pl.entry(iter).getValue(&zval);
532  if (zname=="ghost_layers")
533  ghost_layers = zval;
534  else
535  ghost_bridge = zval;
536  }
537  }
538  }
539  catch (std::exception &e) {
540  //No parma_parameters sublist found
541  }
542 
543  const Teuchos::ParameterEntry *pe2 = pl.getEntryPtr("imbalance_tolerance");
544  if (pe2){
545  imbalance = pe2->getValue<double>(&imbalance);
546  }
547 
548  //booleans for which dimensions need weights
549  bool weightVertex,weightEdge,weightFace,weightElement;
550  weightVertex=weightEdge=weightFace=weightElement=false;
551 
552  //Build the selected balancer
553  apf::Balancer* balancer;
554  const int verbose = 1;
555  if (alg_name=="Vertex") {
556  balancer = Parma_MakeVtxBalancer(m, step, verbose);
557  weightVertex = true;
558  }
559  else if (alg_name=="Element") {
560  balancer = Parma_MakeElmBalancer(m, step, verbose);
561  weightElement=true;
562  }
563  else if (alg_name=="VtxElm") {
564  balancer = Parma_MakeVtxElmBalancer(m,step,verbose);
565  weightVertex = weightElement=true;
566  }
567  else if (alg_name=="VtxEdgeElm") {
568  balancer = Parma_MakeVtxEdgeElmBalancer(m, step, verbose);
569  weightVertex=weightEdge=weightElement=true;
570  }
571  else if (alg_name=="Ghost") {
572  balancer = Parma_MakeGhostDiffuser(m, ghost_layers, ghost_bridge, step, verbose);
573  weightVertex=weightEdge=weightFace=true;
574  if (3 == m->getDimension()) {
575  weightElement=true;
576  }
577  }
578  else if (alg_name=="Shape") {
579  balancer = Parma_MakeShapeOptimizer(m,step,verbose);
580  weightElement=true;
581  }
582  else if (alg_name=="Centroid") {
583  balancer = Parma_MakeCentroidDiffuser(m,step,verbose);
584  weightElement=true;
585  }
586  else {
587  throw std::runtime_error("No such parma method defined");
588  }
589 
590  //build the weights
591  apf::MeshTag* weights = setWeights(weightVertex,weightEdge,weightFace,weightElement);
592 
593  //balance the apf mesh
594  balancer->balance(weights, imbalance);
595  delete balancer;
596 
597  // Load answer into the solution.
598  int num_local = adapter->getLocalNumOf(adapter->getPrimaryEntityType());
599  ArrayRCP<part_t> partList(new part_t[num_local], 0, num_local, true);
600 
601  //Setup for communication
602  PCU_Comm_Begin();
603  apf::MeshEntity* ent;
604  apf::MeshIterator* itr = m->begin(m->getDimension());
605  //Pack information back to each elements original owner
606  while ((ent=m->iterate(itr))) {
607  if (m->isOwned(ent)) {
608  part_t target_part_id = apf::getNumber(origin_part_ids,ent,0,0);
609  gno_t element_gid = apf::getNumber(gids,ent,0,0);
610  PCU_COMM_PACK(target_part_id,element_gid);
611  }
612  }
613  m->end(itr);
614 
615  //Send information off
616  PCU_Comm_Send();
617 
618  //Unpack information and set new part ids
619  while (PCU_Comm_Receive()) {
620  gno_t global_id;
621  PCU_COMM_UNPACK(global_id);
622  lno_t local_id = mapping_elm_gids_index[global_id];
623  part_t new_part_id = PCU_Comm_Sender();
624  partList[local_id] = new_part_id;
625  }
626  //construct partition solution
627  solution->setParts(partList);
628 
629  // Clean up
630  apf::destroyNumbering(gids);
631  apf::destroyNumbering(origin_part_ids);
632  apf::removeTagFromDimension(m, weights, m->getDimension());
633  m->destroyTag(weights);
634  m->destroyNative();
635  apf::destroyMesh(m);
636  //only free PCU if it isn't being used outside
637  if (!pcu_outside)
638  PCU_Comm_Free();
639 }
640 
641 } // namespace Zoltan2
642 
643 #endif // HAVE_ZOLTAN2_PARMA
644 
645 #endif
#define Z2_FORWARD_EXCEPTIONS
Forward an exception back through call stack.
AlgParMA(const RCP< const Environment > &env, const RCP< const Comm< int > > &problemComm, const RCP< const BaseAdapter< user_t > > &adapter)
static ArrayRCP< ArrayRCP< zscalar_t > > weights
Defines the PartitioningSolution class.
Adapter::user_t user_t
Adapter::scalar_t scalar_t
Adapter::part_t part_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.
virtual void partition(const RCP< PartitioningSolution< Adapter > > &solution)
Partitioning method.
Traits class to handle conversions between gno_t/lno_t and TPL data types (e.g., ParMETIS&#39;s idx_t...
BaseAdapter defines methods required by all Adapters.
MeshEntityType
Enumerate entity types for meshes: Regions, Faces, Edges, or Vertices.
A gathering of useful namespace methods.