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 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 (elm)
205  num_ws = std::max(num_ws,adapter->getNumWeightsPerOf(entityAPFtoZ2(m->getDimension())));
206  apf::MeshTag* tag = m->createDoubleTag("parma_weight",num_ws);
207  if (vtx)
208  setEntWeights(0,tag);
209  if (edge)
210  setEntWeights(1,tag);
211  if (elm) {
212  setEntWeights(m->getDimension(),tag);
213  }
214  return tag;
215  }
216 
217 
218  //APF Mesh construction helper functions modified and placed here to support arbitrary entity types
219  void constructElements(const gno_t* conn, lno_t nelem, const lno_t* offsets,
220  const EntityTopologyType* tops, apf::GlobalToVert& globalToVert)
221  {
222  apf::ModelEntity* interior = m->findModelEntity(m->getDimension(), 0);
223  for (lno_t i = 0; i < nelem; ++i) {
224  apf::Mesh::Type etype = topologyZ2toAPF(tops[i]);
225  apf::Downward verts;
226  for (int j = offsets[i]; j < offsets[i+1]; ++j)
227  verts[j-offsets[i]] = globalToVert[conn[j]];
228  buildElement(m, interior, etype, verts);
229  }
230  }
231  int getMax(const apf::GlobalToVert& globalToVert)
232  {
233  int max = -1;
234  APF_CONST_ITERATE(apf::GlobalToVert, globalToVert, it)
235  max = std::max(max, it->first);
236  PCU_Max_Ints(&max, 1); // this is type-dependent
237  return max;
238  }
239  void constructResidence(apf::GlobalToVert& globalToVert)
240  {
241  int max = getMax(globalToVert);
242  int total = max + 1;
243  int peers = PCU_Comm_Peers();
244  int quotient = total / peers;
245  int remainder = total % peers;
246  int mySize = quotient;
247  int self = PCU_Comm_Self();
248  if (self == (peers - 1))
249  mySize += remainder;
250  typedef std::vector< std::vector<int> > TmpParts;
251  TmpParts tmpParts(mySize);
252  /* if we have a vertex, send its global id to the
253  broker for that global id */
254  PCU_Comm_Begin();
255  APF_ITERATE(apf::GlobalToVert, globalToVert, it) {
256  int gid = it->first;
257  int to = std::min(peers - 1, gid / quotient);
258  PCU_COMM_PACK(to, gid);
259  }
260  PCU_Comm_Send();
261  int myOffset = self * quotient;
262  /* brokers store all the part ids that sent messages
263  for each global id */
264  while (PCU_Comm_Receive()) {
265  int gid;
266  PCU_COMM_UNPACK(gid);
267  int from = PCU_Comm_Sender();
268  tmpParts.at(gid - myOffset).push_back(from);
269  }
270  /* for each global id, send all associated part ids
271  to all associated parts */
272  PCU_Comm_Begin();
273  for (int i = 0; i < mySize; ++i) {
274  std::vector<int>& parts = tmpParts[i];
275  for (size_t j = 0; j < parts.size(); ++j) {
276  int to = parts[j];
277  int gid = i + myOffset;
278  int nparts = parts.size();
279  PCU_COMM_PACK(to, gid);
280  PCU_COMM_PACK(to, nparts);
281  for (size_t k = 0; k < parts.size(); ++k)
282  PCU_COMM_PACK(to, parts[k]);
283  }
284  }
285  PCU_Comm_Send();
286  /* receiving a global id and associated parts,
287  lookup the vertex and classify it on the partition
288  model entity for that set of parts */
289  while (PCU_Comm_Receive()) {
290  int gid;
291  PCU_COMM_UNPACK(gid);
292  int nparts;
293  PCU_COMM_UNPACK(nparts);
294  apf::Parts residence;
295  for (int i = 0; i < nparts; ++i) {
296  int part;
297  PCU_COMM_UNPACK(part);
298  residence.insert(part);
299  }
300  apf::MeshEntity* vert = globalToVert[gid];
301  m->setResidence(vert, residence);
302  }
303  }
304 
305  /* given correct residence from the above algorithm,
306  negotiate remote copies by exchanging (gid,pointer)
307  pairs with parts in the residence of the vertex */
308  void constructRemotes(apf::GlobalToVert& globalToVert)
309  {
310  int self = PCU_Comm_Self();
311  PCU_Comm_Begin();
312  APF_ITERATE(apf::GlobalToVert, globalToVert, it) {
313  int gid = it->first;
314  apf::MeshEntity* vert = it->second;
315  apf::Parts residence;
316  m->getResidence(vert, residence);
317  APF_ITERATE(apf::Parts, residence, rit)
318  if (*rit != self) {
319  PCU_COMM_PACK(*rit, gid);
320  PCU_COMM_PACK(*rit, vert);
321  }
322  }
323  PCU_Comm_Send();
324  while (PCU_Comm_Receive()) {
325  int gid;
326  PCU_COMM_UNPACK(gid);
327  apf::MeshEntity* remote;
328  PCU_COMM_UNPACK(remote);
329  int from = PCU_Comm_Sender();
330  apf::MeshEntity* vert = globalToVert[gid];
331  m->addRemote(vert, from, remote);
332  }
333  }
334 
335 public:
336 
342  AlgParMA(const RCP<const Environment> &env__,
343  const RCP<const Comm<int> > &problemComm__,
344  const RCP<const IdentifierAdapter<user_t> > &adapter__)
345  {
346  throw std::runtime_error("ParMA needs a MeshAdapter but you haven't given it one");
347  }
348 
349  AlgParMA(const RCP<const Environment> &env__,
350  const RCP<const Comm<int> > &problemComm__,
351  const RCP<const VectorAdapter<user_t> > &adapter__)
352  {
353  throw std::runtime_error("ParMA needs a MeshAdapter but you haven't given it one");
354  }
355 
356  AlgParMA(const RCP<const Environment> &env__,
357  const RCP<const Comm<int> > &problemComm__,
358  const RCP<const GraphAdapter<user_t,userCoord_t> > &adapter__)
359  {
360  throw std::runtime_error("ParMA needs a MeshAdapter but you haven't given it one");
361  }
362 
363  AlgParMA(const RCP<const Environment> &env__,
364  const RCP<const Comm<int> > &problemComm__,
365  const RCP<const MatrixAdapter<user_t,userCoord_t> > &adapter__)
366  {
367  throw std::runtime_error("ParMA needs a MeshAdapter but you haven't given it one");
368 
369  }
370 
371  AlgParMA(const RCP<const Environment> &env__,
372  const RCP<const Comm<int> > &problemComm__,
373  const RCP<const MeshAdapter<user_t> > &adapter__) :
374  env(env__), problemComm(problemComm__), adapter(adapter__)
375  {
376  setMPIComm(problemComm__);
377 
378  //Setup PCU communications
379  //If PCU was already initialized outside (EX: for the APFMeshAdapter)
380  // we don't initialize it again.
381  pcu_outside=false;
382  if (!PCU_Comm_Initialized())
383  PCU_Comm_Init();
384  else
385  pcu_outside=true;
386  PCU_Switch_Comm(mpicomm);
387 
388  //Find the mesh dimension based on if there are any regions or faces in the part
389  // an all reduce is needed in case one part is empty (Ex: after hypergraph partitioning)
390  int dim;
391  if (adapter->getLocalNumOf(MESH_REGION)>0)
392  dim=3;
393  else if (adapter->getLocalNumOf(MESH_FACE)>0)
394  dim=2;
395  else
396  dim=0;
397  PCU_Max_Ints(&dim,1);
398  if (dim<2)
399  throw std::runtime_error("ParMA neeeds faces or region information");
400 
401  //GFD Currently not allowing ParMA to balance non element primary types
402  if (dim!=adapter->getPrimaryEntityType())
403  throw std::runtime_error("ParMA only supports balancing primary type==mesh element");
404 
405  //Create empty apf mesh
406  gmi_register_null();
407  gmi_model* g = gmi_load(".null");
408  enum MeshEntityType primary_type = entityAPFtoZ2(dim);
409  m = apf::makeEmptyMdsMesh(g,dim,false);
410 
411  //Get entity topology types
412  const EntityTopologyType* tops;
413  try {
414  adapter->getTopologyViewOf(primary_type,tops);
415  }
417 
418  //Get element global ids and part ids
419  const gno_t* element_gids;
420  const part_t* part_ids;
421  adapter->getIDsViewOf(primary_type,element_gids);
422  adapter->getPartsView(part_ids);
423  for (size_t i =0;i<adapter->getLocalNumOf(primary_type);i++)
424  mapping_elm_gids_index[element_gids[i]] = i;
425 
426  //get vertex global ids
427  const gno_t* vertex_gids;
428  adapter->getIDsViewOf(MESH_VERTEX,vertex_gids);
429 
430  //Get vertex coordinates
431  int c_dim = adapter->getDimension();
432  const scalar_t ** vertex_coords = new const scalar_t*[c_dim];
433  int* strides = new int[c_dim];
434  for (int i=0;i<c_dim;i++)
435  adapter->getCoordinatesViewOf(MESH_VERTEX,vertex_coords[i],strides[i],i);
436 
437  //Get first adjacencies from elements to vertices
438  if (!adapter->availAdjs(primary_type,MESH_VERTEX))
439  throw "APF needs adjacency information from elements to vertices";
440  const lno_t* offsets;
441  const gno_t* adjacent_vertex_gids;
442  adapter->getAdjsView(primary_type, MESH_VERTEX,offsets,adjacent_vertex_gids);
443 
444  //build the apf mesh
445  apf::GlobalToVert vertex_mapping;
446  apf::ModelEntity* interior = m->findModelEntity(m->getDimension(), 0);
447  for (size_t i=0;i<adapter->getLocalNumOf(MESH_VERTEX);i++) {
448  apf::MeshEntity* vtx = m->createVert_(interior);
449  scalar_t temp_coords[3];
450  for (int k=0;k<c_dim&&k<3;k++)
451  temp_coords[k] = vertex_coords[k][i*strides[k]];
452 
453  for (int k=c_dim;k<3;k++)
454  temp_coords[k] = 0;
455  apf::Vector3 point(temp_coords[0],temp_coords[1],temp_coords[2]);
456  m->setPoint(vtx,0,point);
457  vertex_mapping[vertex_gids[i]] = vtx;
458  }
459  //Call modified helper functions to build the mesh from element to vertex adjacency
460  constructElements(adjacent_vertex_gids, adapter->getLocalNumOf(primary_type), offsets, tops, vertex_mapping);
461  constructResidence(vertex_mapping);
462  constructRemotes(vertex_mapping);
463  stitchMesh(m);
464  m->acceptChanges();
465 
466 
467  //Setup numberings of global ids and original part ids
468  // for use after ParMA is run
469  apf::FieldShape* s = apf::getConstant(dim);
470  gids = apf::createNumbering(m,"global_ids",s,1);
471  origin_part_ids = apf::createNumbering(m,"origin",s,1);
472 
473  //number the global ids and original part ids
474  apf::MeshIterator* itr = m->begin(dim);
475  apf::MeshEntity* ent;
476  int i = 0;
477  while ((ent = m->iterate(itr))) {
478  apf::number(gids,ent,0,0,element_gids[i]);
479  apf::number(origin_part_ids,ent,0,0,PCU_Comm_Self());
480  i++;
481  }
482  m->end(itr);
483 
484  //final setup for apf mesh
485  apf::alignMdsRemotes(m);
486  apf::deriveMdsModel(m);
487  m->acceptChanges();
488  m->verify();
489 
490  //cleanup temp storage
491  delete [] vertex_coords;
492  delete [] strides;
493  }
494  void partition(const RCP<PartitioningSolution<Adapter> > &solution);
495 
496 };
497 
499 template <typename Adapter>
501  const RCP<PartitioningSolution<Adapter> > &solution
502 )
503 {
504  //Get parameters
505  std::string alg_name = "VtxElm";
506  double imbalance = 1.1;
507  double step = .5;
508  int ghost_layers=3;
509  int ghost_bridge=m->getDimension()-1;
510 
511  //Get the parameters for ParMA
512  const Teuchos::ParameterList &pl = env->getParameters();
513  try {
514  const Teuchos::ParameterList &ppl = pl.sublist("parma_parameters");
515  for (ParameterList::ConstIterator iter = ppl.begin();
516  iter != ppl.end(); iter++) {
517  const std::string &zname = pl.name(iter);
518  if (zname == "parma_method") {
519  std::string zval = pl.entry(iter).getValue(&zval);
520  alg_name = zval;
521  }
522  else if (zname == "step_size") {
523  double zval = pl.entry(iter).getValue(&zval);
524  step = zval;
525  }
526  else if (zname=="ghost_layers" || zname=="ghost_bridge") {
527  int zval = pl.entry(iter).getValue(&zval);
528  if (zname=="ghost_layers")
529  ghost_layers = zval;
530  else
531  ghost_bridge = zval;
532  }
533  }
534  }
535  catch (std::exception &e) {
536  //No parma_parameters sublist found
537  }
538 
539  const Teuchos::ParameterEntry *pe2 = pl.getEntryPtr("imbalance_tolerance");
540  if (pe2){
541  imbalance = pe2->getValue<double>(&imbalance);
542  }
543 
544  //booleans for which dimensions need weights
545  bool weightVertex,weightEdge,weightElement;
546  weightVertex=weightEdge=weightElement=false;
547 
548  //Build the selected balancer
549  apf::Balancer* balancer;
550  const int verbose = 1;
551  if (alg_name=="Vertex") {
552  balancer = Parma_MakeVtxBalancer(m, step, verbose);
553  weightVertex = true;
554  }
555  else if (alg_name=="Element") {
556  balancer = Parma_MakeElmBalancer(m, step, verbose);
557  weightElement=true;
558  }
559  else if (alg_name=="VtxElm") {
560  balancer = Parma_MakeVtxElmBalancer(m,step,verbose);
561  weightVertex = weightElement=true;
562  }
563  else if (alg_name=="VtxEdgeElm") {
564  balancer = Parma_MakeVtxEdgeElmBalancer(m, step, verbose);
565  weightVertex=weightEdge=weightElement=true;
566  }
567  else if (alg_name=="Ghost") {
568  balancer = Parma_MakeGhostDiffuser(m, ghost_layers, ghost_bridge, step, verbose);
569  weightVertex = true;
570  }
571  else if (alg_name=="Shape") {
572  balancer = Parma_MakeShapeOptimizer(m,step,verbose);
573  weightElement=true;
574  }
575  else if (alg_name=="Centroid") {
576  balancer = Parma_MakeCentroidDiffuser(m,step,verbose);
577  weightElement=true;
578  }
579  else {
580  throw std::runtime_error("No such parma method defined");
581  }
582 
583  //build the weights
584  apf::MeshTag* weights = setWeights(weightVertex,weightEdge,weightElement);
585 
586  //balance the apf mesh
587  balancer->balance(weights, imbalance);
588  delete balancer;
589 
590  // Load answer into the solution.
591  int num_local = adapter->getLocalNumOf(adapter->getPrimaryEntityType());
592  ArrayRCP<part_t> partList(new part_t[num_local], 0, num_local, true);
593 
594  //Setup for communication
595  PCU_Comm_Begin();
596  apf::MeshEntity* ent;
597  apf::MeshIterator* itr = m->begin(m->getDimension());
598  //Pack information back to each elements original owner
599  while ((ent=m->iterate(itr))) {
600  if (m->isOwned(ent)) {
601  part_t target_part_id = apf::getNumber(origin_part_ids,ent,0,0);
602  gno_t element_gid = apf::getNumber(gids,ent,0,0);
603  PCU_COMM_PACK(target_part_id,element_gid);
604  }
605  }
606  m->end(itr);
607 
608  //Send information off
609  PCU_Comm_Send();
610 
611  //Unpack information and set new part ids
612  while (PCU_Comm_Receive()) {
613  gno_t global_id;
614  PCU_COMM_UNPACK(global_id);
615  lno_t local_id = mapping_elm_gids_index[global_id];
616  part_t new_part_id = PCU_Comm_Sender();
617  partList[local_id] = new_part_id;
618  }
619  //construct partition solution
620  solution->setParts(partList);
621 
622  // Clean up
623  apf::destroyNumbering(gids);
624  apf::destroyNumbering(origin_part_ids);
625  apf::removeTagFromDimension(m, weights, m->getDimension());
626  m->destroyTag(weights);
627  m->destroyNative();
628  apf::destroyMesh(m);
629  //only free PCU if it isn't being used outside
630  if (!pcu_outside)
631  PCU_Comm_Free();
632 }
633 
634 } // namespace Zoltan2
635 
636 #endif // HAVE_ZOLTAN2_PARMA
637 
638 #endif
IdentifierAdapter defines the interface for identifiers.
#define Z2_FORWARD_EXCEPTIONS
Forward an exception back through call stack.
MatrixAdapter defines the adapter interface for matrices.
GraphAdapter defines the interface for graph-based user data.
AlgParMA(const RCP< const Environment > &env, const RCP< const Comm< int > > &problemComm, const RCP< const BaseAdapter< user_t > > &adapter)
MeshAdapter defines the interface for mesh input.
static ArrayRCP< ArrayRCP< zscalar_t > > weights
Defines the PartitioningSolution class.
Adapter::user_t user_t
Adapter::scalar_t scalar_t
A PartitioningSolution is a solution to a partitioning problem.
Adapter::part_t part_t
VectorAdapter defines the interface for vector input.
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.