14#ifndef _ZOLTAN2_APFMESHADAPTER_HPP_
15#define _ZOLTAN2_APFMESHADAPTER_HPP_
20#include <unordered_map>
25#ifndef HAVE_ZOLTAN2_PARMA
31template <
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>
82template <
typename User>
83 class APFMeshAdapter:
public MeshAdapter<User> {
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++) {
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];
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)
366 else if (ttype==apf::Mesh::TRIANGLE)
368 else if (ttype==apf::Mesh::QUAD)
370 else if (ttype==apf::Mesh::TET)
372 else if (ttype==apf::Mesh::HEX)
374 else if (ttype==apf::Mesh::PRISM)
376 else if (ttype==apf::Mesh::PYRAMID)
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;
415template <
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))) {
509 gno_t gid = apf::getNumber(gids[i],apf::Node(ent,0));
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;
682template <
typename User>
683void 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;
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");
732 ArrayRCP<const scalar_t> weight_rcp(val,0,stride*getLocalNumOf(etype),
false);
733 weights[dim][idx] =std::make_pair(weight_rcp,stride);
737template <
typename User>
738void 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");
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");
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);
819template <
typename User>
820void 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];
Zoltan2::BasicUserTypes< zscalar_t, zlno_t, zgno_t > user_t
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.
SparseMatrixAdapter_t::part_t part_t