14 #ifndef _ZOLTAN2_APFMESHADAPTER_HPP_
15 #define _ZOLTAN2_APFMESHADAPTER_HPP_
20 #include <unordered_map>
25 #ifndef HAVE_ZOLTAN2_PARMA
31 template <
typename User>
37 APFMeshAdapter(
const Comm<int> &comm, apf::Mesh* m,std::string primary,std::string adjacency,
bool needSecondAdj=
false)
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.");
47 #ifdef HAVE_ZOLTAN2_PARMA
50 #include <apfDynamicArray.h>
51 #include <apfNumbering.h>
82 template <
typename User>
83 class APFMeshAdapter:
public MeshAdapter<User> {
87 typedef typename InputTraits<User>::scalar_t
scalar_t;
90 typedef typename InputTraits<User>::offset_t
offset_t;
107 APFMeshAdapter(
const Comm<int> &comm, apf::Mesh* m,std::string primary,
108 std::string adjacency,
bool needSecondAdj=
false,
int needs=0);
111 void print(
int me,
int verbosity=0);
112 template <
typename Adapter>
114 const PartitioningSolution<Adapter> &solution)
const{
116 apf::Migration* plan =
new apf::Migration(*out);
117 const part_t* new_part_ids = solution.getPartListView();
122 apf::MeshIterator* itr = (*out)->begin(m_dimension);
123 apf::MeshEntity* ent;
125 while ((ent=(*out)->iterate(itr))) {
126 assert(new_part_ids[i]<PCU_Comm_Peers());
127 plan->send(ent,new_part_ids[i]);
136 apf::MeshIterator* itr = (*out)->begin(m_dimension);
137 apf::MeshEntity* ent;
139 while ((ent=(*out)->iterate(itr))) {
140 std::unordered_map<unsigned int,unsigned int> newOwners;
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++) {
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];
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");
159 plan->send(ent,new_part);
164 (*out)->migrate(plan);
178 int dim = entityZ2toAPF(etype);
179 return dim==m_dimension;
183 int dim = entityZ2toAPF(etype);
184 if (dim<=m_dimension&&dim>=0)
185 return num_local[dim];
191 int dim = entityZ2toAPF(etype);
192 if (dim<=m_dimension&&dim>=0)
193 Ids = gid_mapping[dim];
200 int dim = entityZ2toAPF(etype);
201 if (dim<=m_dimension&&dim>=0)
202 Types = topologies[dim];
208 int dim = entityZ2toAPF(etype);
209 return static_cast<int>(
weights[dim].size());
213 int &stride,
int idx = 0)
const
215 int dim = entityZ2toAPF(etype);
216 typename map_array_t::iterator itr =
weights[dim].find(idx);
218 ws = &(*(itr->second.first));
219 stride = itr->second.second;
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;
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);
259 int dim_source = entityZ2toAPF(source);
260 int dim_target = entityZ2toAPF(target);
262 return adj_gids[dim_source][dim_target].size();
269 int dim_source = entityZ2toAPF(source);
270 int dim_target = entityZ2toAPF(target);
272 offsets = adj_offsets[dim_source][dim_target];
273 adjacencyIds = &(adj_gids[dim_source][dim_target][0]);
283 #ifndef USE_MESH_ADAPTER
288 int dim_source = entityZ2toAPF(sourcetarget);
289 int dim_target = entityZ2toAPF(through);
290 if (dim_source==1&&dim_target==0)
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);
301 int dim_source = entityZ2toAPF(sourcetarget);
302 int dim_target = entityZ2toAPF(through);
304 return adj2_gids[dim_source][dim_target].size();
312 int dim_source = entityZ2toAPF(sourcetarget);
313 int dim_target = entityZ2toAPF(through);
315 offsets=adj2_offsets[dim_source][dim_target];
316 adjacencyIds=&(adj2_gids[dim_source][dim_target][0]);
355 bool has(
int dim)
const {
return (entity_needs>>dim)%2;}
358 int entityZ2toAPF(
enum MeshEntityType etype)
const {
return static_cast<int>(etype);}
362 if (ttype==apf::Mesh::VERTEX)
364 else if (ttype==apf::Mesh::EDGE)
368 else if (ttype==apf::Mesh::QUAD)
370 else if (ttype==apf::Mesh::TET)
372 else if (ttype==apf::Mesh::HEX)
379 throw "No such APF topology type";
384 void getTagWeight(apf::Mesh* m, apf::MeshTag* tag,apf::MeshEntity* ent,
scalar_t* ws);
393 apf::Numbering** lids;
394 apf::GlobalNumbering** gids;
399 std::vector<gno_t>** adj_gids;
401 std::vector<gno_t>** adj2_gids;
406 typedef std::unordered_map<int, std::pair<ArrayRCP<const scalar_t>,
int> > map_array_t;
415 template <
typename User>
419 std::string adjacency,
424 m_dimension = m->getDimension();
427 entity_needs = needs;
433 if (primary==
"element") {
439 if (adjacency==
"element") {
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);
452 int dim1 = entityZ2toAPF(this->getPrimaryEntityType());
453 int dim2 = entityZ2toAPF(this->getAdjacencyEntityType());
457 entity_needs|=new_needs;
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];
467 for (
int i=0;i<=m_dimension;i++) {
470 topologies[i] = NULL;
471 gid_mapping[i] = NULL;
475 num_local[i] = m->count(i);
476 long global_count = countOwned(m,i);
477 PCU_Add_Longs(&global_count,1);
482 sprintf(lids_name,
"lids%d",i);
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;
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;
499 assert(num==num_local[i]);
503 gid_mapping[i] =
new gno_t[num_local[i]];
505 apf::DynamicArray<apf::Node> nodes;
508 while((ent=m->iterate(itr))) {
510 gid_mapping[i][ apf::getNumber(lids[i],ent,0,0)] = gid;
519 adj_gids =
new std::vector<gno_t>*[m_dimension+1];
520 adj_offsets =
new offset_t**[m_dimension+1];
522 adj2_gids =
new std::vector<gno_t>*[m_dimension+1];
523 adj2_offsets =
new offset_t**[m_dimension+1];
529 for (
int i=0;i<=m_dimension;i++) {
534 adj2_offsets[i]=NULL;
538 adj_gids[i] =
new std::vector<gno_t>[m_dimension+1];
539 adj_offsets[i] =
new offset_t*[m_dimension+1];
541 adj2_gids[i] =
new std::vector<gno_t>[m_dimension+1];
542 adj2_offsets[i] =
new offset_t*[m_dimension+1];
544 for (
int j=0;j<=m_dimension;j++) {
547 adj_offsets[i][j]=NULL;
549 adj2_offsets[i][j]=NULL;
554 apf::MeshIterator* itr = m->begin(i);
555 apf::MeshEntity* ent;
557 adj_offsets[i][j] =
new offset_t[num_local[i]+1];
558 adj_offsets[i][j][0] =0;
560 adj2_offsets[i][j] =
new offset_t[num_local[i]+1];
561 adj2_offsets[i][j][0] =0;
568 std::unordered_map<gno_t,apf::MeshEntity*> part_boundary_mapping;
570 while ((ent=m->iterate(itr))) {
571 std::set<gno_t> temp_adjs;
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)));
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) {
585 m->getResidence(adj[l],res);
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++) {
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));
593 PCU_Comm_Pack(*it,send_vals,2*
sizeof(
gno_t));
598 adj_offsets[i][j][k] = adj_gids[i][j].size();
601 if (needSecondAdj && i!=m_dimension) {
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++) {
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));
620 std::set<gno_t>* adjs2 =
new std::set<gno_t>[num_local[i]];
621 while (PCU_Comm_Receive()) {
623 PCU_Comm_Unpack(adj2,2*
sizeof(
gno_t));
625 if (i==m_dimension) {
626 apf::MeshEntity* through = part_boundary_mapping[adj2[0]];
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]);
635 lno_t index = lid_mapping[i][adj2[0]];
636 adjs2[index].insert(adj2[1]);
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);
644 adj2_offsets[i][j][l+1]=adj2_gids[i][j].size();
651 ent_coords =
new scalar_t*[m_dimension+1];
652 for (
int i=0;i<=m_dimension;i++) {
653 ent_coords[i] = NULL;
656 apf::MeshIterator* itr = m->begin(i);
657 apf::MeshEntity* ent;
658 ent_coords[i] =
new scalar_t[3*num_local[i]];
660 while((ent=m->iterate(itr))) {
663 m->getPoint(ent,0,point);
666 point = apf::getLinearCentroid(m,ent);
668 for (
int k=0;k<3;k++)
669 ent_coords[i][j*3+k] = point[k];
677 weights =
new map_array_t[m_dimension+1];
680 delete [] lid_mapping;
682 template <
typename User>
683 void APFMeshAdapter<User>::destroy() {
687 for (
int i=0;i<=m_dimension;i++) {
690 delete [] ent_coords[i];
691 delete [] adj_gids[i];
693 delete [] adj2_gids[i];
694 for (
int j=0;j<=m_dimension;j++) {
698 delete [] adj_offsets[i][j];
700 delete [] adj2_offsets[i][j];
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]);
710 delete [] ent_coords;
712 delete [] adj_offsets;
715 delete [] adj2_offsets;
717 delete [] gid_mapping;
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");
732 ArrayRCP<const scalar_t> weight_rcp(val,0,stride*getLocalNumOf(etype),
false);
733 weights[dim][idx] =std::make_pair(weight_rcp,stride);
737 template <
typename User>
738 void APFMeshAdapter<User>::getTagWeight(apf::Mesh* m,
740 apf::MeshEntity* ent,
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]);
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]);
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]);
766 throw std::runtime_error(
"Unrecognized tag type");
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");
776 int n_weights = m->getTagSize(tag);
777 bool delete_ids =
false;
779 ids =
new int[n_weights];
781 for (
int i=0;i<n_weights;i++)
784 scalar_t* ones =
new scalar_t[n_weights];
785 for (
int i=0;i<n_weights;i++)
788 scalar_t* ws =
new scalar_t[num_local[dim]*n_weights];
789 apf::MeshIterator* itr = m->begin(dim);
790 apf::MeshEntity* ent;
792 while ((ent=m->iterate(itr))) {
794 if (m->hasTag(ent,tag)) {
795 w =
new scalar_t[n_weights];
796 getTagWeight(m,tag,ent,w);
801 for (
int i=0;i<n_weights;i++) {
802 ws[i*getLocalNumOf(etype)+j] = w[i];
806 if (m->hasTag(ent,tag))
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);
819 template <
typename User>
820 void APFMeshAdapter<User>::print(
int me,
int verbosity)
822 if (m_dimension==-1) {
823 std::cout<<
"Cannot print destroyed mesh adapter\n";
827 std::string fn(
" APFMesh ");
828 std::cout << me << fn
829 <<
" dimension = " << m_dimension
833 for (
int i=0;i<=m_dimension;i++) {
836 std::cout<<me<<
" Number of dimension " << i<<
" = " <<num_local[i] <<std::endl;
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++) {
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];
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];
865 #endif //HAVE_ZOLTAN2_PARMA
virtual void getAdjsView(MeshEntityType source, MeshEntityType target, const offset_t *&offsets, const gno_t *&adjacencyIds) const
Sets pointers to this process' 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.
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
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 avail2ndAdjs(MeshEntityType sourcetarget, MeshEntityType through) const
Returns whether a second adjacency combination is available. If combination is not available in the M...
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
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' 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
EntityTopologyType
Enumerate entity topology types for meshes: points,lines,polygons,triangles,quadrilaterals, polyhedrons, tetrahedrons, hexhedrons, prisms, or pyramids.
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
This file defines the StridedData class.
Zoltan2::BasicUserTypes< zscalar_t, zlno_t, zgno_t > user_t