Dune Core Modules (2.5.0)

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
14extern "C"
15{
16#include <parmetis.h>
17}
18#endif
19
20#include <dune/common/timer.hh>
21#include <dune/common/unused.hh>
29
32
41namespace 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++;
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 {
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) {
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();
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
void copyOwnerToAll(const T &source, T &dest) const
Communicate values from owner data points to all other data points.
Definition: owneroverlapcopy.hh:315
const RemoteIndices & remoteIndices() const
Get the underlying remote indices.
Definition: owneroverlapcopy.hh:472
SolverCategory::Category getSolverCategory() const
Get Solver Category.
Definition: owneroverlapcopy.hh:299
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.
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
const IndexPair * pair(const std::size_t &local) const
Get the index pair corresponding to a local index.
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.111.3 (Nov 13, 23:29, 2024)