Dune Core Modules (2.5.2)

repartition.hh
Go to the documentation of this file.
1 // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi: set et ts=4 sw=2 sts=2:
3 #ifndef DUNE_ISTL_REPARTITION_HH
4 #define DUNE_ISTL_REPARTITION_HH
5 
6 #include <cassert>
7 #include <map>
8 #include <utility>
9 
10 #if HAVE_PARMETIS
11 // Explicitly use C linkage as scotch does not extern "C" in its headers.
12 // Works because ParMETIS/METIS checks whether compiler is C++ and otherwise
13 // does not use extern "C". Therfore no nested extern "C" will be created
14 extern "C"
15 {
16 #include <parmetis.h>
17 }
18 #endif
19 
20 #include <dune/common/timer.hh>
21 #include <dune/common/unused.hh>
22 #include <dune/common/enumset.hh>
29 
31 #include <dune/istl/paamg/graph.hh>
32 
41 namespace Dune
42 {
43 #if HAVE_MPI
57  template<class G, class T1, class T2>
59  {
61  typedef typename IndexSet::LocalIndex::Attribute Attribute;
62 
63  IndexSet& indexSet = oocomm.indexSet();
64  const typename Dune::OwnerOverlapCopyCommunication<T1,T2>::GlobalLookupIndexSet& lookup =oocomm.globalLookup();
65 
66  // The type of the const vertex iterator.
67  typedef typename G::ConstVertexIterator VertexIterator;
68 
69 
70  std::size_t sum=0, needed = graph.noVertices()-indexSet.size();
71  std::vector<std::size_t> neededall(oocomm.communicator().size(), 0);
72 
73  MPI_Allgather(&needed, 1, MPITraits<std::size_t>::getType() , &(neededall[0]), 1, MPITraits<std::size_t>::getType(), oocomm.communicator());
74  for(int i=0; i<oocomm.communicator().size(); ++i)
75  sum=sum+neededall[i]; // MAke this for generic
76 
77  if(sum==0)
78  // Nothing to do
79  return;
80 
81  //Compute Maximum Global Index
82  T1 maxgi=0;
83  typedef typename IndexSet::const_iterator Iterator;
84  Iterator end;
85  end = indexSet.end();
86  for(Iterator it = indexSet.begin(); it != end; ++it)
87  maxgi=std::max(maxgi,it->global());
88 
89  //Process p creates global indices consecutively
90  //starting atmaxgi+\sum_{i=1}^p neededall[i]
91  // All created indices are owned by the process
92  maxgi=oocomm.communicator().max(maxgi);
93  ++maxgi; //Sart with the next free index.
94 
95  for(int i=0; i<oocomm.communicator().rank(); ++i)
96  maxgi=maxgi+neededall[i]; // TODO: make this more generic
97 
98  // Store the global index information for repairing the remote index information
99  std::map<int,SLList<std::pair<T1,Attribute> > > globalIndices;
100  storeGlobalIndicesOfRemoteIndices(globalIndices, oocomm.remoteIndices());
101  indexSet.beginResize();
102 
103  for(VertexIterator vertex = graph.begin(), vend=graph.end(); vertex != vend; ++vertex) {
104  const typename IndexSet::IndexPair* pair=lookup.pair(*vertex);
105  if(pair==0) {
106  // No index yet, add new one
107  indexSet.add(maxgi, typename IndexSet::LocalIndex(*vertex, OwnerOverlapCopyAttributeSet::owner, false));
108  ++maxgi;
109  }
110  }
111 
112  indexSet.endResize();
113 
114  repairLocalIndexPointers(globalIndices, oocomm.remoteIndices(), indexSet);
115 
116  oocomm.freeGlobalLookup();
117  oocomm.buildGlobalLookup();
118 #ifdef DEBUG_REPART
119  std::cout<<"Holes are filled!"<<std::endl;
120  std::cout<<oocomm.communicator().rank()<<": "<<oocomm.indexSet()<<std::endl;
121 #endif
122  }
123 
124  namespace
125  {
126 
127  class ParmetisDuneIndexMap
128  {
129  public:
130  // define index type as provided by ParMETIS
131 #if HAVE_PARMETIS
132  #if PARMETIS_MAJOR_VERSION > 3
133  typedef idx_t idxtype;
134  #else
135  typedef int idxtype;
136  #endif // PARMETIS_MAJOR_VERSION > 3
137 #else
138  typedef std::size_t idxtype;
139 #endif // #if HAVE_PARMETIS
140 
141  template<class Graph, class OOComm>
142  ParmetisDuneIndexMap(const Graph& graph, const OOComm& com);
143  int toParmetis(int i) const
144  {
145  return duneToParmetis[i];
146  }
147  int toLocalParmetis(int i) const
148  {
149  return duneToParmetis[i]-base_;
150  }
151  int operator[](int i) const
152  {
153  return duneToParmetis[i];
154  }
155  int toDune(int i) const
156  {
157  return parmetisToDune[i];
158  }
159  std::vector<int>::size_type numOfOwnVtx() const
160  {
161  return parmetisToDune.size();
162  }
163  idxtype* vtxDist()
164  {
165  return &vtxDist_[0];
166  }
167  int globalOwnerVertices;
168  private:
169  int base_;
170  std::vector<int> duneToParmetis;
171  std::vector<int> parmetisToDune;
172  // range of vertices for processor i: vtxdist[i] to vtxdist[i+1] (parmetis global)
173  std::vector<idxtype> vtxDist_;
174  };
175 
176  template<class G, class OOComm>
177  ParmetisDuneIndexMap::ParmetisDuneIndexMap(const G& graph, const OOComm& oocomm)
178  : duneToParmetis(graph.noVertices(), -1), vtxDist_(oocomm.communicator().size()+1)
179  {
180  int npes=oocomm.communicator().size(), mype=oocomm.communicator().rank();
181 
182  typedef typename OOComm::ParallelIndexSet::const_iterator Iterator;
183  typedef typename OOComm::OwnerSet OwnerSet;
184 
185  int numOfOwnVtx=0;
186  Iterator end = oocomm.indexSet().end();
187  for(Iterator index = oocomm.indexSet().begin(); index != end; ++index) {
188  if (OwnerSet::contains(index->local().attribute())) {
189  numOfOwnVtx++;
190  }
191  }
192  parmetisToDune.resize(numOfOwnVtx);
193  std::vector<int> globalNumOfVtx(npes);
194  // make this number available to all processes
195  MPI_Allgather(&numOfOwnVtx, 1, MPI_INT, &(globalNumOfVtx[0]), 1, MPI_INT, oocomm.communicator());
196 
197  int base=0;
198  vtxDist_[0] = 0;
199  for(int i=0; i<npes; i++) {
200  if (i<mype) {
201  base += globalNumOfVtx[i];
202  }
203  vtxDist_[i+1] = vtxDist_[i] + globalNumOfVtx[i];
204  }
205  globalOwnerVertices=vtxDist_[npes];
206  base_=base;
207 
208  // The type of the const vertex iterator.
209  typedef typename G::ConstVertexIterator VertexIterator;
210 #ifdef DEBUG_REPART
211  std::cout << oocomm.communicator().rank()<<" vtxDist: ";
212  for(int i=0; i<= npes; ++i)
213  std::cout << vtxDist_[i]<<" ";
214  std::cout<<std::endl;
215 #endif
216 
217  // Traverse the graph and assign a new consecutive number/index
218  // starting by "base" to all owner vertices.
219  // The new index is used as the ParMETIS global index and is
220  // stored in the vector "duneToParmetis"
221  VertexIterator vend = graph.end();
222  for(VertexIterator vertex = graph.begin(); vertex != vend; ++vertex) {
223  const typename OOComm::ParallelIndexSet::IndexPair* index=oocomm.globalLookup().pair(*vertex);
224  assert(index);
225  if (OwnerSet::contains(index->local().attribute())) {
226  // assign and count the index
227  parmetisToDune[base-base_]=index->local();
228  duneToParmetis[index->local()] = base++;
229  }
230  }
231 
232  // At this point, every process knows the ParMETIS global index
233  // of it's owner vertices. The next step is to get the
234  // ParMETIS global index of the overlap vertices from the
235  // associated processes. To do this, the Dune::Interface class
236  // is used.
237 #ifdef DEBUG_REPART
238  std::cout <<oocomm.communicator().rank()<<": before ";
239  for(std::size_t i=0; i<duneToParmetis.size(); ++i)
240  std::cout<<duneToParmetis[i]<<" ";
241  std::cout<<std::endl;
242 #endif
243  oocomm.copyOwnerToAll(duneToParmetis,duneToParmetis);
244 #ifdef DEBUG_REPART
245  std::cout <<oocomm.communicator().rank()<<": after ";
246  for(std::size_t i=0; i<duneToParmetis.size(); ++i)
247  std::cout<<duneToParmetis[i]<<" ";
248  std::cout<<std::endl;
249 #endif
250  }
251  }
252 
253  struct RedistributeInterface
254  : public Interface
255  {
256  void setCommunicator(MPI_Comm comm)
257  {
258  communicator_=comm;
259  }
260  template<class Flags,class IS>
261  void buildSendInterface(const std::vector<int>& toPart, const IS& idxset)
262  {
263  std::map<int,int> sizes;
264 
265  typedef typename IS::const_iterator IIter;
266  for(IIter i=idxset.begin(), end=idxset.end(); i!=end; ++i)
267  if(Flags::contains(i->local().attribute()))
268  ++sizes[toPart[i->local()]];
269 
270  // Allocate the necessary space
271  typedef std::map<int,int>::const_iterator MIter;
272  for(MIter i=sizes.begin(), end=sizes.end(); i!=end; ++i)
273  interfaces()[i->first].first.reserve(i->second);
274 
275  //Insert the interface information
276  typedef typename IS::const_iterator IIter;
277  for(IIter i=idxset.begin(), end=idxset.end(); i!=end; ++i)
278  if(Flags::contains(i->local().attribute()))
279  interfaces()[toPart[i->local()]].first.add(i->local());
280  }
281 
282  void reserveSpaceForReceiveInterface(int proc, int size)
283  {
284  interfaces()[proc].second.reserve(size);
285  }
286  void addReceiveIndex(int proc, std::size_t idx)
287  {
288  interfaces()[proc].second.add(idx);
289  }
290  template<typename TG>
291  void buildReceiveInterface(std::vector<std::pair<TG,int> >& indices)
292  {
293  typedef typename std::vector<std::pair<TG,int> >::const_iterator VIter;
294  std::size_t i=0;
295  for(VIter idx=indices.begin(); idx!= indices.end(); ++idx) {
296  interfaces()[idx->second].second.add(i++);
297  }
298  }
299 
300  ~RedistributeInterface()
301  {}
302 
303  };
304 
305  namespace
306  {
307  // idxtype is given by ParMETIS package
308  typedef ParmetisDuneIndexMap :: idxtype idxtype ;
309 
319  template<class GI>
320  void createSendBuf(std::vector<GI>& ownerVec, std::set<GI>& overlapVec, std::set<int>& neighbors, char *sendBuf, int buffersize, MPI_Comm comm) {
321  // Pack owner vertices
322  std::size_t s=ownerVec.size();
323  int pos=0;
324  if(s==0)
325  ownerVec.resize(1); // otherwise would read beyond the memory bound
326  MPI_Pack(&s, 1, MPITraits<std::size_t>::getType(), sendBuf, buffersize, &pos, comm);
327  MPI_Pack(&(ownerVec[0]), s, MPITraits<GI>::getType(), sendBuf, buffersize, &pos, comm);
328  s = overlapVec.size();
329  MPI_Pack(&s, 1, MPITraits<std::size_t>::getType(), sendBuf, buffersize, &pos, comm);
330  typedef typename std::set<GI>::iterator Iter;
331  for(Iter i=overlapVec.begin(), end= overlapVec.end(); i != end; ++i)
332  MPI_Pack(const_cast<GI*>(&(*i)), 1, MPITraits<GI>::getType(), sendBuf, buffersize, &pos, comm);
333 
334  s=neighbors.size();
335  MPI_Pack(&s, 1, MPITraits<std::size_t>::getType(), sendBuf, buffersize, &pos, comm);
336  typedef typename std::set<int>::iterator IIter;
337 
338  for(IIter i=neighbors.begin(), end= neighbors.end(); i != end; ++i)
339  MPI_Pack(const_cast<int*>(&(*i)), 1, MPI_INT, sendBuf, buffersize, &pos, comm);
340  }
349  template<class GI>
350  void saveRecvBuf(char *recvBuf, int bufferSize, std::vector<std::pair<GI,int> >& ownerVec,
351  std::set<GI>& overlapVec, std::set<int>& neighbors, RedistributeInterface& inf, int from, MPI_Comm comm) {
352  std::size_t size;
353  int pos=0;
354  // unpack owner vertices
355  MPI_Unpack(recvBuf, bufferSize, &pos, &size, 1, MPITraits<std::size_t>::getType(), comm);
356  inf.reserveSpaceForReceiveInterface(from, size);
357  ownerVec.reserve(ownerVec.size()+size);
358  for(; size!=0; --size) {
359  GI gi;
360  MPI_Unpack(recvBuf, bufferSize, &pos, &gi, 1, MPITraits<GI>::getType(), comm);
361  ownerVec.push_back(std::make_pair(gi,from));
362  }
363  // unpack overlap vertices
364  MPI_Unpack(recvBuf, bufferSize, &pos, &size, 1, MPITraits<std::size_t>::getType(), comm);
365  typename std::set<GI>::iterator ipos = overlapVec.begin();
366  Dune::dverb << "unpacking "<<size<<" overlap"<<std::endl;
367  for(; size!=0; --size) {
368  GI gi;
369  MPI_Unpack(recvBuf, bufferSize, &pos, &gi, 1, MPITraits<GI>::getType(), comm);
370  ipos=overlapVec.insert(ipos, gi);
371  }
372  //unpack neighbors
373  MPI_Unpack(recvBuf, bufferSize, &pos, &size, 1, MPITraits<std::size_t>::getType(), comm);
374  Dune::dverb << "unpacking "<<size<<" neighbors"<<std::endl;
375  typename std::set<int>::iterator npos = neighbors.begin();
376  for(; size!=0; --size) {
377  int n;
378  MPI_Unpack(recvBuf, bufferSize, &pos, &n, 1, MPI_INT, comm);
379  npos=neighbors.insert(npos, n);
380  }
381  }
382 
396  template<typename T>
397  void getDomain(const MPI_Comm& comm, T *part, int numOfOwnVtx, int nparts, int *myDomain, std::vector<int> &domainMapping) {
398  int npes, mype;
399  MPI_Comm_size(comm, &npes);
400  MPI_Comm_rank(comm, &mype);
401  MPI_Status status;
402 
403  *myDomain = -1;
404  int i=0;
405  int j=0;
406 
407  std::vector<int> domain(nparts, 0);
408  std::vector<int> assigned(npes, 0);
409  // init domain Mapping
410  domainMapping.assign(domainMapping.size(), -1);
411 
412  // count the occurrence of domains
413  for (i=0; i<numOfOwnVtx; i++) {
414  domain[part[i]]++;
415  }
416 
417  std::vector<int> domainMatrix(npes * nparts, -1);
418 
419  // init buffer with the own domain
420  int *buf = new int[nparts];
421  for (i=0; i<nparts; i++) {
422  buf[i] = domain[i];
423  domainMatrix[mype*nparts+i] = domain[i];
424  }
425  int pe=0;
426  int src = (mype-1+npes)%npes;
427  int dest = (mype+1)%npes;
428  // ring communication, we need n-1 communications for n processors
429  for (i=0; i<npes-1; i++) {
430  MPI_Sendrecv_replace(buf, nparts, MPI_INT, dest, 0, src, 0, comm, &status);
431  // pe is the process of the actual received buffer
432  pe = ((mype-1-i)+npes)%npes;
433  for(j=0; j<nparts; j++) {
434  // save the values to the domain matrix
435  domainMatrix[pe*nparts+j] = buf[j];
436  }
437  }
438  delete[] buf;
439 
440  // Start the domain calculation.
441  // The process which contains the maximum number of vertices of a
442  // particular domain is selected to choose it's favorate domain
443  int maxOccurance = 0;
444  pe = -1;
445  std::set<std::size_t> unassigned;
446 
447  for(i=0; i<nparts; i++) {
448  for(j=0; j<npes; j++) {
449  // process has no domain assigned
450  if (assigned[j]==0) {
451  if (maxOccurance < domainMatrix[j*nparts+i]) {
452  maxOccurance = domainMatrix[j*nparts+i];
453  pe = j;
454  }
455  }
456 
457  }
458  if (pe!=-1) {
459  // process got a domain, ...
460  domainMapping[i] = pe;
461  // ...mark as assigned
462  assigned[pe] = 1;
463  if (pe==mype) {
464  *myDomain = i;
465  }
466  pe = -1;
467  }
468  else
469  {
470  unassigned.insert(i);
471  }
472  maxOccurance = 0;
473  }
474 
475  typename std::vector<int>::iterator next_free = assigned.begin();
476 
477  for(typename std::set<std::size_t>::iterator domain = unassigned.begin(),
478  end = unassigned.end(); domain != end; ++domain)
479  {
480  next_free = std::find_if(next_free, assigned.end(), std::bind2nd(std::less<int>(), 1));
481  assert(next_free != assigned.end());
482  domainMapping[*domain] = next_free-assigned.begin();
483  *next_free = 1;
484  }
485  }
486 
487  struct SortFirst
488  {
489  template<class T>
490  bool operator()(const T& t1, const T& t2) const
491  {
492  return t1<t2;
493  }
494  };
495 
496 
507  template<class GI>
508  void mergeVec(std::vector<std::pair<GI, int> >& ownerVec, std::set<GI>& overlapSet) {
509 
510  typedef typename std::vector<std::pair<GI,int> >::const_iterator VIter;
511 #ifdef DEBUG_REPART
512  // Safety check for duplicates.
513  if(ownerVec.size()>0)
514  {
515  VIter old=ownerVec.begin();
516  for(VIter i=old+1, end=ownerVec.end(); i != end; old=i++)
517  {
518  if(i->first==old->first)
519  {
520  std::cerr<<"Value at indes"<<old-ownerVec.begin()<<" is the same as at index "
521  <<i-ownerVec.begin()<<" ["<<old->first<<","<<old->second<<"]==["
522  <<i->first<<","<<i->second<<"]"<<std::endl;
523  throw "Huch!";
524  }
525  }
526  }
527 
528 #endif
529 
530  typedef typename std::set<GI>::iterator SIter;
531  VIter v=ownerVec.begin(), vend=ownerVec.end();
532  for(SIter s=overlapSet.begin(), send=overlapSet.end(); s!=send;)
533  {
534  while(v!=vend && v->first<*s) ++v;
535  if(v!=vend && v->first==*s) {
536  // Move to the next element before erasing
537  // thus s stays valid!
538  SIter tmp=s;
539  ++s;
540  overlapSet.erase(tmp);
541  }else
542  ++s;
543  }
544  }
545 
546 
560  template<class OwnerSet, class Graph, class IS, class GI>
561  void getNeighbor(const Graph& g, std::vector<int>& part,
562  typename Graph::VertexDescriptor vtx, const IS& indexSet,
563  int toPe, std::set<GI>& neighbor, std::set<int>& neighborProcs) {
564  typedef typename Graph::ConstEdgeIterator Iter;
565  for(Iter edge=g.beginEdges(vtx), end=g.endEdges(vtx); edge!=end; ++edge)
566  {
567  const typename IS::IndexPair* pindex = indexSet.pair(edge.target());
568  assert(pindex);
569  if(part[pindex->local()]!=toPe || !OwnerSet::contains(pindex->local().attribute()))
570  {
571  // is sent to another process and therefore becomes overlap
572  neighbor.insert(pindex->global());
573  neighborProcs.insert(part[pindex->local()]);
574  }
575  }
576  }
577 
578  template<class T, class I>
579  void my_push_back(std::vector<T>& ownerVec, const I& index, int proc)
580  {
581  DUNE_UNUSED_PARAMETER(proc);
582  ownerVec.push_back(index);
583  }
584 
585  template<class T, class I>
586  void my_push_back(std::vector<std::pair<T,int> >& ownerVec, const I& index, int proc)
587  {
588  ownerVec.push_back(std::make_pair(index,proc));
589  }
590  template<class T>
591  void reserve(std::vector<T>&, RedistributeInterface&, int)
592  {}
593  template<class T>
594  void reserve(std::vector<std::pair<T,int> >& ownerVec, RedistributeInterface& redist, int proc)
595  {
596  redist.reserveSpaceForReceiveInterface(proc, ownerVec.size());
597  }
598 
599 
617  template<class OwnerSet, class G, class IS, class T, class GI>
618  void getOwnerOverlapVec(const G& graph, std::vector<int>& part, IS& indexSet,
619  int myPe, int toPe, std::vector<T>& ownerVec, std::set<GI>& overlapSet,
620  RedistributeInterface& redist, std::set<int>& neighborProcs) {
621  DUNE_UNUSED_PARAMETER(myPe);
622  //typedef typename IndexSet::const_iterator Iterator;
623  typedef typename IS::const_iterator Iterator;
624  for(Iterator index = indexSet.begin(); index != indexSet.end(); ++index) {
625  // Only Process owner vertices, the others are not in the parmetis graph.
626  if(OwnerSet::contains(index->local().attribute()))
627  {
628  if(part[index->local()]==toPe)
629  {
630  getNeighbor<OwnerSet>(graph, part, index->local(), indexSet,
631  toPe, overlapSet, neighborProcs);
632  my_push_back(ownerVec, index->global(), toPe);
633  }
634  }
635  }
636  reserve(ownerVec, redist, toPe);
637 
638  }
639 
640 
647  template<class F, class IS>
648  inline bool isOwner(IS& indexSet, int index) {
649 
650  const typename IS::IndexPair* pindex=indexSet.pair(index);
651 
652  assert(pindex);
653  return F::contains(pindex->local().attribute());
654  }
655 
656 
657  class BaseEdgeFunctor
658  {
659  public:
660  BaseEdgeFunctor(idxtype* adj,const ParmetisDuneIndexMap& data)
661  : i_(), adj_(adj), data_(data)
662  {}
663 
664  template<class T>
665  void operator()(const T& edge)
666  {
667  // Get the egde weight
668  // const Weight& weight=edge.weight();
669  adj_[i_] = data_.toParmetis(edge.target());
670  i_++;
671  }
672  std::size_t index()
673  {
674  return i_;
675  }
676 
677  private:
678  std::size_t i_;
679  idxtype* adj_;
680  const ParmetisDuneIndexMap& data_;
681  };
682 
683  template<typename G>
684  struct EdgeFunctor
685  : public BaseEdgeFunctor
686  {
687  EdgeFunctor(idxtype* adj, const ParmetisDuneIndexMap& data, std::size_t)
688  : BaseEdgeFunctor(adj, data)
689  {}
690 
691  idxtype* getWeights()
692  {
693  return NULL;
694  }
695  void free(){}
696  };
697 
698  template<class G, class V, class E, class VM, class EM>
699  class EdgeFunctor<Dune::Amg::PropertiesGraph<G,V,E,VM,EM> >
700  : public BaseEdgeFunctor
701  {
702  public:
703  EdgeFunctor(idxtype* adj, const ParmetisDuneIndexMap& data, std::size_t s)
704  : BaseEdgeFunctor(adj, data)
705  {
706  weight_=new idxtype[s];
707  }
708 
709  template<class T>
710  void operator()(const T& edge)
711  {
712  weight_[index()]=edge.properties().depends() ? 3 : 1;
713  BaseEdgeFunctor::operator()(edge);
714  }
715  idxtype* getWeights()
716  {
717  return weight_;
718  }
719  void free(){
720  if(weight_!=0) {
721  delete weight_;
722  weight_=0;
723  }
724  }
725  private:
726  idxtype* weight_;
727  };
728 
729 
730 
744  template<class F, class G, class IS, class EW>
745  void getAdjArrays(G& graph, IS& indexSet, idxtype *xadj,
746  EW& ew)
747  {
748  int j=0;
749 
750  // The type of the const vertex iterator.
751  typedef typename G::ConstVertexIterator VertexIterator;
752  //typedef typename IndexSet::const_iterator Iterator;
753  typedef typename IS::const_iterator Iterator;
754 
755  VertexIterator vend = graph.end();
756  Iterator end;
757 
758  for(VertexIterator vertex = graph.begin(); vertex != vend; ++vertex) {
759  if (isOwner<F>(indexSet,*vertex)) {
760  // The type of const edge iterator.
761  typedef typename G::ConstEdgeIterator EdgeIterator;
762  EdgeIterator eend = vertex.end();
763  xadj[j] = ew.index();
764  j++;
765  for(EdgeIterator edge = vertex.begin(); edge != eend; ++edge) {
766  ew(edge);
767  }
768  }
769  }
770  xadj[j] = ew.index();
771  }
772  } // end anonymous namespace
773 
774  template<class G, class T1, class T2>
775  bool buildCommunication(const G& graph, std::vector<int>& realparts,
778  RedistributeInterface& redistInf,
779  bool verbose=false);
780 #if HAVE_PARMETIS
781 #ifndef METIS_VER_MAJOR
782  extern "C"
783  {
784  // backwards compatibility to parmetis < 4.0.0
785  void METIS_PartGraphKway(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt,
786  idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts,
787  int *options, int *edgecut, idxtype *part);
788 
789  void METIS_PartGraphRecursive(int *nvtxs, idxtype *xadj, idxtype *adjncy, idxtype *vwgt,
790  idxtype *adjwgt, int *wgtflag, int *numflag, int *nparts,
791  int *options, int *edgecut, idxtype *part);
792  }
793 #endif
794 #endif // HAVE_PARMETIS
795 
796  template<class S, class T>
797  inline void print_carray(S& os, T* array, std::size_t l)
798  {
799  for(T *cur=array, *end=array+l; cur!=end; ++cur)
800  os<<*cur<<" ";
801  }
802 
803  template<class S, class T>
804  inline bool isValidGraph(std::size_t noVtx, std::size_t gnoVtx, S noEdges, T* xadj,
805  T* adjncy, bool checkSymmetry)
806  {
807  bool correct=true;
808 
809  for(idxtype vtx=0; vtx<(idxtype)noVtx; ++vtx) {
810  if(xadj[vtx]>noEdges||xadj[vtx]<0) {
811  std::cerr <<"Check graph: xadj["<<vtx<<"]="<<xadj[vtx]<<" (>"
812  <<noEdges<<") out of range!"<<std::endl;
813  correct=false;
814  }
815  if(xadj[vtx+1]>noEdges||xadj[vtx+1]<0) {
816  std::cerr <<"Check graph: xadj["<<vtx+1<<"]="<<xadj[vtx+1]<<" (>"
817  <<noEdges<<") out of range!"<<std::endl;
818  correct=false;
819  }
820  // Check numbers in adjncy
821  for(idxtype i=xadj[vtx]; i< xadj[vtx+1]; ++i) {
822  if(adjncy[i]<0||((std::size_t)adjncy[i])>gnoVtx) {
823  std::cerr<<" Edge "<<adjncy[i]<<" out of range ["<<0<<","<<noVtx<<")"
824  <<std::endl;
825  correct=false;
826  }
827  }
828  if(checkSymmetry) {
829  for(idxtype i=xadj[vtx]; i< xadj[vtx+1]; ++i) {
830  idxtype target=adjncy[i];
831  // search for symmetric edge
832  int found=0;
833  for(idxtype j=xadj[target]; j< xadj[target+1]; ++j)
834  if(adjncy[j]==vtx)
835  found++;
836  if(found!=1) {
837  std::cerr<<"Edge ("<<target<<","<<vtx<<") "<<i<<" time"<<std::endl;
838  correct=false;
839  }
840  }
841  }
842  }
843  return correct;
844  }
845 
846  template<class M, class T1, class T2>
847  bool commGraphRepartition(const M& mat, Dune::OwnerOverlapCopyCommunication<T1,T2>& oocomm,
848  idxtype nparts,
850  RedistributeInterface& redistInf,
851  bool verbose=false)
852  {
853  if(verbose && oocomm.communicator().rank()==0)
854  std::cout<<"Repartitioning from "<<oocomm.communicator().size()
855  <<" to "<<nparts<<" parts"<<std::endl;
856  Timer time;
857  int rank = oocomm.communicator().rank();
858 #if !HAVE_PARMETIS
859  int* part = new int[1];
860  part[0]=0;
861 #else
862  idxtype* part = new idxtype[1]; // where all our data moves to
863 
864  if(nparts>1) {
865 
866  part[0]=rank;
867 
868  { // sublock for automatic memory deletion
869 
870  // Build the graph of the communication scheme and create an appropriate indexset.
871  // calculate the neighbour vertices
872  int noNeighbours = oocomm.remoteIndices().neighbours();
873  typedef typename Dune::OwnerOverlapCopyCommunication<T1,T2>::RemoteIndices RemoteIndices;
874  typedef typename RemoteIndices::const_iterator
875  NeighbourIterator;
876 
877  for(NeighbourIterator n= oocomm.remoteIndices().begin(); n != oocomm.remoteIndices().end();
878  ++n)
879  if(n->first==rank) {
880  //do not include ourselves.
881  --noNeighbours;
882  break;
883  }
884 
885  // A parmetis graph representing the communication graph.
886  // The diagonal entries are the number of nodes on the process.
887  // The offdiagonal entries are the number of edges leading to other processes.
888 
889  idxtype *xadj=new idxtype[2];
890  idxtype *vtxdist=new idxtype[oocomm.communicator().size()+1];
891  idxtype *adjncy=new idxtype[noNeighbours];
892 #ifdef USE_WEIGHTS
893  idxtype *vwgt = 0;
894  idxtype *adjwgt = 0;
895 #endif
896 
897  // each process has exactly one vertex!
898  for(int i=0; i<oocomm.communicator().size(); ++i)
899  vtxdist[i]=i;
900  vtxdist[oocomm.communicator().size()]=oocomm.communicator().size();
901 
902  xadj[0]=0;
903  xadj[1]=noNeighbours;
904 
905  // count edges to other processor
906  // a vector mapping the index to the owner
907  // std::vector<int> owner(mat.N(), oocomm.communicator().rank());
908  // for(NeighbourIterator n= oocomm.remoteIndices().begin(); n != oocomm.remoteIndices().end();
909  // ++n)
910  // {
911  // if(n->first!=oocomm.communicator().rank()){
912  // typedef typename RemoteIndices::RemoteIndexList RIList;
913  // const RIList& rlist = *(n->second.first);
914  // typedef typename RIList::const_iterator LIter;
915  // for(LIter entry=rlist.begin(); entry!=rlist.end(); ++entry){
916  // if(entry->attribute()==OwnerOverlapCopyAttributeSet::owner)
917  // owner[entry->localIndexPair().local()] = n->first;
918  // }
919  // }
920  // }
921 
922  // std::map<int,idxtype> edgecount; // edges to other processors
923  // typedef typename M::ConstRowIterator RIter;
924  // typedef typename M::ConstColIterator CIter;
925 
926  // // calculate edge count
927  // for(RIter row=mat.begin(), endr=mat.end(); row != endr; ++row)
928  // if(owner[row.index()]==OwnerOverlapCopyAttributeSet::owner)
929  // for(CIter entry= row->begin(), ende = row->end(); entry != ende; ++entry)
930  // ++edgecount[owner[entry.index()]];
931 
932  // setup edge and weight pattern
933  typedef typename RemoteIndices::const_iterator NeighbourIterator;
934 
935  idxtype* adjp=adjncy;
936 
937 #ifdef USE_WEIGHTS
938  vwgt = new idxtype[1];
939  vwgt[0]= mat.N(); // weight is numer of rows TODO: Should actually be the nonzeros.
940 
941  adjwgt = new idxtype[noNeighbours];
942  idxtype* adjwp=adjwgt;
943 #endif
944 
945  for(NeighbourIterator n= oocomm.remoteIndices().begin(); n != oocomm.remoteIndices().end();
946  ++n)
947  if(n->first != rank) {
948  *adjp=n->first;
949  ++adjp;
950 #ifdef USE_WEIGHTS
951  *adjwp=1; //edgecount[n->first];
952  ++adjwp;
953 #endif
954  }
955  assert(isValidGraph(vtxdist[rank+1]-vtxdist[rank],
956  vtxdist[oocomm.communicator().size()],
957  noNeighbours, xadj, adjncy, false));
958 
959  idxtype wgtflag=0, numflag=0;
960  idxtype edgecut;
961 #ifdef USE_WEIGHTS
962  wgtflag=3;
963 #endif
964  float *tpwgts = new float[nparts];
965  for(int i=0; i<nparts; ++i)
966  tpwgts[i]=1.0/nparts;
967  int options[5] ={ 0,1,15,0,0};
968  MPI_Comm comm=oocomm.communicator();
969 
970  Dune::dinfo<<rank<<" vtxdist: ";
971  print_carray(Dune::dinfo, vtxdist, oocomm.communicator().size()+1);
972  Dune::dinfo<<std::endl<<rank<<" xadj: ";
973  print_carray(Dune::dinfo, xadj, 2);
974  Dune::dinfo<<std::endl<<rank<<" adjncy: ";
975  print_carray(Dune::dinfo, adjncy, noNeighbours);
976 
977 #ifdef USE_WEIGHTS
978  Dune::dinfo<<std::endl<<rank<<" vwgt: ";
979  print_carray(Dune::dinfo, vwgt, 1);
980  Dune::dinfo<<std::endl<<rank<<" adwgt: ";
981  print_carray(Dune::dinfo, adjwgt, noNeighbours);
982 #endif
983  Dune::dinfo<<std::endl;
984  oocomm.communicator().barrier();
985  if(verbose && oocomm.communicator().rank()==0)
986  std::cout<<"Creating comm graph took "<<time.elapsed()<<std::endl;
987  time.reset();
988 
989 #ifdef PARALLEL_PARTITION
990  float ubvec = 1.15;
991  int ncon=1;
992 
993  //=======================================================
994  // ParMETIS_V3_PartKway
995  //=======================================================
996  ParMETIS_V3_PartKway(vtxdist, xadj, adjncy,
997  vwgt, adjwgt, &wgtflag,
998  &numflag, &ncon, &nparts, tpwgts, &ubvec, options, &edgecut, part,
999  &comm);
1000  if(verbose && oocomm.communicator().rank()==0)
1001  std::cout<<"ParMETIS took "<<time.elapsed()<<std::endl;
1002  time.reset();
1003 #else
1004  Timer time1;
1005  std::size_t gnoedges=0;
1006  int* noedges = 0;
1007  noedges = new int[oocomm.communicator().size()];
1008  Dune::dverb<<"noNeighbours: "<<noNeighbours<<std::endl;
1009  // gather number of edges for each vertex.
1010  MPI_Allgather(&noNeighbours,1,MPI_INT,noedges,1, MPI_INT,oocomm.communicator());
1011 
1012  if(verbose && oocomm.communicator().rank()==0)
1013  std::cout<<"Gathering noedges took "<<time1.elapsed()<<std::endl;
1014  time1.reset();
1015 
1016  idxtype noVertices = vtxdist[oocomm.communicator().size()];
1017  idxtype *gxadj = 0;
1018  idxtype *gvwgt = 0;
1019  idxtype *gadjncy = 0;
1020  idxtype *gadjwgt = 0;
1021  idxtype *gpart = 0;
1022  int* displ = 0;
1023  int* noxs = 0;
1024  int* xdispl = 0; // displacement for xadj
1025  int* novs = 0;
1026  int* vdispl=0; // real vertex displacement
1027 #ifdef USE_WEIGHTS
1028  std::size_t localNoVtx=vtxdist[rank+1]-vtxdist[rank];
1029 #endif
1030  std::size_t gxadjlen = vtxdist[oocomm.communicator().size()]-vtxdist[0]+oocomm.communicator().size();
1031 
1032  {
1033  Dune::dinfo<<"noedges: ";
1034  print_carray(Dune::dinfo, noedges, oocomm.communicator().size());
1035  Dune::dinfo<<std::endl;
1036  displ = new int[oocomm.communicator().size()];
1037  xdispl = new int[oocomm.communicator().size()];
1038  noxs = new int[oocomm.communicator().size()];
1039  vdispl = new int[oocomm.communicator().size()];
1040  novs = new int[oocomm.communicator().size()];
1041 
1042  for(int i=0; i < oocomm.communicator().size(); ++i) {
1043  noxs[i]=vtxdist[i+1]-vtxdist[i]+1;
1044  novs[i]=vtxdist[i+1]-vtxdist[i];
1045  }
1046 
1047  idxtype *so= vtxdist;
1048  int offset = 0;
1049  for(int *xcurr = xdispl, *vcurr = vdispl, *end=vdispl+oocomm.communicator().size();
1050  vcurr!=end; ++vcurr, ++xcurr, ++so, ++offset) {
1051  *vcurr = *so;
1052  *xcurr = offset + *so;
1053  }
1054 
1055  int *pdispl =displ;
1056  int cdispl = 0;
1057  *pdispl = 0;
1058  for(int *curr=noedges, *end=noedges+oocomm.communicator().size()-1;
1059  curr!=end; ++curr) {
1060  ++pdispl; // next displacement
1061  cdispl += *curr; // next value
1062  *pdispl = cdispl;
1063  }
1064  Dune::dinfo<<"displ: ";
1065  print_carray(Dune::dinfo, displ, oocomm.communicator().size());
1066  Dune::dinfo<<std::endl;
1067 
1068  // calculate global number of edges
1069  // It is bigger than the actual one as we habe size-1 additional end entries
1070  for(int *curr=noedges, *end=noedges+oocomm.communicator().size();
1071  curr!=end; ++curr)
1072  gnoedges += *curr;
1073 
1074  // alocate gobal graph
1075  Dune::dinfo<<"gxadjlen: "<<gxadjlen<<" noVertices: "<<noVertices
1076  <<" gnoedges: "<<gnoedges<<std::endl;
1077  gxadj = new idxtype[gxadjlen];
1078  gpart = new idxtype[noVertices];
1079 #ifdef USE_WEIGHTS
1080  gvwgt = new idxtype[noVertices];
1081  gadjwgt = new idxtype[gnoedges];
1082 #endif
1083  gadjncy = new idxtype[gnoedges];
1084  }
1085 
1086  if(verbose && oocomm.communicator().rank()==0)
1087  std::cout<<"Preparing global graph took "<<time1.elapsed()<<std::endl;
1088  time1.reset();
1089  // Communicate data
1090 
1091  MPI_Allgatherv(xadj,2,MPITraits<idxtype>::getType(),
1092  gxadj,noxs,xdispl,MPITraits<idxtype>::getType(),
1093  comm);
1094  MPI_Allgatherv(adjncy,noNeighbours,MPITraits<idxtype>::getType(),
1095  gadjncy,noedges,displ,MPITraits<idxtype>::getType(),
1096  comm);
1097 #ifdef USE_WEIGHTS
1098  MPI_Allgatherv(adjwgt,noNeighbours,MPITraits<idxtype>::getType(),
1099  gadjwgt,noedges,displ,MPITraits<idxtype>::getType(),
1100  comm);
1101  MPI_Allgatherv(vwgt,localNoVtx,MPITraits<idxtype>::getType(),
1102  gvwgt,novs,vdispl,MPITraits<idxtype>::getType(),
1103  comm);
1104 #endif
1105  if(verbose && oocomm.communicator().rank()==0)
1106  std::cout<<"Gathering global graph data took "<<time1.elapsed()<<std::endl;
1107  time1.reset();
1108 
1109  {
1110  // create the real gxadj array
1111  // i.e. shift entries and add displacements.
1112 
1113  print_carray(Dune::dinfo, gxadj, gxadjlen);
1114 
1115  int offset = 0;
1116  idxtype increment = vtxdist[1];
1117  idxtype *start=gxadj+1;
1118  for(int i=1; i<oocomm.communicator().size(); ++i) {
1119  offset+=1;
1120  int lprev = vtxdist[i]-vtxdist[i-1];
1121  int l = vtxdist[i+1]-vtxdist[i];
1122  start+=lprev;
1123  assert((start+l+offset)-gxadj<=static_cast<idxtype>(gxadjlen));
1124  increment = *(start-1);
1125  std::transform(start+offset, start+l+offset, start, std::bind2nd(std::plus<idxtype>(), increment));
1126  }
1127  Dune::dinfo<<std::endl<<"shifted xadj:";
1128  print_carray(Dune::dinfo, gxadj, noVertices+1);
1129  Dune::dinfo<<std::endl<<" gadjncy: ";
1130  print_carray(Dune::dinfo, gadjncy, gnoedges);
1131 #ifdef USE_WEIGHTS
1132  Dune::dinfo<<std::endl<<" gvwgt: ";
1133  print_carray(Dune::dinfo, gvwgt, noVertices);
1134  Dune::dinfo<<std::endl<<"adjwgt: ";
1135  print_carray(Dune::dinfo, gadjwgt, gnoedges);
1136  Dune::dinfo<<std::endl;
1137 #endif
1138  // everything should be fine now!!!
1139  if(verbose && oocomm.communicator().rank()==0)
1140  std::cout<<"Postprocesing global graph data took "<<time1.elapsed()<<std::endl;
1141  time1.reset();
1142 #ifndef NDEBUG
1143  assert(isValidGraph(noVertices, noVertices, gnoedges,
1144  gxadj, gadjncy, true));
1145 #endif
1146 
1147  if(verbose && oocomm.communicator().rank()==0)
1148  std::cout<<"Creating grah one 1 process took "<<time.elapsed()<<std::endl;
1149  time.reset();
1150  options[0]=0; options[1]=1; options[2]=1; options[3]=3; options[4]=3;
1151 #if METIS_VER_MAJOR >= 5
1152  idxtype ncon = 1;
1153  idxtype moptions[METIS_NOPTIONS];
1154  METIS_SetDefaultOptions(moptions);
1155  moptions[METIS_OPTION_NUMBERING] = numflag;
1156  METIS_PartGraphRecursive(&noVertices, &ncon, gxadj, gadjncy, gvwgt, NULL, gadjwgt,
1157  &nparts, NULL, NULL, moptions, &edgecut, gpart);
1158 #else
1159  // Call metis
1160  METIS_PartGraphRecursive(&noVertices, gxadj, gadjncy, gvwgt, gadjwgt, &wgtflag,
1161  &numflag, &nparts, options, &edgecut, gpart);
1162 #endif
1163 
1164  if(verbose && oocomm.communicator().rank()==0)
1165  std::cout<<"METIS took "<<time.elapsed()<<std::endl;
1166  time.reset();
1167 
1168  Dune::dinfo<<std::endl<<"part:";
1169  print_carray(Dune::dinfo, gpart, noVertices);
1170 
1171  delete[] gxadj;
1172  delete[] gadjncy;
1173 #ifdef USE_WEIGHTS
1174  delete[] gvwgt;
1175  delete[] gadjwgt;
1176 #endif
1177  }
1178  // Scatter result
1179  MPI_Scatter(gpart, 1, MPITraits<idxtype>::getType(), part, 1,
1180  MPITraits<idxtype>::getType(), 0, comm);
1181 
1182  {
1183  // release remaining memory
1184  delete[] gpart;
1185  delete[] noedges;
1186  delete[] displ;
1187  }
1188 
1189 
1190 #endif
1191  delete[] xadj;
1192  delete[] vtxdist;
1193  delete[] adjncy;
1194 #ifdef USE_WEIGHTS
1195  delete[] vwgt;
1196  delete[] adjwgt;
1197 #endif
1198  delete[] tpwgts;
1199  }
1200  }else{
1201  part[0]=0;
1202  }
1203 #endif
1204  Dune::dinfo<<" repart "<<rank <<" -> "<< part[0]<<std::endl;
1205 
1206  std::vector<int> realpart(mat.N(), part[0]);
1207  delete[] part;
1208 
1209  oocomm.copyOwnerToAll(realpart, realpart);
1210 
1211  if(verbose && oocomm.communicator().rank()==0)
1212  std::cout<<"Scattering repartitioning took "<<time.elapsed()<<std::endl;
1213  time.reset();
1214 
1215 
1216  oocomm.buildGlobalLookup(mat.N());
1217  Dune::Amg::MatrixGraph<M> graph(const_cast<M&>(mat));
1218  fillIndexSetHoles(graph, oocomm);
1219  if(verbose && oocomm.communicator().rank()==0)
1220  std::cout<<"Filling index set took "<<time.elapsed()<<std::endl;
1221  time.reset();
1222 
1223  if(verbose) {
1224  int noNeighbours=oocomm.remoteIndices().neighbours();
1225  noNeighbours = oocomm.communicator().sum(noNeighbours)
1226  / oocomm.communicator().size();
1227  if(oocomm.communicator().rank()==0)
1228  std::cout<<"Average no neighbours was "<<noNeighbours<<std::endl;
1229  }
1230  bool ret = buildCommunication(graph, realpart, oocomm, outcomm, redistInf,
1231  verbose);
1232  if(verbose && oocomm.communicator().rank()==0)
1233  std::cout<<"Building index sets took "<<time.elapsed()<<std::endl;
1234  time.reset();
1235 
1236 
1237  return ret;
1238 
1239  }
1240 
1255  template<class G, class T1, class T2>
1256  bool graphRepartition(const G& graph, Dune::OwnerOverlapCopyCommunication<T1,T2>& oocomm, idxtype nparts,
1258  RedistributeInterface& redistInf,
1259  bool verbose=false)
1260  {
1261  Timer time;
1262 
1263  MPI_Comm comm=oocomm.communicator();
1264  oocomm.buildGlobalLookup(graph.noVertices());
1265  fillIndexSetHoles(graph, oocomm);
1266 
1267  if(verbose && oocomm.communicator().rank()==0)
1268  std::cout<<"Filling holes took "<<time.elapsed()<<std::endl;
1269  time.reset();
1270 
1271  // simple precondition checks
1272 
1273 #ifdef PERF_REPART
1274  // Profiling variables
1275  double t1=0.0, t2=0.0, t3=0.0, t4=0.0, tSum=0.0;
1276 #endif
1277 
1278 
1279  // MPI variables
1280  int mype = oocomm.communicator().rank();
1281 
1282  assert(nparts<=oocomm.communicator().size());
1283 
1284  int myDomain = -1;
1285 
1286  //
1287  // 1) Prepare the required parameters for using ParMETIS
1288  // Especially the arrays that represent the graph must be
1289  // generated by the DUNE Graph and IndexSet input variables.
1290  // These are the arrays:
1291  // - vtxdist
1292  // - xadj
1293  // - adjncy
1294  //
1295  //
1296 #ifdef PERF_REPART
1297  // reset timer for step 1)
1298  t1=MPI_Wtime();
1299 #endif
1300 
1301 
1302  typedef typename Dune::OwnerOverlapCopyCommunication<T1,T2> OOComm;
1303  typedef typename OOComm::OwnerSet OwnerSet;
1304 
1305  // Create the vtxdist array and parmetisVtxMapping.
1306  // Global communications are necessary
1307  // The parmetis global identifiers for the owner vertices.
1308  ParmetisDuneIndexMap indexMap(graph,oocomm);
1309 #if HAVE_PARMETIS
1310  idxtype *part = new idxtype[indexMap.numOfOwnVtx()];
1311 #else
1312  std::size_t *part = new std::size_t[indexMap.numOfOwnVtx()];
1313 #endif
1314  for(std::size_t i=0; i < indexMap.numOfOwnVtx(); ++i)
1315  part[i]=mype;
1316 
1317 #if !HAVE_PARMETIS
1318  if(oocomm.communicator().rank()==0 && nparts>1)
1319  std::cerr<<"ParMETIS not activated. Will repartition to 1 domain instead of requested "
1320  <<nparts<<" domains."<<std::endl;
1321  nparts=1; // No parmetis available, fallback to agglomerating to 1 process
1322 
1323 #else
1324 
1325  if(nparts>1) {
1326  // Create the xadj and adjncy arrays
1327  idxtype *xadj = new idxtype[indexMap.numOfOwnVtx()+1];
1328  idxtype *adjncy = new idxtype[graph.noEdges()];
1329  EdgeFunctor<G> ef(adjncy, indexMap, graph.noEdges());
1330  getAdjArrays<OwnerSet>(graph, oocomm.globalLookup(), xadj, ef);
1331 
1332  //
1333  // 2) Call ParMETIS
1334  //
1335  //
1336  idxtype numflag=0, wgtflag=0, options[3], edgecut=0, ncon=1;
1337  //float *tpwgts = NULL;
1338  float *tpwgts = new float[nparts];
1339  for(int i=0; i<nparts; ++i)
1340  tpwgts[i]=1.0/nparts;
1341  float ubvec[1];
1342  options[0] = 0; // 0=default, 1=options are defined in [1]+[2]
1343 #ifdef DEBUG_REPART
1344  options[1] = 3; // show info: 0=no message
1345 #else
1346  options[1] = 0; // show info: 0=no message
1347 #endif
1348  options[2] = 1; // random number seed, default is 15
1349  wgtflag = (ef.getWeights()!=NULL) ? 1 : 0;
1350  numflag = 0;
1351  edgecut = 0;
1352  ncon=1;
1353  ubvec[0]=1.05; // recommended by ParMETIS
1354 
1355 #ifdef DEBUG_REPART
1356  if (mype == 0) {
1357  std::cout<<std::endl;
1358  std::cout<<"Testing ParMETIS_V3_PartKway with options[1-2] = {"
1359  <<options[1]<<" "<<options[2]<<"}, Ncon: "
1360  <<ncon<<", Nparts: "<<nparts<<std::endl;
1361  }
1362 #endif
1363 #ifdef PERF_REPART
1364  // stop the time for step 1)
1365  t1=MPI_Wtime()-t1;
1366  // reset timer for step 2)
1367  t2=MPI_Wtime();
1368 #endif
1369 
1370  if(verbose) {
1371  oocomm.communicator().barrier();
1372  if(oocomm.communicator().rank()==0)
1373  std::cout<<"Preparing for parmetis took "<<time.elapsed()<<std::endl;
1374  }
1375  time.reset();
1376 
1377  //=======================================================
1378  // ParMETIS_V3_PartKway
1379  //=======================================================
1380  ParMETIS_V3_PartKway(indexMap.vtxDist(), xadj, adjncy,
1381  NULL, ef.getWeights(), &wgtflag,
1382  &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgecut, part, &const_cast<MPI_Comm&>(comm));
1383 
1384 
1385  delete[] xadj;
1386  delete[] adjncy;
1387  delete[] tpwgts;
1388 
1389  ef.free();
1390 
1391 #ifdef DEBUG_REPART
1392  if (mype == 0) {
1393  std::cout<<std::endl;
1394  std::cout<<"ParMETIS_V3_PartKway reported a cut of "<<edgecut<<std::endl;
1395  std::cout<<std::endl;
1396  }
1397  std::cout<<mype<<": PARMETIS-Result: ";
1398  for(int i=0; i < indexMap.vtxDist()[mype+1]-indexMap.vtxDist()[mype]; ++i) {
1399  std::cout<<part[i]<<" ";
1400  }
1401  std::cout<<std::endl;
1402  std::cout<<"Testing ParMETIS_V3_PartKway with options[1-2] = {"
1403  <<options[1]<<" "<<options[2]<<"}, Ncon: "
1404  <<ncon<<", Nparts: "<<nparts<<std::endl;
1405 #endif
1406 #ifdef PERF_REPART
1407  // stop the time for step 2)
1408  t2=MPI_Wtime()-t2;
1409  // reset timer for step 3)
1410  t3=MPI_Wtime();
1411 #endif
1412 
1413 
1414  if(verbose) {
1415  oocomm.communicator().barrier();
1416  if(oocomm.communicator().rank()==0)
1417  std::cout<<"Parmetis took "<<time.elapsed()<<std::endl;
1418  }
1419  time.reset();
1420  }else
1421 #endif
1422  {
1423  // Everything goes to process 0!
1424  for(std::size_t i=0; i<indexMap.numOfOwnVtx(); ++i)
1425  part[i]=0;
1426  }
1427 
1428 
1429  //
1430  // 3) Find a optimal domain based on the ParMETIS repartitioning
1431  // result
1432  //
1433 
1434  std::vector<int> domainMapping(nparts);
1435  if(nparts>1)
1436  getDomain(comm, part, indexMap.numOfOwnVtx(), nparts, &myDomain, domainMapping);
1437  else
1438  domainMapping[0]=0;
1439 
1440 #ifdef DEBUG_REPART
1441  std::cout<<mype<<": myDomain: "<<myDomain<<std::endl;
1442  std::cout<<mype<<": DomainMapping: ";
1443  for(int j=0; j<nparts; j++) {
1444  std::cout<<" do: "<<j<<" pe: "<<domainMapping[j]<<" ";
1445  }
1446  std::cout<<std::endl;
1447 #endif
1448 
1449  // Make a domain mapping for the indexset and translate
1450  //domain number to real process number
1451  // domainMapping is the one of parmetis, that is without
1452  // the overlap/copy vertices
1453  std::vector<int> setPartition(oocomm.indexSet().size(), -1);
1454 
1455  typedef typename OOComm::ParallelIndexSet::const_iterator Iterator;
1456  std::size_t i=0; // parmetis index
1457  for(Iterator index = oocomm.indexSet().begin(); index != oocomm.indexSet().end(); ++index)
1458  if(OwnerSet::contains(index->local().attribute())) {
1459  setPartition[index->local()]=domainMapping[part[i++]];
1460  }
1461 
1462  delete[] part;
1463  oocomm.copyOwnerToAll(setPartition, setPartition);
1464  // communication only needed for ALU
1465  // (ghosts with same global id as owners on the same process)
1466  if (oocomm.getSolverCategory() ==
1467  static_cast<int>(SolverCategory::nonoverlapping))
1468  oocomm.copyCopyToAll(setPartition, setPartition);
1469  bool ret = buildCommunication(graph, setPartition, oocomm, outcomm, redistInf,
1470  verbose);
1471  if(verbose) {
1472  oocomm.communicator().barrier();
1473  if(oocomm.communicator().rank()==0)
1474  std::cout<<"Creating indexsets took "<<time.elapsed()<<std::endl;
1475  }
1476  return ret;
1477  }
1478 
1479 
1480 
1481  template<class G, class T1, class T2>
1482  bool buildCommunication(const G& graph,
1483  std::vector<int>& setPartition, Dune::OwnerOverlapCopyCommunication<T1,T2>& oocomm,
1485  RedistributeInterface& redistInf,
1486  bool verbose)
1487  {
1488  typedef typename Dune::OwnerOverlapCopyCommunication<T1,T2> OOComm;
1489  typedef typename OOComm::OwnerSet OwnerSet;
1490 
1491  Timer time;
1492 
1493  // Build the send interface
1494  redistInf.buildSendInterface<OwnerSet>(setPartition, oocomm.indexSet());
1495 
1496 #ifdef PERF_REPART
1497  // stop the time for step 3)
1498  t3=MPI_Wtime()-t3;
1499  // reset timer for step 4)
1500  t4=MPI_Wtime();
1501 #endif
1502 
1503 
1504  //
1505  // 4) Create the output IndexSet and RemoteIndices
1506  // 4.1) Determine the "send to" and "receive from" relation
1507  // according to the new partition using a MPI ring
1508  // communication.
1509  //
1510  // 4.2) Depends on the "send to" and "receive from" vector,
1511  // the processes will exchange the vertices each other
1512  //
1513  // 4.3) Create the IndexSet, RemoteIndices and the new MPI
1514  // communicator
1515  //
1516 
1517  //
1518  // 4.1) Let's start...
1519  //
1520  int npes = oocomm.communicator().size();
1521  int *sendTo = 0;
1522  int noSendTo = 0;
1523  std::set<int> recvFrom;
1524 
1525  // the max number of vertices is stored in the sendTo buffer,
1526  // not the number of vertices to send! Because the max number of Vtx
1527  // is used as the fixed buffer size by the MPI send/receive calls
1528 
1529  typedef typename std::vector<int>::const_iterator VIter;
1530  int mype = oocomm.communicator().rank();
1531 
1532  {
1533  std::set<int> tsendTo;
1534  for(VIter i=setPartition.begin(), iend = setPartition.end(); i!=iend; ++i)
1535  tsendTo.insert(*i);
1536 
1537  noSendTo = tsendTo.size();
1538  sendTo = new int[noSendTo];
1539  typedef std::set<int>::const_iterator iterator;
1540  int idx=0;
1541  for(iterator i=tsendTo.begin(); i != tsendTo.end(); ++i, ++idx)
1542  sendTo[idx]=*i;
1543  }
1544 
1545  //
1546  int* gnoSend= new int[oocomm.communicator().size()];
1547  int* gsendToDispl = new int[oocomm.communicator().size()+1];
1548 
1549  MPI_Allgather(&noSendTo, 1, MPI_INT, gnoSend, 1,
1550  MPI_INT, oocomm.communicator());
1551 
1552  // calculate total receive message size
1553  int totalNoRecv = 0;
1554  for(int i=0; i<npes; ++i)
1555  totalNoRecv += gnoSend[i];
1556 
1557  int *gsendTo = new int[totalNoRecv];
1558 
1559  // calculate displacement for allgatherv
1560  gsendToDispl[0]=0;
1561  for(int i=0; i<npes; ++i)
1562  gsendToDispl[i+1]=gsendToDispl[i]+gnoSend[i];
1563 
1564  // gather the data
1565  MPI_Allgatherv(sendTo, noSendTo, MPI_INT, gsendTo, gnoSend, gsendToDispl,
1566  MPI_INT, oocomm.communicator());
1567 
1568  // Extract from which processes we will receive data
1569  for(int proc=0; proc < npes; ++proc)
1570  for(int i=gsendToDispl[proc]; i < gsendToDispl[proc+1]; ++i)
1571  if(gsendTo[i]==mype)
1572  recvFrom.insert(proc);
1573 
1574  bool existentOnNextLevel = recvFrom.size()>0;
1575 
1576  // Delete memory
1577  delete[] gnoSend;
1578  delete[] gsendToDispl;
1579  delete[] gsendTo;
1580 
1581 
1582 #ifdef DEBUG_REPART
1583  if(recvFrom.size()) {
1584  std::cout<<mype<<": recvFrom: ";
1585  typedef typename std::set<int>::const_iterator siter;
1586  for(siter i=recvFrom.begin(); i!= recvFrom.end(); ++i) {
1587  std::cout<<*i<<" ";
1588  }
1589  }
1590 
1591  std::cout<<std::endl<<std::endl;
1592  std::cout<<mype<<": sendTo: ";
1593  for(int i=0; i<noSendTo; i++) {
1594  std::cout<<sendTo[i]<<" ";
1595  }
1596  std::cout<<std::endl<<std::endl;
1597 #endif
1598 
1599  if(verbose)
1600  if(oocomm.communicator().rank()==0)
1601  std::cout<<" Communicating the receive information took "<<
1602  time.elapsed()<<std::endl;
1603  time.reset();
1604 
1605  //
1606  // 4.2) Start the communication
1607  //
1608 
1609  // Get all the owner and overlap vertices for myself ans save
1610  // it in the vectors myOwnerVec and myOverlapVec.
1611  // The received vertices from the other processes are simple
1612  // added to these vector.
1613  //
1614 
1615 
1616  typedef typename OOComm::ParallelIndexSet::GlobalIndex GI;
1617  typedef std::vector<GI> GlobalVector;
1618  std::vector<std::pair<GI,int> > myOwnerVec;
1619  std::set<GI> myOverlapSet;
1620  GlobalVector sendOwnerVec;
1621  std::set<GI> sendOverlapSet;
1622  std::set<int> myNeighbors;
1623 
1624  // getOwnerOverlapVec<OwnerSet>(graph, setPartition, oocomm.globalLookup(),
1625  // mype, mype, myOwnerVec, myOverlapSet, redistInf, myNeighbors);
1626 
1627  char **sendBuffers=new char*[noSendTo];
1628  MPI_Request *requests = new MPI_Request[noSendTo];
1629 
1630  // Create all messages to be sent
1631  for(int i=0; i < noSendTo; ++i) {
1632  // clear the vector for sending
1633  sendOwnerVec.clear();
1634  sendOverlapSet.clear();
1635  // get all owner and overlap vertices for process j and save these
1636  // in the vectors sendOwnerVec and sendOverlapSet
1637  std::set<int> neighbors;
1638  getOwnerOverlapVec<OwnerSet>(graph, setPartition, oocomm.globalLookup(),
1639  mype, sendTo[i], sendOwnerVec, sendOverlapSet, redistInf,
1640  neighbors);
1641  // +2, we need 2 integer more for the length of each part
1642  // (owner/overlap) of the array
1643  int buffersize=0;
1644  int tsize;
1645  MPI_Pack_size(1, MPITraits<std::size_t>::getType(), oocomm.communicator(), &buffersize);
1646  MPI_Pack_size(sendOwnerVec.size(), MPITraits<GI>::getType(), oocomm.communicator(), &tsize);
1647  buffersize +=tsize;
1648  MPI_Pack_size(1, MPITraits<std::size_t>::getType(), oocomm.communicator(), &tsize);
1649  buffersize +=tsize;
1650  MPI_Pack_size(sendOverlapSet.size(), MPITraits<GI>::getType(), oocomm.communicator(), &tsize);
1651  buffersize += tsize;
1652  MPI_Pack_size(1, MPITraits<std::size_t>::getType(), oocomm.communicator(), &tsize);
1653  buffersize += tsize;
1654  MPI_Pack_size(neighbors.size(), MPI_INT, oocomm.communicator(), &tsize);
1655  buffersize += tsize;
1656 
1657  sendBuffers[i] = new char[buffersize];
1658 
1659 #ifdef DEBUG_REPART
1660  std::cout<<mype<<" sending "<<sendOwnerVec.size()<<" owner and "<<
1661  sendOverlapSet.size()<<" overlap to "<<sendTo[i]<<" buffersize="<<buffersize<<std::endl;
1662 #endif
1663  createSendBuf(sendOwnerVec, sendOverlapSet, neighbors, sendBuffers[i], buffersize, oocomm.communicator());
1664  MPI_Issend(sendBuffers[i], buffersize, MPI_PACKED, sendTo[i], 99, oocomm.communicator(), requests+i);
1665  }
1666 
1667  if(verbose) {
1668  oocomm.communicator().barrier();
1669  if(oocomm.communicator().rank()==0)
1670  std::cout<<" Creating sends took "<<
1671  time.elapsed()<<std::endl;
1672  }
1673  time.reset();
1674 
1675  // Receive Messages
1676  int noRecv = recvFrom.size();
1677  int oldbuffersize=0;
1678  char* recvBuf = 0;
1679  while(noRecv>0) {
1680  // probe for an incoming message
1681  MPI_Status stat;
1682  MPI_Probe(MPI_ANY_SOURCE, 99, oocomm.communicator(), &stat);
1683  int buffersize;
1684  MPI_Get_count(&stat, MPI_PACKED, &buffersize);
1685 
1686  if(oldbuffersize<buffersize) {
1687  // buffer too small, reallocate
1688  delete[] recvBuf;
1689  recvBuf = new char[buffersize];
1690  oldbuffersize = buffersize;
1691  }
1692  MPI_Recv(recvBuf, buffersize, MPI_PACKED, stat.MPI_SOURCE, 99, oocomm.communicator(), &stat);
1693  saveRecvBuf(recvBuf, buffersize, myOwnerVec, myOverlapSet, myNeighbors, redistInf,
1694  stat.MPI_SOURCE, oocomm.communicator());
1695  --noRecv;
1696  }
1697 
1698  if(recvBuf)
1699  delete[] recvBuf;
1700 
1701  time.reset();
1702  // Wait for sending messages to complete
1703  MPI_Status *statuses = new MPI_Status[noSendTo];
1704  int send = MPI_Waitall(noSendTo, requests, statuses);
1705 
1706  // check for errors
1707  if(send==MPI_ERR_IN_STATUS) {
1708  std::cerr<<mype<<": Error in sending :"<<std::endl;
1709  // Search for the error
1710  for(int i=0; i< noSendTo; i++)
1711  if(statuses[i].MPI_ERROR!=MPI_SUCCESS) {
1712  char message[300];
1713  int messageLength;
1714  MPI_Error_string(statuses[i].MPI_ERROR, message, &messageLength);
1715  std::cerr<<" source="<<statuses[i].MPI_SOURCE<<" message: ";
1716  for(int j = 0; j < messageLength; j++)
1717  std::cout<<message[j];
1718  }
1719  std::cerr<<std::endl;
1720  }
1721 
1722  if(verbose) {
1723  oocomm.communicator().barrier();
1724  if(oocomm.communicator().rank()==0)
1725  std::cout<<" Receiving and saving took "<<
1726  time.elapsed()<<std::endl;
1727  }
1728  time.reset();
1729 
1730  for(int i=0; i < noSendTo; ++i)
1731  delete[] sendBuffers[i];
1732 
1733  delete[] sendBuffers;
1734  delete[] statuses;
1735  delete[] requests;
1736 
1737  redistInf.setCommunicator(oocomm.communicator());
1738 
1739  //
1740  // 4.2) Create the IndexSet etc.
1741  //
1742 
1743  // build the new outputIndexSet
1744 
1745 
1746  int color=0;
1747 
1748  if (!existentOnNextLevel) {
1749  // this process is not used anymore
1750  color= MPI_UNDEFINED;
1751  }
1752  MPI_Comm outputComm;
1753 
1754  MPI_Comm_split(oocomm.communicator(), color, oocomm.communicator().rank(), &outputComm);
1755  outcomm = new OOComm(outputComm,oocomm.getSolverCategory(),true);
1756 
1757  // translate neighbor ranks.
1758  int newrank=outcomm->communicator().rank();
1759  int *newranks=new int[oocomm.communicator().size()];
1760  std::vector<int> tneighbors;
1761  tneighbors.reserve(myNeighbors.size());
1762 
1763  typename OOComm::ParallelIndexSet& outputIndexSet = outcomm->indexSet();
1764 
1765  MPI_Allgather(&newrank, 1, MPI_INT, newranks, 1,
1766  MPI_INT, oocomm.communicator());
1767  typedef typename std::set<int>::const_iterator IIter;
1768 
1769 #ifdef DEBUG_REPART
1770  std::cout<<oocomm.communicator().rank()<<" ";
1771  for(IIter i=myNeighbors.begin(), end=myNeighbors.end();
1772  i!=end; ++i) {
1773  assert(newranks[*i]>=0);
1774  std::cout<<*i<<"->"<<newranks[*i]<<" ";
1775  tneighbors.push_back(newranks[*i]);
1776  }
1777  std::cout<<std::endl;
1778 #else
1779  for(IIter i=myNeighbors.begin(), end=myNeighbors.end();
1780  i!=end; ++i) {
1781  tneighbors.push_back(newranks[*i]);
1782  }
1783 #endif
1784  delete[] newranks;
1785  myNeighbors.clear();
1786 
1787  if(verbose) {
1788  oocomm.communicator().barrier();
1789  if(oocomm.communicator().rank()==0)
1790  std::cout<<" Calculating new neighbours ("<<tneighbors.size()<<") took "<<
1791  time.elapsed()<<std::endl;
1792  }
1793  time.reset();
1794 
1795 
1796  outputIndexSet.beginResize();
1797  // 1) add the owner vertices
1798  // Sort the owners
1799  std::sort(myOwnerVec.begin(), myOwnerVec.end(), SortFirst());
1800  // The owners are sorted according to there global index
1801  // Therefore the entries of ownerVec are the same as the
1802  // ones in the resulting index set.
1803  typedef typename OOComm::ParallelIndexSet::LocalIndex LocalIndex;
1804  typedef typename std::vector<std::pair<GI,int> >::const_iterator VPIter;
1805  int i=0;
1806  for(VPIter g=myOwnerVec.begin(), end =myOwnerVec.end(); g!=end; ++g, ++i ) {
1807  outputIndexSet.add(g->first,LocalIndex(i, OwnerOverlapCopyAttributeSet::owner, true));
1808  redistInf.addReceiveIndex(g->second, i);
1809  }
1810 
1811  if(verbose) {
1812  oocomm.communicator().barrier();
1813  if(oocomm.communicator().rank()==0)
1814  std::cout<<" Adding owner indices took "<<
1815  time.elapsed()<<std::endl;
1816  }
1817  time.reset();
1818 
1819 
1820  // After all the vertices are received, the vectors must
1821  // be "merged" together to create the final vectors.
1822  // Because some vertices that are sent as overlap could now
1823  // already included as owner vertiecs in the new partition
1824  mergeVec(myOwnerVec, myOverlapSet);
1825 
1826  // Trick to free memory
1827  myOwnerVec.clear();
1828  myOwnerVec.swap(myOwnerVec);
1829 
1830  if(verbose) {
1831  oocomm.communicator().barrier();
1832  if(oocomm.communicator().rank()==0)
1833  std::cout<<" Merging indices took "<<
1834  time.elapsed()<<std::endl;
1835  }
1836  time.reset();
1837 
1838 
1839  // 2) add the overlap vertices
1840  typedef typename std::set<GI>::const_iterator SIter;
1841  for(SIter g=myOverlapSet.begin(), end=myOverlapSet.end(); g!=end; ++g, i++) {
1842  outputIndexSet.add(*g,LocalIndex(i, OwnerOverlapCopyAttributeSet::copy, true));
1843  }
1844  myOverlapSet.clear();
1845  outputIndexSet.endResize();
1846 
1847 #ifdef DUNE_ISTL_WITH_CHECKING
1848  int numOfOwnVtx =0;
1849  typedef typename OOComm::ParallelIndexSet::const_iterator Iterator;
1850  Iterator end = outputIndexSet.end();
1851  for(Iterator index = outputIndexSet.begin(); index != end; ++index) {
1852  if (OwnerSet::contains(index->local().attribute())) {
1853  numOfOwnVtx++;
1854  }
1855  }
1856  numOfOwnVtx = oocomm.communicator().sum(numOfOwnVtx);
1857  // if(numOfOwnVtx!=indexMap.globalOwnerVertices)
1858  // {
1859  // std::cerr<<numOfOwnVtx<<"!="<<indexMap.globalOwnerVertices<<" owners missing or additional ones!"<<std::endl;
1860  // DUNE_THROW(ISTLError, numOfOwnVtx<<"!="<<indexMap.globalOwnerVertices<<" owners missing or additional ones"
1861  // <<" during repartitioning.");
1862  // }
1863  Iterator index=outputIndexSet.begin();
1864  if(index!=end) {
1865  ++index;
1866  for(Iterator old = outputIndexSet.begin(); index != end; old=index++) {
1867  if(old->global()>index->global())
1868  DUNE_THROW(ISTLError, "Index set's globalindex not sorted correctly");
1869  }
1870  }
1871 #endif
1872  if(verbose) {
1873  oocomm.communicator().barrier();
1874  if(oocomm.communicator().rank()==0)
1875  std::cout<<" Adding overlap indices took "<<
1876  time.elapsed()<<std::endl;
1877  }
1878  time.reset();
1879 
1880 
1881  if(color != MPI_UNDEFINED) {
1882  outcomm->remoteIndices().setNeighbours(tneighbors);
1883  outcomm->remoteIndices().template rebuild<true>();
1884 
1885  }
1886 
1887  // release the memory
1888  delete[] sendTo;
1889 
1890  if(verbose) {
1891  oocomm.communicator().barrier();
1892  if(oocomm.communicator().rank()==0)
1893  std::cout<<" Storing indexsets took "<<
1894  time.elapsed()<<std::endl;
1895  }
1896 
1897 #ifdef PERF_REPART
1898  // stop the time for step 4) and print the results
1899  t4=MPI_Wtime()-t4;
1900  tSum = t1 + t2 + t3 + t4;
1901  std::cout<<std::endl
1902  <<mype<<": WTime for step 1): "<<t1
1903  <<" 2): "<<t2
1904  <<" 3): "<<t3
1905  <<" 4): "<<t4
1906  <<" total: "<<tSum
1907  <<std::endl;
1908 #endif
1909 
1910  return color!=MPI_UNDEFINED;
1911 
1912  }
1913 #else
1914  template<class G, class P,class T1, class T2, class R>
1915  bool graphRepartition(const G& graph, P& oocomm, int nparts,
1916  P*& outcomm,
1917  R& redistInf,
1918  bool v=false)
1919  {
1920  if(nparts!=oocomm.size())
1921  DUNE_THROW(NotImplemented, "only available for MPI programs");
1922  }
1923 
1924 
1925  template<class G, class P,class T1, class T2, class R>
1926  bool commGraphRepartition(const G& graph, P& oocomm, int nparts,
1927  P*& outcomm,
1928  R& redistInf,
1929  bool v=false)
1930  {
1931  if(nparts!=oocomm.size())
1932  DUNE_THROW(NotImplemented, "only available for MPI programs");
1933  }
1934 #endif // HAVE_MPI
1935 } // end of namespace Dune
1936 #endif
The (undirected) graph of a matrix.
Definition: graph.hh:49
int rank() const
Return rank, is between 0 and size()-1.
Definition: mpicollectivecommunication.hh:166
T max(T &in) const
Compute the maximum of the argument over all processes and return the result in every process....
Definition: mpicollectivecommunication.hh:228
int size() const
Number of processes in set, is greater than 0.
Definition: mpicollectivecommunication.hh:172
int barrier() const
Wait until all processes have arrived at this point in the program.
Definition: mpicollectivecommunication.hh:243
T sum(T &in) const
Compute the sum of the argument over all processes and return the result in every process....
Definition: mpicollectivecommunication.hh:179
Index Set Interface base class.
Definition: indexidset.hh:76
IndexType size(GeometryType type) const
Return total number of entities of given geometry type in entity set .
Definition: indexidset.hh:220
MPI_Comm communicator_
The MPI communicator we use.
Definition: interface.hh:314
size_type N() const
Return the number of rows.
Definition: matrix.hh:690
A class setting up standard communication for a two-valued attribute set with owner/overlap/copy sema...
Definition: owneroverlapcopy.hh:172
const ParallelIndexSet & indexSet() const
Get the underlying parallel index set.
Definition: owneroverlapcopy.hh:463
void copyCopyToAll(const T &source, T &dest) const
Communicate values from copy data points to all other data points.
Definition: owneroverlapcopy.hh:332
const RemoteIndices & remoteIndices() const
Get the underlying remote indices.
Definition: owneroverlapcopy.hh:472
void copyOwnerToAll(const T &source, T &dest) const
Communicate values from owner data points to all other data points.
Definition: owneroverlapcopy.hh:315
SolverCategory::Category getSolverCategory() const
Get Solver Category.
Definition: owneroverlapcopy.hh:299
Manager class for the mapping between local indices and globally unique indices.
Definition: indexset.hh:217
LocalIndex::Attribute Attribute
The type of the attribute.
Definition: remoteindices.hh:218
const_iterator end() const
Get an iterator over all remote index lists.
Definition: remoteindices.hh:1530
int neighbours() const
Get the number of processors we share indices with.
Definition: remoteindices.hh:1447
const_iterator begin() const
Get an iterator over all remote index lists.
Definition: remoteindices.hh:1523
A simple stop watch.
Definition: timer.hh:52
void reset()
Reset timer while keeping the running/stopped state.
Definition: timer.hh:66
double elapsed() const
Get elapsed user-time from last reset until now/last stop in seconds.
Definition: timer.hh:86
Provides utility classes for syncing distributed data via MPI communication.
Classes for building sets out of enumeration values.
Provides classes for building the matrix graph.
const IndexPair * pair(const std::size_t &local) const
Get the index pair corresponding to a local index.
size_t size() const
Get the total number (public and nonpublic) indices.
void repairLocalIndexPointers(std::map< int, SLList< std::pair< typename T::GlobalIndex, typename T::LocalIndex::Attribute >, A > > &globalMap, RemoteIndices< T, A1 > &remoteIndices, const T &indexSet)
Repair the pointers to the local indices in the remote indices.
Definition: indicessyncer.hh:490
iterator begin()
Get an iterator over the indices positioned at the first index.
iterator end()
Get an iterator over the indices positioned after the last index.
const InformationMap & interfaces() const
Get information about the interfaces.
Definition: interface.hh:422
void storeGlobalIndicesOfRemoteIndices(std::map< int, SLList< std::pair< typename T::GlobalIndex, typename T::LocalIndex::Attribute >, A > > &globalMap, const RemoteIndices< T, A1 > &remoteIndices)
Stores the corresponding global indices of the remote index information.
Definition: indicessyncer.hh:461
#define DUNE_THROW(E, m)
Definition: exceptions.hh:216
DInfoType dinfo(std::cout)
Stream for informative output.
Definition: stdstreams.hh:138
DVerbType dverb(std::cout)
Singleton of verbose debug stream.
Definition: stdstreams.hh:114
Provides a map between global and local indices.
Class for adding missing indices of a distributed index set in a local communication.
Traits classes for mapping types onto MPI_Datatype.
Dune namespace.
Definition: alignment.hh:11
bool graphRepartition(const G &graph, Dune::OwnerOverlapCopyCommunication< T1, T2 > &oocomm, idxtype nparts, Dune::OwnerOverlapCopyCommunication< T1, T2 > *&outcomm, RedistributeInterface &redistInf, bool verbose=false)
execute a graph repartition for a giving graph and indexset.
Definition: repartition.hh:1256
void fillIndexSetHoles(const G &graph, Dune::OwnerOverlapCopyCommunication< T1, T2 > &oocomm)
Fills the holes in an index set.
Definition: repartition.hh:58
Classes providing communication interfaces for overlapping Schwarz methods.
Classes describing a distributed indexset.
Standard Dune debug streams.
A traits class describing the mapping of types onto MPI_Datatypes.
Definition: mpitraits.hh:39
@ nonoverlapping
Category for non-overlapping solvers.
Definition: solvercategory.hh:23
A simple timing class.
Definition of the DUNE_UNUSED macro for the case that config.h is not available.
#define DUNE_UNUSED_PARAMETER(parm)
A macro to mark intentionally unused function parameters with.
Definition: unused.hh:18
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.80.0 (May 16, 22:29, 2024)