5#ifndef DUNE_ISTL_REPARTITION_HH
6#define DUNE_ISTL_REPARTITION_HH
23#include <dune/common/timer.hh>
24#include <dune/common/enumset.hh>
25#include <dune/common/stdstreams.hh>
26#include <dune/common/parallel/mpitraits.hh>
27#include <dune/common/parallel/communicator.hh>
28#include <dune/common/parallel/indexset.hh>
29#include <dune/common/parallel/indicessyncer.hh>
30#include <dune/common/parallel/remoteindices.hh>
31#include <dune/common/rangeutilities.hh>
50#if HAVE_PARMETIS && defined(REALTYPEWIDTH)
56#if HAVE_PARMETIS && defined(IDXTYPEWIDTH)
58#elif HAVE_PARMETIS && defined(HAVE_SCOTCH_NUM_TYPE)
59 using idx_t = SCOTCH_Num;
82 template<
class G,
class T1,
class T2>
86 typedef typename IndexSet::LocalIndex::Attribute Attribute;
88 IndexSet& indexSet = oocomm.
indexSet();
91 std::size_t sum=0, needed = graph.noVertices()-indexSet.size();
92 std::vector<std::size_t> neededall(oocomm.
communicator().size(), 0);
94 MPI_Allgather(&needed, 1, MPITraits<std::size_t>::getType() , &(neededall[0]), 1, MPITraits<std::size_t>::getType(), oocomm.
communicator());
104 auto end = indexSet.end();
105 for(
auto it = indexSet.begin(); it != end; ++it)
106 maxgi=std::max(maxgi,it->global());
115 maxgi=maxgi+neededall[i];
118 std::map<int,SLList<std::pair<T1,Attribute> > > globalIndices;
119 storeGlobalIndicesOfRemoteIndices(globalIndices, oocomm.
remoteIndices());
120 indexSet.beginResize();
122 for(
auto vertex = graph.begin(), vend=graph.end(); vertex != vend; ++vertex) {
123 const typename IndexSet::IndexPair* pair=lookup.pair(*vertex);
131 indexSet.endResize();
133 repairLocalIndexPointers(globalIndices, oocomm.
remoteIndices(), indexSet);
138 std::cout<<
"Holes are filled!"<<std::endl;
146 class ParmetisDuneIndexMap
149 template<
class Graph,
class OOComm>
150 ParmetisDuneIndexMap(
const Graph& graph,
const OOComm& com);
151 int toParmetis(
int i)
const
153 return duneToParmetis[i];
155 int toLocalParmetis(
int i)
const
157 return duneToParmetis[i]-base_;
159 int operator[](
int i)
const
161 return duneToParmetis[i];
163 int toDune(
int i)
const
165 return parmetisToDune[i];
167 std::vector<int>::size_type numOfOwnVtx()
const
169 return parmetisToDune.size();
178 std::vector<int> duneToParmetis;
179 std::vector<int> parmetisToDune;
181 std::vector<Metis::idx_t> vtxDist_;
184 template<
class G,
class OOComm>
185 ParmetisDuneIndexMap::ParmetisDuneIndexMap(
const G& graph,
const OOComm& oocomm)
186 : duneToParmetis(graph.noVertices(), -1), vtxDist_(oocomm.communicator().size()+1)
188 int npes=oocomm.communicator().size(), mype=oocomm.communicator().rank();
190 typedef typename OOComm::OwnerSet OwnerSet;
193 auto end = oocomm.indexSet().end();
194 for(
auto index = oocomm.indexSet().begin(); index != end; ++index) {
195 if (OwnerSet::contains(index->local().attribute())) {
199 parmetisToDune.resize(numOfOwnVtx);
200 std::vector<int> globalNumOfVtx(npes);
202 MPI_Allgather(&numOfOwnVtx, 1, MPI_INT, &(globalNumOfVtx[0]), 1, MPI_INT, oocomm.communicator());
206 for(
int i=0; i<npes; i++) {
208 base += globalNumOfVtx[i];
210 vtxDist_[i+1] = vtxDist_[i] + globalNumOfVtx[i];
216 std::cout << oocomm.communicator().rank()<<
" vtxDist: ";
217 for(
int i=0; i<= npes; ++i)
218 std::cout << vtxDist_[i]<<
" ";
219 std::cout<<std::endl;
226 auto vend = graph.end();
227 for(
auto vertex = graph.begin(); vertex != vend; ++vertex) {
228 const typename OOComm::ParallelIndexSet::IndexPair* index=oocomm.globalLookup().pair(*vertex);
230 if (OwnerSet::contains(index->local().attribute())) {
232 parmetisToDune[base-base_]=index->local();
233 duneToParmetis[index->local()] = base++;
243 std::cout <<oocomm.communicator().rank()<<
": before ";
244 for(std::size_t i=0; i<duneToParmetis.size(); ++i)
245 std::cout<<duneToParmetis[i]<<
" ";
246 std::cout<<std::endl;
248 oocomm.copyOwnerToAll(duneToParmetis,duneToParmetis);
250 std::cout <<oocomm.communicator().rank()<<
": after ";
251 for(std::size_t i=0; i<duneToParmetis.size(); ++i)
252 std::cout<<duneToParmetis[i]<<
" ";
253 std::cout<<std::endl;
265 template<
class Flags,
class IS>
268 std::map<int,int> sizes;
270 for(
auto i=idxset.begin(), end=idxset.end(); i!=end; ++i)
271 if(Flags::contains(i->local().attribute()))
272 ++sizes[toPart[i->local()]];
275 for(
auto i=sizes.begin(), end=sizes.end(); i!=end; ++i)
276 interfaces()[i->first].first.reserve(i->second);
279 for(
auto i=idxset.begin(), end=idxset.end(); i!=end; ++i)
280 if(Flags::contains(i->local().attribute()))
281 interfaces()[toPart[i->local()]].first.add(i->local());
286 interfaces()[proc].second.reserve(size);
290 interfaces()[proc].second.add(idx);
292 template<
typename TG>
296 for(
auto idx=indices.begin(); idx!= indices.end(); ++idx) {
297 interfaces()[idx->second].second.add(i++);
318 void createSendBuf(std::vector<GI>& ownerVec, std::set<GI>& overlapVec, std::set<int>& neighbors,
char *sendBuf,
int buffersize, MPI_Comm comm) {
320 std::size_t s=ownerVec.size();
324 MPI_Pack(&s, 1, MPITraits<std::size_t>::getType(), sendBuf, buffersize, &pos, comm);
325 MPI_Pack(&(ownerVec[0]), s, MPITraits<GI>::getType(), sendBuf, buffersize, &pos, comm);
326 s = overlapVec.size();
327 MPI_Pack(&s, 1, MPITraits<std::size_t>::getType(), sendBuf, buffersize, &pos, comm);
328 for(
auto i=overlapVec.begin(), end= overlapVec.end(); i != end; ++i)
329 MPI_Pack(
const_cast<GI*
>(&(*i)), 1, MPITraits<GI>::getType(), sendBuf, buffersize, &pos, comm);
332 MPI_Pack(&s, 1, MPITraits<std::size_t>::getType(), sendBuf, buffersize, &pos, comm);
334 for(
auto i=neighbors.begin(), end= neighbors.end(); i != end; ++i)
335 MPI_Pack(
const_cast<int*
>(&(*i)), 1, MPI_INT, sendBuf, buffersize, &pos, comm);
346 void saveRecvBuf(
char *recvBuf,
int bufferSize, std::vector<std::pair<GI,int> >& ownerVec,
347 std::set<GI>& overlapVec, std::set<int>& neighbors, RedistributeInterface& inf,
int from, MPI_Comm comm) {
351 MPI_Unpack(recvBuf, bufferSize, &pos, &size, 1, MPITraits<std::size_t>::getType(), comm);
352 inf.reserveSpaceForReceiveInterface(from, size);
353 ownerVec.reserve(ownerVec.size()+size);
354 for(; size!=0; --size) {
356 MPI_Unpack(recvBuf, bufferSize, &pos, &gi, 1, MPITraits<GI>::getType(), comm);
357 ownerVec.push_back(std::make_pair(gi,from));
360 MPI_Unpack(recvBuf, bufferSize, &pos, &size, 1, MPITraits<std::size_t>::getType(), comm);
361 typename std::set<GI>::iterator ipos = overlapVec.begin();
362 Dune::dverb <<
"unpacking "<<size<<
" overlap"<<std::endl;
363 for(; size!=0; --size) {
365 MPI_Unpack(recvBuf, bufferSize, &pos, &gi, 1, MPITraits<GI>::getType(), comm);
366 ipos=overlapVec.insert(ipos, gi);
369 MPI_Unpack(recvBuf, bufferSize, &pos, &size, 1, MPITraits<std::size_t>::getType(), comm);
370 Dune::dverb <<
"unpacking "<<size<<
" neighbors"<<std::endl;
371 typename std::set<int>::iterator npos = neighbors.begin();
372 for(; size!=0; --size) {
374 MPI_Unpack(recvBuf, bufferSize, &pos, &n, 1, MPI_INT, comm);
375 npos=neighbors.insert(npos, n);
393 void getDomain(
const MPI_Comm& comm, T *part,
int numOfOwnVtx,
int nparts,
int *myDomain, std::vector<int> &domainMapping) {
395 MPI_Comm_size(comm, &npes);
396 MPI_Comm_rank(comm, &mype);
403 std::vector<int> domain(nparts, 0);
404 std::vector<int> assigned(npes, 0);
406 domainMapping.assign(domainMapping.size(), -1);
409 for (i=0; i<numOfOwnVtx; i++) {
413 std::vector<int> domainMatrix(npes * nparts, -1);
416 int *buf =
new int[nparts];
417 for (i=0; i<nparts; i++) {
419 domainMatrix[mype*nparts+i] = domain[i];
422 int src = (mype-1+npes)%npes;
423 int dest = (mype+1)%npes;
425 for (i=0; i<npes-1; i++) {
426 MPI_Sendrecv_replace(buf, nparts, MPI_INT, dest, 0, src, 0, comm, &status);
428 pe = ((mype-1-i)+npes)%npes;
429 for(j=0; j<nparts; j++) {
431 domainMatrix[pe*nparts+j] = buf[j];
439 int maxOccurance = 0;
441 std::set<std::size_t> unassigned;
443 for(i=0; i<nparts; i++) {
444 for(j=0; j<npes; j++) {
446 if (assigned[j]==0) {
447 if (maxOccurance < domainMatrix[j*nparts+i]) {
448 maxOccurance = domainMatrix[j*nparts+i];
456 domainMapping[i] = pe;
466 unassigned.insert(i);
471 typename std::vector<int>::iterator next_free = assigned.begin();
473 for(
auto udomain = unassigned.begin(),
474 end = unassigned.end(); udomain != end; ++udomain)
476 next_free = std::find_if(next_free, assigned.end(), std::bind(std::less<int>(), std::placeholders::_1, 1));
477 assert(next_free != assigned.end());
478 domainMapping[*udomain] = next_free-assigned.begin();
486 bool operator()(
const T& t1,
const T& t2)
const
504 void mergeVec(std::vector<std::pair<GI, int> >& ownerVec, std::set<GI>& overlapSet) {
508 if(ownerVec.size()>0)
510 auto old=ownerVec.begin();
511 for(
auto i=old+1, end=ownerVec.end(); i != end; old=i++)
513 if(i->first==old->first)
515 std::cerr<<
"Value at indes"<<old-ownerVec.begin()<<
" is the same as at index "
516 <<i-ownerVec.begin()<<
" ["<<old->first<<
","<<old->second<<
"]==["
517 <<i->first<<
","<<i->second<<
"]"<<std::endl;
525 auto v=ownerVec.begin(), vend=ownerVec.end();
526 for(
auto s=overlapSet.begin(), send=overlapSet.end(); s!=send;)
528 while(v!=vend && v->first<*s) ++v;
529 if(v!=vend && v->first==*s) {
534 overlapSet.erase(tmp);
554 template<
class OwnerSet,
class Graph,
class IS,
class GI>
555 void getNeighbor(
const Graph& g, std::vector<int>& part,
556 typename Graph::VertexDescriptor vtx,
const IS& indexSet,
557 int toPe, std::set<GI>& neighbor, std::set<int>& neighborProcs) {
558 for(
auto edge=g.beginEdges(vtx), end=g.endEdges(vtx); edge!=end; ++edge)
560 const typename IS::IndexPair* pindex = indexSet.pair(edge.target());
562 if(part[pindex->local()]!=toPe || !OwnerSet::contains(pindex->local().attribute()))
565 neighbor.insert(pindex->global());
566 neighborProcs.insert(part[pindex->local()]);
571 template<
class T,
class I>
572 void my_push_back(std::vector<T>& ownerVec,
const I& index, [[maybe_unused]]
int proc)
574 ownerVec.push_back(index);
577 template<
class T,
class I>
578 void my_push_back(std::vector<std::pair<T,int> >& ownerVec,
const I& index,
int proc)
580 ownerVec.push_back(std::make_pair(index,proc));
583 void reserve(std::vector<T>&, RedistributeInterface&,
int)
586 void reserve(std::vector<std::pair<T,int> >& ownerVec, RedistributeInterface& redist,
int proc)
588 redist.reserveSpaceForReceiveInterface(proc, ownerVec.size());
609 template<
class OwnerSet,
class G,
class IS,
class T,
class GI>
610 void getOwnerOverlapVec(
const G& graph, std::vector<int>& part, IS& indexSet,
611 [[maybe_unused]]
int myPe,
int toPe, std::vector<T>& ownerVec, std::set<GI>& overlapSet,
612 RedistributeInterface& redist, std::set<int>& neighborProcs) {
613 for(
auto index = indexSet.begin(); index != indexSet.end(); ++index) {
615 if(OwnerSet::contains(index->local().attribute()))
617 if(part[index->local()]==toPe)
619 getNeighbor<OwnerSet>(graph, part, index->local(), indexSet,
620 toPe, overlapSet, neighborProcs);
621 my_push_back(ownerVec, index->global(), toPe);
625 reserve(ownerVec, redist, toPe);
636 template<
class F,
class IS>
637 inline bool isOwner(IS& indexSet,
int index) {
639 const typename IS::IndexPair* pindex=indexSet.pair(index);
642 return F::contains(pindex->local().attribute());
646 class BaseEdgeFunctor
649 BaseEdgeFunctor(Metis::idx_t* adj,
const ParmetisDuneIndexMap& data)
650 : i_(), adj_(adj), data_(data)
654 void operator()(
const T& edge)
658 adj_[i_] = data_.toParmetis(edge.target());
669 const ParmetisDuneIndexMap& data_;
674 :
public BaseEdgeFunctor
676 EdgeFunctor(Metis::idx_t* adj,
const ParmetisDuneIndexMap& data, std::size_t)
677 : BaseEdgeFunctor(adj, data)
680 Metis::idx_t* getWeights()
687 template<
class G,
class V,
class E,
class VM,
class EM>
688 class EdgeFunctor<
Dune::Amg::PropertiesGraph<G,V,E,VM,EM> >
689 :
public BaseEdgeFunctor
692 EdgeFunctor(Metis::idx_t* adj,
const ParmetisDuneIndexMap& data, std::size_t s)
693 : BaseEdgeFunctor(adj, data)
695 weight_=
new Metis::idx_t[s];
699 void operator()(
const T& edge)
701 weight_[index()]=edge.properties().depends() ? 3 : 1;
702 BaseEdgeFunctor::operator()(edge);
704 Metis::idx_t* getWeights()
715 Metis::idx_t* weight_;
733 template<
class F,
class G,
class IS,
class EW>
734 void getAdjArrays(G& graph, IS& indexSet, Metis::idx_t *xadj,
738 auto vend = graph.end();
740 for(
auto vertex = graph.begin(); vertex != vend; ++vertex) {
741 if (isOwner<F>(indexSet,*vertex)) {
743 auto eend = vertex.end();
744 xadj[j] = ew.index();
746 for(
auto edge = vertex.begin(); edge != eend; ++edge) {
751 xadj[j] = ew.index();
755 template<
class G,
class T1,
class T2>
759 RedistributeInterface& redistInf,
762#ifndef METIS_VER_MAJOR
766 void METIS_PartGraphKway(
int *nvtxs, Metis::idx_t *xadj, Metis::idx_t *adjncy, Metis::idx_t *vwgt,
767 Metis::idx_t *adjwgt,
int *wgtflag,
int *numflag,
int *nparts,
768 int *options,
int *edgecut, Metis::idx_t *part);
770 void METIS_PartGraphRecursive(
int *nvtxs, Metis::idx_t *xadj, Metis::idx_t *adjncy, Metis::idx_t *vwgt,
771 Metis::idx_t *adjwgt,
int *wgtflag,
int *numflag,
int *nparts,
772 int *options,
int *edgecut, Metis::idx_t *part);
777 template<
class S,
class T>
780 for(T *cur=array, *end=array+l; cur!=end; ++cur)
784 template<
class S,
class T>
785 inline bool isValidGraph(std::size_t noVtx, std::size_t gnoVtx, S noEdges, T* xadj,
786 T* adjncy,
bool checkSymmetry)
792 if(
static_cast<S
>(xadj[vtx])>noEdges || signbit(xadj[vtx])) {
793 std::cerr <<
"Check graph: xadj["<<vtx<<
"]="<<xadj[vtx]<<
" (>"
794 <<noEdges<<
") out of range!"<<std::endl;
797 if(
static_cast<S
>(xadj[vtx+1])>noEdges || signbit(xadj[vtx+1])) {
798 std::cerr <<
"Check graph: xadj["<<vtx+1<<
"]="<<xadj[vtx+1]<<
" (>"
799 <<noEdges<<
") out of range!"<<std::endl;
804 if(signbit(adjncy[i]) || ((std::size_t)adjncy[i])>gnoVtx) {
805 std::cerr<<
" Edge "<<adjncy[i]<<
" out of range ["<<0<<
","<<noVtx<<
")"
815 for(
Metis::idx_t j=xadj[target]; j< xadj[target+1]; ++j)
819 std::cerr<<
"Edge ("<<target<<
","<<vtx<<
") "<<i<<
" time"<<std::endl;
828 template<
class M,
class T1,
class T2>
836 std::cout<<
"Repartitioning from "<<oocomm.
communicator().size()
837 <<
" to "<<nparts<<
" parts"<<std::endl;
841 int* part =
new int[1];
882 xadj[1]=noNeighbours;
925 if(n->first != rank) {
935 noNeighbours, xadj, adjncy,
false));
944 for(
int i=0; i<nparts; ++i)
945 tpwgts[i]=1.0/nparts;
948 Dune::dinfo<<rank<<
" vtxdist: ";
950 Dune::dinfo<<std::endl<<rank<<
" xadj: ";
952 Dune::dinfo<<std::endl<<rank<<
" adjncy: ";
956 Dune::dinfo<<std::endl<<rank<<
" vwgt: ";
958 Dune::dinfo<<std::endl<<rank<<
" adwgt: ";
961 Dune::dinfo<<std::endl;
964 std::cout<<
"Creating comm graph took "<<time.elapsed()<<std::endl;
967#ifdef PARALLEL_PARTITION
970 int options[5] ={ 0,1,15,0,0};
975 ParMETIS_V3_PartKway(vtxdist, xadj, adjncy,
976 vwgt, adjwgt, &wgtflag,
977 &numflag, &ncon, &nparts, tpwgts, &ubvec, options, &edgecut, part,
980 std::cout<<
"ParMETIS took "<<time.elapsed()<<std::endl;
984 std::size_t gnoedges=0;
987 Dune::dverb<<
"noNeighbours: "<<noNeighbours<<std::endl;
989 MPI_Allgather(&noNeighbours,1,MPI_INT,noedges,1, MPI_INT,oocomm.
communicator());
992 std::cout<<
"Gathering noedges took "<<time1.elapsed()<<std::endl;
1007 std::size_t localNoVtx=vtxdist[rank+1]-vtxdist[rank];
1012 Dune::dinfo<<
"noedges: ";
1014 Dune::dinfo<<std::endl;
1022 noxs[i]=vtxdist[i+1]-vtxdist[i]+1;
1023 novs[i]=vtxdist[i+1]-vtxdist[i];
1028 for(
int *xcurr = xdispl, *vcurr = vdispl, *end=vdispl+oocomm.
communicator().size();
1029 vcurr!=end; ++vcurr, ++xcurr, ++so, ++offset) {
1031 *xcurr = offset + *so;
1037 for(
int *curr=noedges, *end=noedges+oocomm.
communicator().size()-1;
1038 curr!=end; ++curr) {
1043 Dune::dinfo<<
"displ: ";
1045 Dune::dinfo<<std::endl;
1049 for(
int *curr=noedges, *end=noedges+oocomm.
communicator().size();
1054 Dune::dinfo<<
"gxadjlen: "<<gxadjlen<<
" noVertices: "<<noVertices
1055 <<
" gnoedges: "<<gnoedges<<std::endl;
1066 std::cout<<
"Preparing global graph took "<<time1.elapsed()<<std::endl;
1070 MPI_Allgatherv(xadj,2,MPITraits<Metis::idx_t>::getType(),
1071 gxadj,noxs,xdispl,MPITraits<Metis::idx_t>::getType(),
1073 MPI_Allgatherv(adjncy,noNeighbours,MPITraits<Metis::idx_t>::getType(),
1074 gadjncy,noedges,displ,MPITraits<Metis::idx_t>::getType(),
1077 MPI_Allgatherv(adjwgt,noNeighbours,MPITraits<Metis::idx_t>::getType(),
1078 gadjwgt,noedges,displ,MPITraits<Metis::idx_t>::getType(),
1080 MPI_Allgatherv(vwgt,localNoVtx,MPITraits<Metis::idx_t>::getType(),
1081 gvwgt,novs,vdispl,MPITraits<Metis::idx_t>::getType(),
1085 std::cout<<
"Gathering global graph data took "<<time1.elapsed()<<std::endl;
1099 int lprev = vtxdist[i]-vtxdist[i-1];
1100 int l = vtxdist[i+1]-vtxdist[i];
1102 assert((start+l+offset)-gxadj<=
static_cast<Metis::idx_t>(gxadjlen));
1103 increment = *(start-1);
1104 std::transform(start+offset, start+l+offset, start, std::bind(std::plus<Metis::idx_t>(), std::placeholders::_1, increment));
1106 Dune::dinfo<<std::endl<<
"shifted xadj:";
1108 Dune::dinfo<<std::endl<<
" gadjncy: ";
1111 Dune::dinfo<<std::endl<<
" gvwgt: ";
1113 Dune::dinfo<<std::endl<<
"adjwgt: ";
1115 Dune::dinfo<<std::endl;
1119 std::cout<<
"Postprocesing global graph data took "<<time1.elapsed()<<std::endl;
1123 gxadj, gadjncy,
true));
1127 std::cout<<
"Creating grah one 1 process took "<<time.elapsed()<<std::endl;
1129#if METIS_VER_MAJOR >= 5
1132 METIS_SetDefaultOptions(moptions);
1133 moptions[METIS_OPTION_NUMBERING] = numflag;
1134 METIS_PartGraphRecursive(&noVertices, &ncon, gxadj, gadjncy, gvwgt, NULL, gadjwgt,
1135 &nparts, NULL, NULL, moptions, &edgecut, gpart);
1137 int options[5] = {0, 1, 1, 3, 3};
1139 METIS_PartGraphRecursive(&noVertices, gxadj, gadjncy, gvwgt, gadjwgt, &wgtflag,
1140 &numflag, &nparts, options, &edgecut, gpart);
1144 std::cout<<
"METIS took "<<time.elapsed()<<std::endl;
1147 Dune::dinfo<<std::endl<<
"part:";
1158 MPI_Scatter(gpart, 1, MPITraits<Metis::idx_t>::getType(), part, 1,
1159 MPITraits<Metis::idx_t>::getType(), 0, comm);
1183 Dune::dinfo<<
" repart "<<rank <<
" -> "<< part[0]<<std::endl;
1185 std::vector<int> realpart(
mat.N(), part[0]);
1191 std::cout<<
"Scattering repartitioning took "<<time.elapsed()<<std::endl;
1199 std::cout<<
"Filling index set took "<<time.elapsed()<<std::endl;
1207 std::cout<<
"Average no neighbours was "<<noNeighbours<<std::endl;
1212 std::cout<<
"Building index sets took "<<time.elapsed()<<std::endl;
1234 template<
class G,
class T1,
class T2>
1247 std::cout<<
"Filling holes took "<<time.elapsed()<<std::endl;
1254 double t1=0.0, t2=0.0, t3=0.0, t4=0.0, tSum=0.0;
1282 typedef typename OOComm::OwnerSet OwnerSet;
1287 ParmetisDuneIndexMap indexMap(graph,oocomm);
1289 for(std::size_t i=0; i < indexMap.numOfOwnVtx(); ++i)
1294 std::cerr<<
"ParMETIS not activated. Will repartition to 1 domain instead of requested "
1295 <<nparts<<
" domains."<<std::endl;
1304 EdgeFunctor<G> ef(adjncy, indexMap, graph.noEdges());
1305 getAdjArrays<OwnerSet>(graph, oocomm.
globalLookup(), xadj, ef);
1311 Metis::idx_t numflag=0, wgtflag=0, options[3], edgecut=0, ncon=1;
1314 for(
int i=0; i<nparts; ++i)
1315 tpwgts[i]=1.0/nparts;
1324 wgtflag = (ef.getWeights()!=NULL) ? 1 : 0;
1332 std::cout<<std::endl;
1333 std::cout<<
"Testing ParMETIS_V3_PartKway with options[1-2] = {"
1334 <<options[1]<<
" "<<options[2]<<
"}, Ncon: "
1335 <<ncon<<
", Nparts: "<<nparts<<std::endl;
1348 std::cout<<
"Preparing for parmetis took "<<time.elapsed()<<std::endl;
1355 ParMETIS_V3_PartKway(indexMap.vtxDist(), xadj, adjncy,
1356 NULL, ef.getWeights(), &wgtflag,
1357 &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgecut, part, &
const_cast<MPI_Comm&
>(comm));
1368 std::cout<<std::endl;
1369 std::cout<<
"ParMETIS_V3_PartKway reported a cut of "<<edgecut<<std::endl;
1370 std::cout<<std::endl;
1372 std::cout<<mype<<
": PARMETIS-Result: ";
1373 for(
int i=0; i < indexMap.vtxDist()[mype+1]-indexMap.vtxDist()[mype]; ++i) {
1374 std::cout<<part[i]<<
" ";
1376 std::cout<<std::endl;
1377 std::cout<<
"Testing ParMETIS_V3_PartKway with options[1-2] = {"
1378 <<options[1]<<
" "<<options[2]<<
"}, Ncon: "
1379 <<ncon<<
", Nparts: "<<nparts<<std::endl;
1392 std::cout<<
"Parmetis took "<<time.elapsed()<<std::endl;
1399 for(std::size_t i=0; i<indexMap.numOfOwnVtx(); ++i)
1409 std::vector<int> domainMapping(nparts);
1411 getDomain(comm, part, indexMap.numOfOwnVtx(), nparts, &myDomain, domainMapping);
1416 std::cout<<mype<<
": myDomain: "<<myDomain<<std::endl;
1417 std::cout<<mype<<
": DomainMapping: ";
1418 for(
auto j : range(nparts)) {
1419 std::cout<<
" do: "<<j<<
" pe: "<<domainMapping[j]<<
" ";
1421 std::cout<<std::endl;
1428 std::vector<int> setPartition(oocomm.
indexSet().size(), -1);
1431 for(
auto index = oocomm.
indexSet().begin(); index != oocomm.
indexSet().end(); ++index)
1432 if(OwnerSet::contains(index->local().attribute())) {
1433 setPartition[index->local()]=domainMapping[part[i++]];
1440 if (SolverCategory::category(oocomm) ==
1441 static_cast<int>(SolverCategory::nonoverlapping))
1448 std::cout<<
"Creating indexsets took "<<time.elapsed()<<std::endl;
1455 template<
class G,
class T1,
class T2>
1463 typedef typename OOComm::OwnerSet OwnerSet;
1497 std::set<int> recvFrom;
1506 std::set<int> tsendTo;
1507 for(
auto i=setPartition.begin(), iend = setPartition.end(); i!=iend; ++i)
1510 noSendTo = tsendTo.size();
1511 sendTo =
new int[noSendTo];
1513 for(
auto i=tsendTo.begin(); i != tsendTo.end(); ++i, ++idx)
1519 int* gsendToDispl =
new int[oocomm.
communicator().size()+1];
1521 MPI_Allgather(&noSendTo, 1, MPI_INT, gnoSend, 1,
1525 int totalNoRecv = 0;
1526 for(
int i=0; i<npes; ++i)
1527 totalNoRecv += gnoSend[i];
1529 int *gsendTo =
new int[totalNoRecv];
1533 for(
int i=0; i<npes; ++i)
1534 gsendToDispl[i+1]=gsendToDispl[i]+gnoSend[i];
1537 MPI_Allgatherv(sendTo, noSendTo, MPI_INT, gsendTo, gnoSend, gsendToDispl,
1541 for(
int proc=0; proc < npes; ++proc)
1542 for(
int i=gsendToDispl[proc]; i < gsendToDispl[proc+1]; ++i)
1543 if(gsendTo[i]==mype)
1544 recvFrom.insert(proc);
1546 bool existentOnNextLevel = recvFrom.size()>0;
1550 delete[] gsendToDispl;
1555 if(recvFrom.size()) {
1556 std::cout<<mype<<
": recvFrom: ";
1557 for(
auto i=recvFrom.begin(); i!= recvFrom.end(); ++i) {
1562 std::cout<<std::endl<<std::endl;
1563 std::cout<<mype<<
": sendTo: ";
1564 for(
int i=0; i<noSendTo; i++) {
1565 std::cout<<sendTo[i]<<
" ";
1567 std::cout<<std::endl<<std::endl;
1572 std::cout<<
" Communicating the receive information took "<<
1573 time.elapsed()<<std::endl;
1587 typedef typename OOComm::ParallelIndexSet::GlobalIndex GI;
1588 typedef std::vector<GI> GlobalVector;
1589 std::vector<std::pair<GI,int> > myOwnerVec;
1590 std::set<GI> myOverlapSet;
1591 GlobalVector sendOwnerVec;
1592 std::set<GI> sendOverlapSet;
1593 std::set<int> myNeighbors;
1598 char **sendBuffers=
new char*[noSendTo];
1599 MPI_Request *requests =
new MPI_Request[noSendTo];
1602 for(
int i=0; i < noSendTo; ++i) {
1604 sendOwnerVec.clear();
1605 sendOverlapSet.clear();
1608 std::set<int> neighbors;
1609 getOwnerOverlapVec<OwnerSet>(graph, setPartition, oocomm.
globalLookup(),
1610 mype, sendTo[i], sendOwnerVec, sendOverlapSet, redistInf,
1616 MPI_Pack_size(1, MPITraits<std::size_t>::getType(), oocomm.
communicator(), &buffersize);
1617 MPI_Pack_size(sendOwnerVec.size(), MPITraits<GI>::getType(), oocomm.
communicator(), &tsize);
1619 MPI_Pack_size(1, MPITraits<std::size_t>::getType(), oocomm.
communicator(), &tsize);
1621 MPI_Pack_size(sendOverlapSet.size(), MPITraits<GI>::getType(), oocomm.
communicator(), &tsize);
1622 buffersize += tsize;
1623 MPI_Pack_size(1, MPITraits<std::size_t>::getType(), oocomm.
communicator(), &tsize);
1624 buffersize += tsize;
1625 MPI_Pack_size(neighbors.size(), MPI_INT, oocomm.
communicator(), &tsize);
1626 buffersize += tsize;
1628 sendBuffers[i] =
new char[buffersize];
1631 std::cout<<mype<<
" sending "<<sendOwnerVec.size()<<
" owner and "<<
1632 sendOverlapSet.size()<<
" overlap to "<<sendTo[i]<<
" buffersize="<<buffersize<<std::endl;
1634 createSendBuf(sendOwnerVec, sendOverlapSet, neighbors, sendBuffers[i], buffersize, oocomm.
communicator());
1635 MPI_Issend(sendBuffers[i], buffersize, MPI_PACKED, sendTo[i], 99, oocomm.
communicator(), requests+i);
1641 std::cout<<
" Creating sends took "<<
1642 time.elapsed()<<std::endl;
1647 int noRecv = recvFrom.size();
1648 int oldbuffersize=0;
1653 MPI_Probe(MPI_ANY_SOURCE, 99, oocomm.
communicator(), &stat);
1655 MPI_Get_count(&stat, MPI_PACKED, &buffersize);
1657 if(oldbuffersize<buffersize) {
1660 recvBuf =
new char[buffersize];
1661 oldbuffersize = buffersize;
1663 MPI_Recv(recvBuf, buffersize, MPI_PACKED, stat.MPI_SOURCE, 99, oocomm.
communicator(), &stat);
1664 saveRecvBuf(recvBuf, buffersize, myOwnerVec, myOverlapSet, myNeighbors, redistInf,
1674 MPI_Status *statuses =
new MPI_Status[noSendTo];
1675 int send = MPI_Waitall(noSendTo, requests, statuses);
1678 if(send==MPI_ERR_IN_STATUS) {
1679 std::cerr<<mype<<
": Error in sending :"<<std::endl;
1681 for(
int i=0; i< noSendTo; i++)
1682 if(statuses[i].MPI_ERROR!=MPI_SUCCESS) {
1685 MPI_Error_string(statuses[i].MPI_ERROR, message, &messageLength);
1686 std::cerr<<
" source="<<statuses[i].MPI_SOURCE<<
" message: ";
1687 for(
int j = 0; j < messageLength; j++)
1688 std::cout<<message[j];
1690 std::cerr<<std::endl;
1696 std::cout<<
" Receiving and saving took "<<
1697 time.elapsed()<<std::endl;
1701 for(
int i=0; i < noSendTo; ++i)
1702 delete[] sendBuffers[i];
1704 delete[] sendBuffers;
1719 if (!existentOnNextLevel) {
1721 color= MPI_UNDEFINED;
1723 MPI_Comm outputComm;
1726 outcomm = std::make_shared<OOComm>(outputComm,SolverCategory::category(oocomm),
true);
1729 int newrank=outcomm->communicator().rank();
1731 std::vector<int> tneighbors;
1732 tneighbors.reserve(myNeighbors.size());
1734 typename OOComm::ParallelIndexSet& outputIndexSet = outcomm->indexSet();
1736 MPI_Allgather(&newrank, 1, MPI_INT, newranks, 1,
1741 for(
auto i=myNeighbors.begin(), end=myNeighbors.end();
1743 assert(newranks[*i]>=0);
1744 std::cout<<*i<<
"->"<<newranks[*i]<<
" ";
1745 tneighbors.push_back(newranks[*i]);
1747 std::cout<<std::endl;
1749 for(
auto i=myNeighbors.begin(), end=myNeighbors.end();
1751 tneighbors.push_back(newranks[*i]);
1755 myNeighbors.clear();
1760 std::cout<<
" Calculating new neighbours ("<<tneighbors.size()<<
") took "<<
1761 time.elapsed()<<std::endl;
1766 outputIndexSet.beginResize();
1769 std::sort(myOwnerVec.begin(), myOwnerVec.end(), SortFirst());
1774 using LocalIndexT =
typename OOComm::ParallelIndexSet::LocalIndex;
1775 for(
auto g=myOwnerVec.begin(), end =myOwnerVec.end(); g!=end; ++g, ++i ) {
1776 outputIndexSet.add(g->first,LocalIndexT(i, OwnerOverlapCopyAttributeSet::owner,
true));
1783 std::cout<<
" Adding owner indices took "<<
1784 time.elapsed()<<std::endl;
1793 mergeVec(myOwnerVec, myOverlapSet);
1797 myOwnerVec.swap(myOwnerVec);
1802 std::cout<<
" Merging indices took "<<
1803 time.elapsed()<<std::endl;
1809 for(
auto g=myOverlapSet.begin(), end=myOverlapSet.end(); g!=end; ++g, i++) {
1810 outputIndexSet.add(*g,LocalIndexT(i, OwnerOverlapCopyAttributeSet::copy,
true));
1812 myOverlapSet.clear();
1813 outputIndexSet.endResize();
1815#ifdef DUNE_ISTL_WITH_CHECKING
1817 auto end = outputIndexSet.end();
1818 for(
auto index = outputIndexSet.begin(); index != end; ++index) {
1819 if (OwnerSet::contains(index->local().attribute())) {
1830 std::is_sorted(outputIndexSet.begin(), outputIndexSet.end(),
1831 [](
const auto& v1,
const auto& v2){ return v1.global() < v2.global();});
1836 std::cout<<
" Adding overlap indices took "<<
1837 time.elapsed()<<std::endl;
1842 if(color != MPI_UNDEFINED) {
1843 outcomm->remoteIndices().setNeighbours(tneighbors);
1844 outcomm->remoteIndices().template rebuild<true>();
1854 std::cout<<
" Storing indexsets took "<<
1855 time.elapsed()<<std::endl;
1861 tSum = t1 + t2 + t3 + t4;
1862 std::cout<<std::endl
1863 <<mype<<
": WTime for step 1): "<<t1
1871 return color!=MPI_UNDEFINED;
1875 template<
class G,
class P,
class T1,
class T2,
class R>
1876 bool graphRepartition(
const G& graph, P& oocomm,
int nparts,
1877 std::shared_ptr<P>& outcomm,
1881 if(nparts!=oocomm.size())
1882 DUNE_THROW(NotImplemented,
"only available for MPI programs");
1886 template<
class G,
class P,
class T1,
class T2,
class R>
1888 std::shared_ptr<P>& outcomm,
1892 if(nparts!=oocomm.size())
1893 DUNE_THROW(NotImplemented,
"only available for MPI programs");
Classes providing communication interfaces for overlapping Schwarz methods.
Provides classes for building the matrix graph.
int globalOwnerVertices
Definition repartition.hh:175
Matrix & mat
Definition matrixmatrix.hh:347
Definition allocator.hh:11
bool buildCommunication(const G &graph, std::vector< int > &realparts, Dune::OwnerOverlapCopyCommunication< T1, T2 > &oocomm, std::shared_ptr< Dune::OwnerOverlapCopyCommunication< T1, T2 > > &outcomm, RedistributeInterface &redistInf, bool verbose=false)
Definition repartition.hh:1456
void fillIndexSetHoles(const G &graph, Dune::OwnerOverlapCopyCommunication< T1, T2 > &oocomm)
Fills the holes in an index set.
Definition repartition.hh:83
bool commGraphRepartition(const M &mat, Dune::OwnerOverlapCopyCommunication< T1, T2 > &oocomm, Metis::idx_t nparts, std::shared_ptr< Dune::OwnerOverlapCopyCommunication< T1, T2 > > &outcomm, RedistributeInterface &redistInf, bool verbose=false)
Definition repartition.hh:829
void print_carray(S &os, T *array, std::size_t l)
Definition repartition.hh:778
bool isValidGraph(std::size_t noVtx, std::size_t gnoVtx, S noEdges, T *xadj, T *adjncy, bool checkSymmetry)
Definition repartition.hh:785
bool graphRepartition(const G &graph, Dune::OwnerOverlapCopyCommunication< T1, T2 > &oocomm, Metis::idx_t nparts, std::shared_ptr< Dune::OwnerOverlapCopyCommunication< T1, T2 > > &outcomm, RedistributeInterface &redistInf, bool verbose=false)
execute a graph repartition for a giving graph and indexset.
Definition repartition.hh:1235
float real_t
Definition repartition.hh:53
std::size_t idx_t
Definition repartition.hh:63
@ owner
Definition owneroverlapcopy.hh:61
A class setting up standard communication for a two-valued attribute set with owner/overlap/copy sema...
Definition owneroverlapcopy.hh:174
const GlobalLookupIndexSet & globalLookup() const
Definition owneroverlapcopy.hh:526
const ParallelIndexSet & indexSet() const
Get the underlying parallel index set.
Definition owneroverlapcopy.hh:462
void copyCopyToAll(const T &source, T &dest) const
Communicate values from copy data points to all other data points.
Definition owneroverlapcopy.hh:328
Dune::GlobalLookupIndexSet< ParallelIndexSet > GlobalLookupIndexSet
The type of the reverse lookup of indices.
Definition owneroverlapcopy.hh:456
void buildGlobalLookup()
Definition owneroverlapcopy.hh:495
const Communication< MPI_Comm > & communicator() const
Definition owneroverlapcopy.hh:299
void copyOwnerToAll(const T &source, T &dest) const
Communicate values from owner data points to all other data points.
Definition owneroverlapcopy.hh:311
const RemoteIndices & remoteIndices() const
Get the underlying remote indices.
Definition owneroverlapcopy.hh:471
void freeGlobalLookup()
Definition owneroverlapcopy.hh:520
Dune::ParallelIndexSet< GlobalIdType, LI, 512 > ParallelIndexSet
The type of the parallel index set.
Definition owneroverlapcopy.hh:449
The (undirected) graph of a matrix.
Definition graph.hh:51
Definition repartition.hh:260
void reserveSpaceForReceiveInterface(int proc, int size)
Definition repartition.hh:284
void buildReceiveInterface(std::vector< std::pair< TG, int > > &indices)
Definition repartition.hh:293
~RedistributeInterface()
Definition repartition.hh:301
void setCommunicator(MPI_Comm comm)
Definition repartition.hh:261
void buildSendInterface(const std::vector< int > &toPart, const IS &idxset)
Definition repartition.hh:266
void addReceiveIndex(int proc, std::size_t idx)
Definition repartition.hh:288