Zoltan2
Loading...
Searching...
No Matches
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
19#include <map>
20#include <unordered_map>
21#include <vector>
22#include <string>
23#include <cassert>
24
25#ifndef HAVE_ZOLTAN2_PARMA
26
27namespace apf {
28 class Mesh;
29}
30namespace Zoltan2 {
31template <typename User>
32class APFMeshAdapter : public MeshAdapter<User>
33{
34public:
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>
54namespace Zoltan2 {
55
82template <typename User>
83 class APFMeshAdapter: public MeshAdapter<User> {
84
85public:
86
88 typedef typename InputTraits<User>::lno_t lno_t;
89 typedef typename InputTraits<User>::gno_t gno_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
350private:
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
415template <typename User>
416APFMeshAdapter<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}
682template <typename User>
683void 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
726template <typename User>
727void 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
737template <typename User>
738void 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
770template <typename User>
771void 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
819template <typename User>
820void 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
enum Zoltan2::EntityTopologyType topologyAPFtoZ2(enum apf::Mesh::Type ttype)
Zoltan2::BasicUserTypes< zscalar_t, zlno_t, zgno_t > user_t
Definition Metric.cpp:39
Defines the MeshAdapter interface.
This file defines the StridedData class.
APFMeshAdapter(const Comm< int > &comm, apf::Mesh *m, std::string primary, std::string adjacency, bool needSecondAdj=false)
typename BaseAdapter< User >::scalar_t scalar_t
typename InputTraits< User >::node_t node_t
typename InputTraits< User >::lno_t lno_t
typename InputTraits< User >::gno_t gno_t
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.
typename InputTraits< User >::part_t part_t
MeshAdapter defines the interface for mesh input.
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' optional entity weights.
virtual bool availAdjs(MeshEntityType source, MeshEntityType target) const
Returns whether a first adjacency combination is available.
virtual int getNumWeightsPerOf(MeshEntityType etype) const
Return the number of weights per entity.
virtual size_t getLocalNum2ndAdjs(MeshEntityType sourcetarget, MeshEntityType through) const
if avail2ndAdjs(), returns the number of second adjacencies on this process.
virtual void getTopologyViewOf(MeshEntityType etype, enum EntityTopologyType const *&Types) const
Provide a pointer to the entity topology types.
virtual int getDimension() const
Return dimension of the entity coordinates, if any.
virtual size_t getLocalNumOf(MeshEntityType etype) const =0
Returns the global number of mesh entities of MeshEntityType.
virtual size_t getLocalNumAdjs(MeshEntityType source, MeshEntityType target) const
Returns the number of first adjacencies on this process.
virtual void getIDsViewOf(MeshEntityType etype, gno_t const *&Ids) const =0
Provide a pointer to this process' identifiers.
virtual bool areEntityIDsUnique(MeshEntityType etype) const
Provide a pointer to the entity topology types.
virtual void getCoordinatesViewOf(MeshEntityType etype, const scalar_t *&coords, int &stride, int coordDim) const
Provide a pointer to one dimension of entity coordinates.
virtual void getAdjsView(MeshEntityType source, MeshEntityType target, const offset_t *&offsets, const gno_t *&adjacencyIds) const
Sets pointers to this process' mesh first adjacencies.
virtual bool avail2ndAdjs(MeshEntityType sourcetarget, MeshEntityType through) const
Returns whether a second adjacency combination is available. If combination is not available in the M...
enum MeshEntityType getPrimaryEntityType() const
Returns the entity to be partitioned, ordered, colored, etc.
virtual void get2ndAdjsView(MeshEntityType sourcetarget, MeshEntityType through, const offset_t *&offsets, const gno_t *&adjacencyIds) const
if avail2ndAdjs(), set pointers to this process' second adjacencies
map_t::local_ordinal_type lno_t
map_t::global_ordinal_type gno_t
Created by mbenlioglu on Aug 31, 2020.
EntityTopologyType
Enumerate entity topology types for meshes: points,lines,polygons,triangles,quadrilaterals,...
MeshEntityType
Enumerate entity types for meshes: Regions, Faces, Edges, or Vertices.
static ArrayRCP< ArrayRCP< zscalar_t > > weights
SparseMatrixAdapter_t::part_t part_t
default_offset_t offset_t
The data type to represent offsets.
default_gno_t gno_t
The ordinal type (e.g., int, long, int64_t) that can represent global counts and identifiers.
default_node_t node_t
The Kokkos node type. This is only meaningful for users of Tpetra objects.
default_lno_t lno_t
The ordinal type (e.g., int, long, int64_t) that represents local counts and local indices.
default_part_t part_t
The data type to represent part numbers.
default_scalar_t scalar_t
The data type for weights and coordinates.