Zoltan2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Zoltan2_APFMeshAdapter.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Zoltan2: A package of combinatorial algorithms for scientific computing
4 //
5 // Copyright 2012 NTESS and the Zoltan2 contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
14 #ifndef _ZOLTAN2_APFMESHADAPTER_HPP_
15 #define _ZOLTAN2_APFMESHADAPTER_HPP_
16 
17 #include <Zoltan2_MeshAdapter.hpp>
18 #include <Zoltan2_StridedData.hpp>
19 #include <map>
20 #include <unordered_map>
21 #include <vector>
22 #include <string>
23 #include <cassert>
24 
25 #ifndef HAVE_ZOLTAN2_PARMA
26 
27 namespace apf {
28  class Mesh;
29 }
30 namespace Zoltan2 {
31 template <typename User>
32 class APFMeshAdapter : public MeshAdapter<User>
33 {
34 public:
35 
36 
37  APFMeshAdapter(const Comm<int> &comm, apf::Mesh* m,std::string primary,std::string adjacency,bool needSecondAdj=false)
38  {
39  throw std::runtime_error(
40  "BUILD ERROR: ParMA requested but not compiled into Zoltan2.\n"
41  "Please set CMake flag Trilinos_ENABLE_SCOREC:BOOL=ON.");
42  }
43 };
44 }
45 #endif
46 
47 #ifdef HAVE_ZOLTAN2_PARMA
48 
49 #include <apfMesh.h>
50 #include <apfDynamicArray.h>
51 #include <apfNumbering.h>
52 #include <apfShape.h>
53 #include <PCU.h>
54 namespace Zoltan2 {
55 
82 template <typename User>
83  class APFMeshAdapter: public MeshAdapter<User> {
84 
85 public:
86 
87  typedef typename InputTraits<User>::scalar_t scalar_t;
88  typedef typename InputTraits<User>::lno_t lno_t;
89  typedef typename InputTraits<User>::gno_t gno_t;
90  typedef typename InputTraits<User>::offset_t offset_t;
91  typedef typename InputTraits<User>::part_t part_t;
92  typedef typename InputTraits<User>::node_t node_t;
93  typedef User user_t;
94 
107  APFMeshAdapter(const Comm<int> &comm, apf::Mesh* m,std::string primary,
108  std::string adjacency,bool needSecondAdj=false, int needs=0);
109 
110  void destroy();
111  void print(int me,int verbosity=0);
112  template <typename Adapter>
113  void applyPartitioningSolution(const User &in, User *&out,
114  const PartitioningSolution<Adapter> &solution) const{
115 
116  apf::Migration* plan = new apf::Migration(*out);
117  const part_t* new_part_ids = solution.getPartListView();
118 
119  if ((m_dimension==3 && this->getPrimaryEntityType()==MESH_REGION) ||
120  (m_dimension==2&&this->getPrimaryEntityType()==MESH_FACE)) {
121  //Elements can simply be sent to the given target parts
122  apf::MeshIterator* itr = (*out)->begin(m_dimension);
123  apf::MeshEntity* ent;
124  int i=0;
125  while ((ent=(*out)->iterate(itr))) {
126  assert(new_part_ids[i]<PCU_Comm_Peers());
127  plan->send(ent,new_part_ids[i]);
128  i++;
129  }
130  }
131  else {
132  //For non-element entities we have to select elements based on the non-element
133  // based Zoltan2 partition. We do this by sending the ith element to the part
134  // that will have the most of the elements downward entities.
135  int dim = entityZ2toAPF(this->getPrimaryEntityType());
136  apf::MeshIterator* itr = (*out)->begin(m_dimension);
137  apf::MeshEntity* ent;
138  size_t i=0;
139  while ((ent=(*out)->iterate(itr))) {
140  std::unordered_map<unsigned int,unsigned int> newOwners;
141  apf::Downward adj;
142  unsigned int max_num = 0;
143  int new_part=PCU_Comm_Self();
144  unsigned int num = in->getDownward(ent,dim,adj);
145  for (unsigned int j=0;j<num;j++) {
146  gno_t gid = apf::getNumber(gids[dim],apf::Node(adj[j],0));
147  lno_t lid = apf::getNumber(lids[dim],adj[j],0,0);
148  newOwners[new_part_ids[lid]]++;
149  if (newOwners[new_part_ids[lid]]>max_num) {
150  max_num=newOwners[new_part_ids[lid]];
151  new_part = new_part_ids[lid];
152  }
153  }
154  if (max_num>1)
155  if (new_part<0||new_part>=PCU_Comm_Peers()) {
156  std::cout<<new_part<<std::endl;
157  throw std::runtime_error("Target part is out of bounds\n");
158  }
159  plan->send(ent,new_part);
160  i++;
161  }
162 
163  }
164  (*out)->migrate(plan);
165  }
166 
168  // The MeshAdapter interface.
169  // This is the interface that would be called by a model or a problem .
171 
172  /* NOTE: Only elements are uniquely provided from the APF Mesh Adapter.
173  All other elements have copies across the shared parts
174  These copies can be joined by the sharing of a unique global id
175  getGlobalNumOf(type) != Sum(getLocalNumOf(type))
176  */
177  bool areEntityIDsUnique(MeshEntityType etype) const {
178  int dim = entityZ2toAPF(etype);
179  return dim==m_dimension;
180  }
181  size_t getLocalNumOf(MeshEntityType etype) const
182  {
183  int dim = entityZ2toAPF(etype);
184  if (dim<=m_dimension&&dim>=0)
185  return num_local[dim];
186  return 0;
187  }
188 
189  void getIDsViewOf(MeshEntityType etype, const gno_t *&Ids) const
190  {
191  int dim = entityZ2toAPF(etype);
192  if (dim<=m_dimension&&dim>=0)
193  Ids = gid_mapping[dim];
194  else
195  Ids = NULL;
196  }
197 
199  enum EntityTopologyType const *&Types) const {
200  int dim = entityZ2toAPF(etype);
201  if (dim<=m_dimension&&dim>=0)
202  Types = topologies[dim];
203  else
204  Types = NULL;
205  }
206 
207  int getNumWeightsPerOf(MeshEntityType etype) const {
208  int dim = entityZ2toAPF(etype);
209  return static_cast<int>(weights[dim].size());
210 }
211 
212  void getWeightsViewOf(MeshEntityType etype, const scalar_t *&ws,
213  int &stride, int idx = 0) const
214  {
215  int dim = entityZ2toAPF(etype);
216  typename map_array_t::iterator itr = weights[dim].find(idx);
217  if (itr!=weights[dim].end()) {
218  ws = &(*(itr->second.first));
219  stride = itr->second.second;
220  }
221  else {
222  ws = NULL;
223  stride = 0;
224  }
225  }
226 
227  int getDimension() const { return coord_dimension; }
228 
229  void getCoordinatesViewOf(MeshEntityType etype, const scalar_t *&coords,
230  int &stride, int coordDim) const {
231  if (coordDim>=0 && coordDim<3) {
232  int dim = entityZ2toAPF(etype);
233  if (dim<=m_dimension&&dim>=0) {
234  coords = ent_coords[dim]+coordDim;
235  stride = 3;
236  }
237  else {
238  coords = NULL;
239  stride = 0;
240  }
241  }
242  else {
243  coords = NULL;
244  stride = 0;
245  }
246  }
247 
248  bool availAdjs(MeshEntityType source, MeshEntityType target) const {
249  int dim_source = entityZ2toAPF(source);
250  int dim_target = entityZ2toAPF(target);
251  return dim_source<=m_dimension && dim_source>=0 &&
252  dim_target<=m_dimension && dim_target>=0 &&
253  dim_target!=dim_source&&
254  has(dim_source) && has(dim_target);
255  }
256 
257  size_t getLocalNumAdjs(MeshEntityType source, MeshEntityType target) const
258  {
259  int dim_source = entityZ2toAPF(source);
260  int dim_target = entityZ2toAPF(target);
261  if (availAdjs(source,target))
262  return adj_gids[dim_source][dim_target].size();
263  return 0;
264  }
265 
266  void getAdjsView(MeshEntityType source, MeshEntityType target,
267  const offset_t *&offsets, const gno_t *& adjacencyIds) const
268  {
269  int dim_source = entityZ2toAPF(source);
270  int dim_target = entityZ2toAPF(target);
271  if (availAdjs(source,target)) {
272  offsets = adj_offsets[dim_source][dim_target];
273  adjacencyIds = &(adj_gids[dim_source][dim_target][0]);
274  }
275  else {
276  offsets=NULL;
277  adjacencyIds = NULL;
278  }
279  }
280  //TODO:: some pairings of the second adjacencies do not include off processor adjacencies.
281  // one such pairing is the edge through vertex second adjacnecies.
282  //#define USE_MESH_ADAPTER
283 #ifndef USE_MESH_ADAPTER
284  bool avail2ndAdjs(MeshEntityType sourcetarget, MeshEntityType through) const
285  {
286  if (adj2_gids==NULL)
287  return false;
288  int dim_source = entityZ2toAPF(sourcetarget);
289  int dim_target = entityZ2toAPF(through);
290  if (dim_source==1&&dim_target==0)
291  return false;
292  return dim_source<=m_dimension && dim_source>=0 &&
293  dim_target<=m_dimension && dim_target>=0 &&
294  dim_target!=dim_source &&
295  has(dim_source)&&has(dim_target);
296  }
297 
298  size_t getLocalNum2ndAdjs(MeshEntityType sourcetarget,
299  MeshEntityType through) const
300  {
301  int dim_source = entityZ2toAPF(sourcetarget);
302  int dim_target = entityZ2toAPF(through);
303  if (avail2ndAdjs(sourcetarget,through))
304  return adj2_gids[dim_source][dim_target].size();
305  return 0;
306 
307  }
308 
309  void get2ndAdjsView(MeshEntityType sourcetarget, MeshEntityType through,
310  const offset_t *&offsets, const gno_t *&adjacencyIds) const
311  {
312  int dim_source = entityZ2toAPF(sourcetarget);
313  int dim_target = entityZ2toAPF(through);
314  if (avail2ndAdjs(sourcetarget,through)) {
315  offsets=adj2_offsets[dim_source][dim_target];
316  adjacencyIds=&(adj2_gids[dim_source][dim_target][0]);
317  }
318 
319  }
320 #endif
321 
335  void setWeights(MeshEntityType etype, const scalar_t *val, int stride, int idx=0);
336 
348  void setWeights(MeshEntityType etype, apf::Mesh* m,apf::MeshTag* weights, int* ids=NULL);
349 
350 private:
355  bool has(int dim) const {return (entity_needs>>dim)%2;}
356 
357  // provides a conversion from the mesh entity type to the apf dimension
358  int entityZ2toAPF(enum MeshEntityType etype) const {return static_cast<int>(etype);}
359 
360  // provides a conversion from the apf topology type to the Zoltan2 topology type
361  enum EntityTopologyType topologyAPFtoZ2(enum apf::Mesh::Type ttype) const {
362  if (ttype==apf::Mesh::VERTEX)
363  return POINT;
364  else if (ttype==apf::Mesh::EDGE)
365  return LINE_SEGMENT;
366  else if (ttype==apf::Mesh::TRIANGLE)
367  return TRIANGLE;
368  else if (ttype==apf::Mesh::QUAD)
369  return QUADRILATERAL;
370  else if (ttype==apf::Mesh::TET)
371  return TETRAHEDRON;
372  else if (ttype==apf::Mesh::HEX)
373  return HEXAHEDRON;
374  else if (ttype==apf::Mesh::PRISM)
375  return PRISM;
376  else if (ttype==apf::Mesh::PYRAMID)
377  return PYRAMID;
378  else
379  throw "No such APF topology type";
380 
381  }
382 
383  // provides a conversion from the mesh tag type to scalar_t since mesh tags are not templated
384  void getTagWeight(apf::Mesh* m, apf::MeshTag* tag,apf::MeshEntity* ent, scalar_t* ws);
385 
386 
387  int m_dimension; //Dimension of the mesh
388 
389  //An int between 0 and 15 that represents the mesh dimensions that are constructed
390  // in binary. A 1 in the ith digit corresponds to the ith dimension being constructed
391  // Ex: 9 = 1001 is equivalent to regions and vertices are needed
392  int entity_needs;
393  apf::Numbering** lids; //[dimension] numbering of local id numbers
394  apf::GlobalNumbering** gids;//[dimension] numbering of global id numbers
395  gno_t** gid_mapping; //[dimension][lid] corresponding global id numbers
396  size_t* num_local; //[dimension] number of local entities
397  EntityTopologyType** topologies; //[dimension] topologies for each entity
398  offset_t*** adj_offsets; //[first_dimension][second_dimension] array of offsets
399  std::vector<gno_t>** adj_gids; //[first_dimension][second_dimension] global_ids of first adjacencies
400  offset_t*** adj2_offsets; //[first_dimension][second_dimension] array of offsets for second adjacencies
401  std::vector<gno_t>** adj2_gids; //[first_dimension][second_dimension] global_ids of second adjacencies
402  int coord_dimension; //dimension of coordinates (always 3 for APF)
403  scalar_t** ent_coords; //[dimension] array of coordinates [xs ys zs]
404 
405  //[dimension][id] has the start of the weights array and the stride
406  typedef std::unordered_map<int, std::pair<ArrayRCP<const scalar_t>, int> > map_array_t;
407  map_array_t* weights;
408 
409 };
410 
412 // Definitions
414 
415 template <typename User>
416 APFMeshAdapter<User>::APFMeshAdapter(const Comm<int> &comm,
417  apf::Mesh* m,
418  std::string primary,
419  std::string adjacency,
420  bool needSecondAdj,
421  int needs) {
422 
423  //get the mesh dimension
424  m_dimension = m->getDimension();
425 
426  //get the dimensions that are needed to be constructed
427  entity_needs = needs;
428 
429  //Make the primary and adjacency entity types
430  //choices are region, face, edge, vertex
431  //element is a shortcut to mean the mesh dimension entity type
432  //region will throw an error on 2D meshes
433  if (primary=="element") {
434  if (m_dimension==2)
435  primary="face";
436  else
437  primary="region";
438  }
439  if (adjacency=="element") {
440  if (m_dimension==2)
441  adjacency="face";
442  else
443  adjacency="region";
444  }
445  if (primary=="region"&&m_dimension<3)
446  throw std::runtime_error("primary type and mesh dimension mismatch");
447  if (adjacency=="region"&&m_dimension<3)
448  throw std::runtime_error("adjacency type and mesh dimension mismatch");
449  this->setEntityTypes(primary,adjacency,adjacency);
450 
451  //setup default needs such that primary and adjacency types are always constructed
452  int dim1 = entityZ2toAPF(this->getPrimaryEntityType());
453  int dim2 = entityZ2toAPF(this->getAdjacencyEntityType());
454  int new_needs=0;
455  new_needs+=1<<dim1;
456  new_needs+=1<<dim2;
457  entity_needs|=new_needs;
458 
459  //count the local and global numbers as well as assign ids and map local to global
460  lids = new apf::Numbering*[m_dimension+1];
461  gids = new apf::GlobalNumbering*[m_dimension+1];
462  gid_mapping = new gno_t*[m_dimension+1];
463  std::unordered_map<gno_t,lno_t>* lid_mapping = new std::unordered_map<gno_t,lno_t>[m_dimension+1];
464  num_local = new size_t[m_dimension+1];
465  topologies = new EntityTopologyType*[m_dimension+1];
466 
467  for (int i=0;i<=m_dimension;i++) {
468  num_local[i]=0;
469 
470  topologies[i] = NULL;
471  gid_mapping[i] = NULL;
472  if (!has(i))
473  continue;
474  //number of local and global entities
475  num_local[i] = m->count(i);
476  long global_count = countOwned(m,i);
477  PCU_Add_Longs(&global_count,1);
478 
479 
480  //Number each entity with local and global numbers
481  char lids_name[15];
482  sprintf(lids_name,"lids%d",i);
483  char gids_name[15];
484  sprintf(gids_name,"ids%d",i);
485  apf::FieldShape* shape = apf::getConstant(i);
486  lids[i] = apf::createNumbering(m,lids_name,shape,1);
487  apf::Numbering* tmp = apf::numberOwnedDimension(m,gids_name,i);
488  gids[i] = apf::makeGlobal(tmp);
489  apf::synchronize(gids[i]);
490  apf::MeshIterator* itr = m->begin(i);
491  apf::MeshEntity* ent;
492  unsigned int num=0;
493  while ((ent=m->iterate(itr))) {
494  apf::number(lids[i],ent,0,0,num);
495  lid_mapping[i][apf::getNumber(gids[i],apf::Node(ent,0))]=num;
496  num++;
497  }
498  m->end(itr);
499  assert(num==num_local[i]);
500 
501  //Make a mapping from local to global
502  //While we are at it take the topology types
503  gid_mapping[i] = new gno_t[num_local[i]];
504  topologies[i] = new EntityTopologyType[num_local[i]];
505  apf::DynamicArray<apf::Node> nodes;
506  itr = m->begin(i);
507  num=0;
508  while((ent=m->iterate(itr))) {
509  gno_t gid = apf::getNumber(gids[i],apf::Node(ent,0));
510  gid_mapping[i][ apf::getNumber(lids[i],ent,0,0)] = gid;
511  topologies[i][num] = topologyAPFtoZ2(m->getType(ent));
512  num++;
513  }
514  m->end(itr);
515 
516 
517  }
518  //First Adjacency and Second Adjacency data
519  adj_gids = new std::vector<gno_t>*[m_dimension+1];
520  adj_offsets = new offset_t**[m_dimension+1];
521  if (needSecondAdj) {
522  adj2_gids = new std::vector<gno_t>*[m_dimension+1];
523  adj2_offsets = new offset_t**[m_dimension+1];
524  }
525  else {
526  adj2_gids=NULL;
527  adj2_offsets=NULL;
528  }
529  for (int i=0;i<=m_dimension;i++) {
530  adj_gids[i]=NULL;
531  adj_offsets[i]=NULL;
532  if (needSecondAdj) {
533  adj2_gids[i]=NULL;
534  adj2_offsets[i]=NULL;
535  }
536  if (!has(i))
537  continue;
538  adj_gids[i] = new std::vector<gno_t>[m_dimension+1];
539  adj_offsets[i] = new offset_t*[m_dimension+1];
540  if (needSecondAdj) {
541  adj2_gids[i] = new std::vector<gno_t>[m_dimension+1];
542  adj2_offsets[i] = new offset_t*[m_dimension+1];
543  }
544  for (int j=0;j<=m_dimension;j++) {
545 
546  if (i==j||!has(j)) {
547  adj_offsets[i][j]=NULL;
548  if (needSecondAdj)
549  adj2_offsets[i][j]=NULL;
550  continue;
551  }
552 
553  //Loop through each entity
554  apf::MeshIterator* itr = m->begin(i);
555  apf::MeshEntity* ent;
556 
557  adj_offsets[i][j] = new offset_t[num_local[i]+1];
558  adj_offsets[i][j][0] =0;
559  if (needSecondAdj) {
560  adj2_offsets[i][j] = new offset_t[num_local[i]+1];
561  adj2_offsets[i][j][0] =0;
562  }
563  int k=1;
564 
565  //We need communication for second adjacency
566  if (needSecondAdj)
567  PCU_Comm_Begin();
568  std::unordered_map<gno_t,apf::MeshEntity*> part_boundary_mapping;
569 
570  while ((ent=m->iterate(itr))) {
571  std::set<gno_t> temp_adjs; //temp storage for second adjacency
572  //Get First Adjacency
573  apf::Adjacent adj;
574  m->getAdjacent(ent,j,adj);
575  for (unsigned int l=0;l<adj.getSize();l++) {
576  adj_gids[i][j].push_back(apf::getNumber(gids[j],apf::Node(adj[l],0)));
577  //Now look at Second Adjacency
578  if (needSecondAdj) {
579  apf::Adjacent adj2;
580  m->getAdjacent(adj[l],i,adj2);
581  for (unsigned int o=0;o<adj2.getSize();o++)
582  temp_adjs.insert(apf::getNumber(gids[i],apf::Node(adj2[o],0)));
583  if (i==m_dimension) {
584  apf::Parts res;
585  m->getResidence(adj[l],res);
586 
587  part_boundary_mapping[apf::getNumber(gids[j],apf::Node(adj[l],0))] = adj[l];
588  for (apf::Parts::iterator it=res.begin();it!=res.end();it++) {
589  gno_t send_vals[2];
590  send_vals[1]=apf::getNumber(gids[i],apf::Node(ent,0));
591  send_vals[0]=apf::getNumber(gids[j],apf::Node(adj[l],0));
592 
593  PCU_Comm_Pack(*it,send_vals,2*sizeof(gno_t));
594  }
595  }
596  }
597  }
598  adj_offsets[i][j][k] = adj_gids[i][j].size();
599  k++;
600  //Copy over local second adjacencies to copies
601  if (needSecondAdj && i!=m_dimension) {
602  apf::Parts res;
603  m->getResidence(ent,res);
604  typename std::set<gno_t>::iterator adj_itr;
605  for (adj_itr=temp_adjs.begin();adj_itr!=temp_adjs.end();adj_itr++) {
606  for (apf::Parts::iterator it=res.begin();it!=res.end();it++) {
607  gno_t send_vals[2];
608  send_vals[0]=apf::getNumber(gids[i],apf::Node(ent,0));
609  send_vals[1] = *adj_itr;
610  if (send_vals[0]!=send_vals[1])
611  PCU_Comm_Pack(*it,send_vals,2*sizeof(gno_t));
612  }
613  }
614  }
615  }
616  m->end(itr);
617  if (needSecondAdj) {
618  //Now capture mesh wide second adjacency locally
619  PCU_Comm_Send();
620  std::set<gno_t>* adjs2 = new std::set<gno_t>[num_local[i]];
621  while (PCU_Comm_Receive()) {
622  gno_t adj2[2];
623  PCU_Comm_Unpack(adj2,2*sizeof(gno_t));
624 
625  if (i==m_dimension) {
626  apf::MeshEntity* through = part_boundary_mapping[adj2[0]];
627  apf::Adjacent adj;
628  m->getAdjacent(through,i,adj);
629  for (unsigned int l=0;l<adj.getSize();l++) {
630  if (apf::getNumber(gids[i],apf::Node(adj[l],0))!=adj2[1])
631  adjs2[apf::getNumber(lids[i],adj[l],0,0)].insert(adj2[1]);
632  }
633  }
634  else {
635  lno_t index = lid_mapping[i][adj2[0]];
636  adjs2[index].insert(adj2[1]);
637  }
638  }
639  //And finally convert the second adjacency to a vector to be returned to user
640  for (size_t l=0;l<num_local[i];l++) {
641  for (typename std::set<gno_t>::iterator sitr = adjs2[l].begin();sitr!=adjs2[l].end();sitr++) {
642  adj2_gids[i][j].push_back(*sitr);
643  }
644  adj2_offsets[i][j][l+1]=adj2_gids[i][j].size();
645  }
646  }
647  }
648  }
649  //Coordinates
650  coord_dimension = 3;
651  ent_coords = new scalar_t*[m_dimension+1];
652  for (int i=0;i<=m_dimension;i++) {
653  ent_coords[i] = NULL;
654  if (!has(i))
655  continue;
656  apf::MeshIterator* itr = m->begin(i);
657  apf::MeshEntity* ent;
658  ent_coords[i] = new scalar_t[3*num_local[i]];
659  int j=0;
660  while((ent=m->iterate(itr))) {
661  apf::Vector3 point;
662  if (i==0) {
663  m->getPoint(ent,0,point);
664  }
665  else {
666  point = apf::getLinearCentroid(m,ent);
667  }
668  for (int k=0;k<3;k++)
669  ent_coords[i][j*3+k] = point[k];
670  j++;
671  }
672  m->end(itr);
673  }
674 
675  //Just make the weights array with nothing in it for now
676  //It will be filled by calls to setWeights(...)
677  weights = new map_array_t[m_dimension+1];
678 
679  //cleanup
680  delete [] lid_mapping;
681 }
682 template <typename User>
683 void APFMeshAdapter<User>::destroy() {
684  //So that we can't destory the adapter twice
685  if (m_dimension==-1)
686  return;
687  for (int i=0;i<=m_dimension;i++) {
688  if (!has(i))
689  continue;
690  delete [] ent_coords[i];
691  delete [] adj_gids[i];
692  if (adj2_gids)
693  delete [] adj2_gids[i];
694  for (int j=0;j<=m_dimension;j++) {
695  if (!has(j))
696  continue;
697  if (i!=j) {
698  delete [] adj_offsets[i][j];
699  if (adj2_gids)
700  delete [] adj2_offsets[i][j];
701  }
702  }
703  if (adj2_gids)
704  delete [] adj2_offsets[i];
705  delete [] adj_offsets[i];
706  delete [] gid_mapping[i];
707  apf::destroyGlobalNumbering(gids[i]);
708  apf::destroyNumbering(lids[i]);
709  }
710  delete [] ent_coords;
711  delete [] adj_gids;
712  delete [] adj_offsets;
713  if (adj2_gids) {
714  delete [] adj2_gids;
715  delete [] adj2_offsets;
716  }
717  delete [] gid_mapping;
718  delete [] gids;
719  delete [] lids;
720  delete [] num_local;
721  delete [] weights;
722  //Set the mesh dimension to -1 so that no operations can be done on the destroyed adapter
723  m_dimension=-1;
724 }
725 
726 template <typename User>
727 void APFMeshAdapter<User>::setWeights(MeshEntityType etype, const scalar_t *val, int stride, int idx) {
728  int dim = entityZ2toAPF(etype);
729  if (dim>m_dimension||!has(dim)) {
730  throw std::runtime_error("Cannot add weights to non existing dimension");
731  }
732  ArrayRCP<const scalar_t> weight_rcp(val,0,stride*getLocalNumOf(etype),false);
733  weights[dim][idx] =std::make_pair(weight_rcp,stride);
734 }
735 
736 //Simple helper function to convert the tag type to the scalar_t type
737 template <typename User>
738 void APFMeshAdapter<User>::getTagWeight(apf::Mesh* m,
739  apf::MeshTag* tag,
740  apf::MeshEntity* ent,
741  scalar_t* ws) {
742  int size = m->getTagSize(tag);
743  int type = m->getTagType(tag);
744  if (type==apf::Mesh::DOUBLE) {
745  double* w = new double[size];
746  m->getDoubleTag(ent,tag,w);
747  for (int i=0;i<size;i++)
748  ws[i] = static_cast<scalar_t>(w[i]);
749  delete [] w;
750  }
751  else if (type==apf::Mesh::INT) {
752  int* w = new int[size];
753  m->getIntTag(ent,tag,w);
754  for (int i=0;i<size;i++)
755  ws[i] = static_cast<scalar_t>(w[i]);
756  delete [] w;
757  }
758  else if (type==apf::Mesh::LONG) {
759  long* w = new long[size];
760  m->getLongTag(ent,tag,w);
761  for (int i=0;i<size;i++)
762  ws[i] = static_cast<scalar_t>(w[i]);
763  delete [] w;
764  }
765  else {
766  throw std::runtime_error("Unrecognized tag type");
767  }
768 }
769 
770 template <typename User>
771 void APFMeshAdapter<User>::setWeights(MeshEntityType etype, apf::Mesh* m,apf::MeshTag* tag, int* ids) {
772  int dim = entityZ2toAPF(etype);
773  if (dim>m_dimension||!has(dim)) {
774  throw std::runtime_error("Cannot add weights to non existing dimension");
775  }
776  int n_weights = m->getTagSize(tag);
777  bool delete_ids = false;
778  if (ids==NULL) {
779  ids = new int[n_weights];
780  delete_ids=true;
781  for (int i=0;i<n_weights;i++)
782  ids[i] = i;
783  }
784  scalar_t* ones = new scalar_t[n_weights];
785  for (int i=0;i<n_weights;i++)
786  ones[i] = 1;
787 
788  scalar_t* ws = new scalar_t[num_local[dim]*n_weights];
789  apf::MeshIterator* itr = m->begin(dim);
790  apf::MeshEntity* ent;
791  int j=0;
792  while ((ent=m->iterate(itr))) {
793  scalar_t* w;
794  if (m->hasTag(ent,tag)) {
795  w = new scalar_t[n_weights];
796  getTagWeight(m,tag,ent,w);
797  }
798  else
799  w = ones;
800 
801  for (int i=0;i<n_weights;i++) {
802  ws[i*getLocalNumOf(etype)+j] = w[i];
803  }
804  j++;
805 
806  if (m->hasTag(ent,tag))
807  delete [] w;
808  }
809  for (int i=0;i<n_weights;i++) {
810  ArrayRCP<const scalar_t> weight_rcp(ws+i*getLocalNumOf(etype),0,getLocalNumOf(etype),i==0);
811  weights[dim][ids[i]] =std::make_pair(weight_rcp,1);
812  }
813 
814  if (delete_ids)
815  delete [] ids;
816  delete [] ones;
817 }
818 
819 template <typename User>
820 void APFMeshAdapter<User>::print(int me,int verbosity)
821 {
822  if (m_dimension==-1) {
823  std::cout<<"Cannot print destroyed mesh adapter\n";
824  return;
825  }
826 
827  std::string fn(" APFMesh ");
828  std::cout << me << fn
829  << " dimension = " << m_dimension
830  << std::endl;
831  if (verbosity==0)
832  return;
833  for (int i=0;i<=m_dimension;i++) {
834  if (!has(i))
835  continue;
836  std::cout<<me<<" Number of dimension " << i<< " = " <<num_local[i] <<std::endl;
837  if (verbosity>=1) {
838  for (size_t j=0;j<num_local[i];j++) {
839  std::cout<<" Entity "<<gid_mapping[i][j]<<"("<<j<<"):\n";
840  for (int k=0;k<=m_dimension;k++) {
841  if (!has(k))
842  continue;
843  if (k==i)
844  continue;
845  std::cout<<" First Adjacency of Dimension "<<k<<":";
846  for (offset_t l=adj_offsets[i][k][j];l<adj_offsets[i][k][j+1];l++)
847  std::cout<<" "<<adj_gids[i][k][l];
848  std::cout<<"\n";
849  if (verbosity>=3) {
850  std::cout<<" Second Adjacency through Dimension "<<k<<":";
851  for (offset_t l=adj2_offsets[i][k][j];l<adj2_offsets[i][k][j+1];l++)
852  std::cout<<" "<<adj2_gids[i][k][l];
853  std::cout<<"\n";
854  }
855  }
856  }
857  }
858  }
859 }
860 
861 
862 
863 } //namespace Zoltan2
864 
865 #endif //HAVE_ZOLTAN2_PARMA
866 
867 #endif
virtual void getAdjsView(MeshEntityType source, MeshEntityType target, const offset_t *&offsets, const gno_t *&adjacencyIds) const
Sets pointers to this process&#39; mesh first adjacencies.
APFMeshAdapter(const Comm< int > &comm, apf::Mesh *m, std::string primary, std::string adjacency, bool needSecondAdj=false)
virtual bool areEntityIDsUnique(MeshEntityType etype) const
Provide a pointer to the entity topology types.
virtual bool availAdjs(MeshEntityType source, MeshEntityType target) const
Returns whether a first adjacency combination is available.
static ArrayRCP< ArrayRCP< zscalar_t > > weights
Defines the MeshAdapter interface.
MeshAdapter defines the interface for mesh input.
virtual size_t getLocalNumOf(MeshEntityType etype) const =0
Returns the global number of mesh entities of MeshEntityType.
map_t::global_ordinal_type gno_t
Definition: mapRemotes.cpp:27
virtual void getWeightsViewOf(MeshEntityType etype, const scalar_t *&weights, int &stride, int idx=0) const
Provide a pointer to one of the number of this process&#39; optional entity weights.
virtual bool avail2ndAdjs(MeshEntityType sourcetarget, MeshEntityType through) const
Returns whether a second adjacency combination is available. If combination is not available in the M...
typename Zoltan2::InputTraits< ztcrsmatrix_t >::node_t node_t
virtual void get2ndAdjsView(MeshEntityType sourcetarget, MeshEntityType through, const offset_t *&offsets, const gno_t *&adjacencyIds) const
if avail2ndAdjs(), set pointers to this process&#39; second adjacencies
virtual int getDimension() const
Return dimension of the entity coordinates, if any.
typename InputTraits< User >::part_t part_t
SparseMatrixAdapter_t::part_t part_t
virtual size_t getLocalNum2ndAdjs(MeshEntityType sourcetarget, MeshEntityType through) const
if avail2ndAdjs(), returns the number of second adjacencies on this process.
typename InputTraits< User >::node_t node_t
virtual void getIDsViewOf(MeshEntityType etype, gno_t const *&Ids) const =0
Provide a pointer to this process&#39; identifiers.
virtual void getCoordinatesViewOf(MeshEntityType etype, const scalar_t *&coords, int &stride, int coordDim) const
Provide a pointer to one dimension of entity coordinates.
typename InputTraits< User >::gno_t gno_t
virtual size_t getLocalNumAdjs(MeshEntityType source, MeshEntityType target) const
Returns the number of first adjacencies on this process.
map_t::local_ordinal_type lno_t
Definition: mapRemotes.cpp:26
EntityTopologyType
Enumerate entity topology types for meshes: points,lines,polygons,triangles,quadrilaterals, polyhedrons, tetrahedrons, hexhedrons, prisms, or pyramids.
enum Zoltan2::EntityTopologyType topologyAPFtoZ2(enum apf::Mesh::Type ttype)
typename InputTraits< User >::offset_t offset_t
void applyPartitioningSolution(const User &in, User *&out, const PartitioningSolution< Adapter > &solution) const
Apply a PartitioningSolution to an input.
MeshEntityType
Enumerate entity types for meshes: Regions, Faces, Edges, or Vertices.
virtual int getNumWeightsPerOf(MeshEntityType etype) const
Return the number of weights per entity.
virtual void getTopologyViewOf(MeshEntityType etype, enum EntityTopologyType const *&Types) const
Provide a pointer to the entity topology types.
typename BaseAdapter< User >::scalar_t scalar_t
enum MeshEntityType getPrimaryEntityType() const
Returns the entity to be partitioned, ordered, colored, etc.
typename InputTraits< User >::lno_t lno_t
Vector::node_type Node
Definition: coloring1.cpp:46
This file defines the StridedData class.
Zoltan2::BasicUserTypes< zscalar_t, zlno_t, zgno_t > user_t
Definition: Metric.cpp:39