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_INTERFACE_HH
4 #define DUNE_INTERFACE_HH
5 
6 #if HAVE_MPI
7 
8 #include "remoteindices.hh"
9 #include <dune/common/enumset.hh>
10 
11 namespace Dune
12 {
13   /** @addtogroup Common_Parallel
14    *
15    * @{
16    */
17   /**
18    * @file
19    * @brief Provides classes for building the communication
20    * interface between remote indices.
21    * @author Markus Blatt
22    */
23 
24   /** @} */
25   /**
26    * @brief Base class of all classes representing a communication
27    * interface.
28    *
29    * It provides an generic utility method for building the interface
30    * for a set of remote indices.
31    */
32   class InterfaceBuilder
33   {
34   public:
35     class RemoteIndicesStateError : public InvalidStateException
36     {};
37 
~InterfaceBuilder()38     virtual ~InterfaceBuilder()
39     {}
40 
41   protected:
42     /**
43      * @brief Not for public use.
44      */
InterfaceBuilder()45     InterfaceBuilder()
46     {}
47 
48     /**
49      * @brief Builds the interface between remote processes.
50      *
51      *
52      * The types T1 and T2 are classes representing a set of
53      * enumeration values of type InterfaceBuilder::Attribute. They have to provide
54      * a (static) method
55      * \code
56      * bool contains(Attribute flag) const;
57      * \endcode
58      * for checking whether the set contains a specific flag.
59      * This functionality is for example provided the classes
60      * EnumItem, EnumRange and Combine.
61      *
62      * If the template parameter send is true the sending side of
63      * the interface will be built, otherwise the information for
64      * receiving will be built.
65      *
66      *
67      * If the template parameter send is true we create interface for sending
68      * in a forward communication.
69      *
70      * @param remoteIndices The indices known to remote processes.
71      * @param sourceFlags The set of flags marking source indices.
72      * @param destFlags The setof flags markig destination indices.
73      * @param functor A functor for callbacks. It should provide the
74      * following methods:
75      * \code
76      * // Reserve memory for the interface to processor proc. The interface
77      * // has to hold size entries
78      * void reserve(int proc, int size);
79      *
80      * // Add an entry to the interface
81      * // We will send/receive size entries at index local to process proc
82      * void add(int proc, int local);
83      * \endcode
84      */
85     template<class R, class T1, class T2, class Op, bool send>
86     void buildInterface (const R& remoteIndices,
87                          const T1& sourceFlags, const T2& destFlags,
88                          Op& functor) const;
89   };
90 
91   /**
92    * @brief Information describing an interface.
93    *
94    * This class is used for temporary gathering information
95    * about the interface needed for actually building it. It
96    * is used be class Interface as functor for InterfaceBuilder::build.
97    */
98   class InterfaceInformation
99   {
100 
101   public:
102 
103     /**
104      * @brief Get the number of entries in the interface.
105      */
size() const106     size_t size() const
107     {
108       return size_;
109     }
110     /**
111      * @brief Get the local index for an entry.
112      * @param i The  index of the entry.
113      */
operator [](size_t i)114     std::size_t& operator[](size_t i)
115     {
116       assert(i<size_);
117       return indices_[i];
118     }
119     /**
120      * @brief Get the local index for an entry.
121      * @param i The  index of the entry.
122      */
operator [](size_t i) const123     std::size_t operator[](size_t i) const
124     {
125       assert(i<size_);
126       return indices_[i];
127     }
128     /**
129      * @brief Reserve space for a number of entries.
130      * @param size The maximum number of entries to hold.
131      */
reserve(size_t size)132     void reserve(size_t size)
133     {
134       indices_ = new std::size_t[size];
135       maxSize_ = size;
136 
137     }
138     /**
139      * brief Frees allocated memory.
140      */
free()141     void free()
142     {
143       if(indices_)
144         delete[] indices_;
145       maxSize_ = 0;
146       size_=0;
147       indices_=0;
148     }
149     /**
150      * @brief Add a new index to the interface.
151      */
add(std::size_t index)152     void add(std::size_t index)
153     {
154       assert(size_<maxSize_);
155       indices_[size_++]=index;
156     }
157 
InterfaceInformation()158     InterfaceInformation()
159       : size_(0), maxSize_(0), indices_(0)
160     {}
161 
~InterfaceInformation()162     virtual ~InterfaceInformation()
163     {}
164 
operator !=(const InterfaceInformation & o) const165     bool operator!=(const InterfaceInformation& o) const
166     {
167       return !operator==(o);
168     }
169 
operator ==(const InterfaceInformation & o) const170     bool operator==(const InterfaceInformation& o) const
171     {
172       if(size_!=o.size_)
173         return false;
174       for(std::size_t i=0; i< size_; ++i)
175         if(indices_[i]!=o.indices_[i])
176           return false;
177       return true;
178     }
179 
180   private:
181     /**
182      * @brief The number of entries in the interface.
183      */
184     size_t size_;
185     /**
186      * @brief The maximum number of indices we can hold.
187      */
188     size_t maxSize_;
189     /**
190      * @brief The local indices of the interface.
191      */
192     std::size_t* indices_;
193   };
194 
195   /** @addtogroup Common_Parallel
196    *
197    * @{
198    */
199 
200   /**
201    * @brief Communication interface between remote and local indices.
202    *
203    * Describes the communication interface between
204    * indices on the local process and those on remote processes.
205    */
206   class Interface : public InterfaceBuilder
207   {
208 
209   public:
210     /**
211      * @brief The type of the map form process number to InterfaceInformation for
212      * sending and receiving to and from it.
213      */
214     typedef std::map<int,std::pair<InterfaceInformation,InterfaceInformation> > InformationMap;
215 
216     /**
217      * @brief Builds the interface.
218      *
219      * The types T1 and T2 are classes representing a set of
220      * enumeration values of type Interface::Attribute. They have to provide
221      * a (static) method
222      * \code
223      * bool contains(Attribute flag) const;
224      * \endcode
225      * for checking whether the set contains a specific flag.
226      * This functionality is for example provided the classes
227      * EnumItem, EnumRange and Combine.
228      * @param remoteIndices The indices known to remote processes.
229      * @param sourceFlags The set of flags marking indices we send from.
230      * @param destFlags The set of flags marking indices we receive for.
231      */
232     template<typename R, typename T1, typename T2>
233     void build(const R& remoteIndices, const T1& sourceFlags,
234                const T2& destFlags);
235 
236     /**
237      * @brief Frees memory allocated during the build.
238      */
239     void free();
240 
241     /**
242      * @brief Get the MPI Communicator.
243      */
244     MPI_Comm communicator() const;
245 
246     /**
247      * @brief Get information about the interfaces.
248      *
249      * @return Map of the interfaces.
250      * The key of the map is the process number and the value
251      * is the information pair (first the send and then the receive
252      * information).
253      */
254     const InformationMap& interfaces() const;
255 
Interface(MPI_Comm comm)256     Interface(MPI_Comm comm)
257       : communicator_(comm), interfaces_()
258     {}
259 
Interface()260     Interface()
261       : communicator_(MPI_COMM_NULL), interfaces_()
262     {}
263 
264     /**
265      * @brief Print the interface to std::out for debugging.
266      */
267     void print() const;
268 
operator !=(const Interface & o) const269     bool operator!=(const Interface& o) const
270     {
271       return ! operator==(o);
272     }
273 
operator ==(const Interface & o) const274     bool operator==(const Interface& o) const
275     {
276       if(communicator_!=o.communicator_)
277         return false;
278       if(interfaces_.size()!=o.interfaces_.size())
279         return false;
280       typedef InformationMap::const_iterator MIter;
281 
282       for(MIter m=interfaces_.begin(), om=o.interfaces_.begin();
283           m!=interfaces_.end(); ++m, ++om)
284       {
285         if(om->first!=m->first)
286           return false;
287         if(om->second.first!=om->second.first)
288           return false;
289         if(om->second.second!=om->second.second)
290           return false;
291       }
292       return true;
293     }
294 
295     /**
296      * @brief Destructor.
297      */
298     virtual ~Interface();
299 
300     void strip();
301   protected:
302 
303     /**
304      * @brief Get information about the interfaces.
305      *
306      * @return Map of the interfaces.
307      * The key of the map is the process number and the value
308      * is the information pair (first the send and then the receive
309      * information).
310      */
311     InformationMap& interfaces();
312 
313     /** @brief The MPI communicator we use. */
314     MPI_Comm communicator_;
315 
316   private:
317     /**
318      * @brief Information about the interfaces.
319      *
320      * The key of the map is the process number and the value
321      * is the information pair (first the send and then the receive
322      * information).
323      */
324     InformationMap interfaces_;
325 
326     template<bool send>
327     class InformationBuilder
328     {
329     public:
InformationBuilder(InformationMap & interfaces)330       InformationBuilder(InformationMap& interfaces)
331         : interfaces_(interfaces)
332       {}
333 
reserve(int proc,int size)334       void reserve(int proc, int size)
335       {
336         if(send)
337           interfaces_[proc].first.reserve(size);
338         else
339           interfaces_[proc].second.reserve(size);
340       }
add(int proc,std::size_t local)341       void add(int proc, std::size_t local)
342       {
343         if(send) {
344           interfaces_[proc].first.add(local);
345         }else{
346           interfaces_[proc].second.add(local);
347         }
348       }
349 
350     private:
351       InformationMap& interfaces_;
352     };
353   };
354 
355   template<class R, class T1, class T2, class Op, bool send>
buildInterface(const R & remoteIndices,const T1 & sourceFlags,const T2 & destFlags,Op & interfaceInformation) const356   void InterfaceBuilder::buildInterface(const R& remoteIndices, const T1& sourceFlags, const T2& destFlags, Op& interfaceInformation) const
357   {
358 
359     if(!remoteIndices.isSynced())
360       DUNE_THROW(RemoteIndicesStateError,"RemoteIndices is not in sync with the index set. Call RemoteIndices::rebuild first!");
361     // Allocate the memory for the data type construction.
362     typedef R RemoteIndices;
363     typedef typename RemoteIndices::RemoteIndexMap::const_iterator const_iterator;
364 
365     const const_iterator end=remoteIndices.end();
366 
367     int rank;
368 
369     MPI_Comm_rank(remoteIndices.communicator(), &rank);
370 
371     // Allocate memory for the type construction.
372     for(const_iterator process=remoteIndices.begin(); process != end; ++process) {
373       // Messure the number of indices send to the remote process first
374       int size=0;
375       typedef typename RemoteIndices::RemoteIndexList::const_iterator RemoteIterator;
376       const RemoteIterator remoteEnd = send ? process->second.first->end() :
377                                        process->second.second->end();
378       RemoteIterator remote = send ? process->second.first->begin() : process->second.second->begin();
379 
380       while(remote!=remoteEnd) {
381         if( send ?  destFlags.contains(remote->attribute()) :
382             sourceFlags.contains(remote->attribute())) {
383 
384           // do we send the index?
385           if( send ? sourceFlags.contains(remote->localIndexPair().local().attribute()) :
386               destFlags.contains(remote->localIndexPair().local().attribute()))
387             ++size;
388         }
389         ++remote;
390       }
391       interfaceInformation.reserve(process->first, size);
392     }
393 
394     // compare the local and remote indices and set up the types
395 
396     for(const_iterator process=remoteIndices.begin(); process != end; ++process) {
397       typedef typename RemoteIndices::RemoteIndexList::const_iterator RemoteIterator;
398       const RemoteIterator remoteEnd = send ? process->second.first->end() :
399                                        process->second.second->end();
400       RemoteIterator remote = send ? process->second.first->begin() : process->second.second->begin();
401 
402       while(remote!=remoteEnd) {
403         if( send ?  destFlags.contains(remote->attribute()) :
404             sourceFlags.contains(remote->attribute())) {
405           // do we send the index?
406           if( send ? sourceFlags.contains(remote->localIndexPair().local().attribute()) :
407               destFlags.contains(remote->localIndexPair().local().attribute()))
408             interfaceInformation.add(process->first,remote->localIndexPair().local().local());
409         }
410         ++remote;
411       }
412     }
413   }
414 
communicator() const415   inline MPI_Comm Interface::communicator() const
416   {
417     return communicator_;
418 
419   }
420 
421 
interfaces() const422   inline const std::map<int,std::pair<InterfaceInformation,InterfaceInformation> >& Interface::interfaces() const
423   {
424     return interfaces_;
425   }
426 
interfaces()427   inline std::map<int,std::pair<InterfaceInformation,InterfaceInformation> >& Interface::interfaces()
428   {
429     return interfaces_;
430   }
431 
print() const432   inline void Interface::print() const
433   {
434     typedef InformationMap::const_iterator const_iterator;
435     const const_iterator end=interfaces_.end();
436     int rank;
437     MPI_Comm_rank(communicator(), &rank);
438 
439     for(const_iterator infoPair=interfaces_.begin(); infoPair!=end; ++infoPair) {
440       {
441         std::cout<<rank<<": send for process "<<infoPair->first<<": ";
442         const InterfaceInformation& info(infoPair->second.first);
443         for(size_t i=0; i < info.size(); i++)
444           std::cout<<info[i]<<" ";
445         std::cout<<std::endl;
446       } {
447 
448         std::cout<<rank<<": receive for process "<<infoPair->first<<": ";
449         const InterfaceInformation& info(infoPair->second.second);
450         for(size_t i=0; i < info.size(); i++)
451           std::cout<<info[i]<<" ";
452         std::cout<<std::endl;
453       }
454 
455     }
456   }
457 
458   template<typename R, typename T1, typename T2>
build(const R & remoteIndices,const T1 & sourceFlags,const T2 & destFlags)459   inline void Interface::build(const R& remoteIndices, const T1& sourceFlags,
460                                const T2& destFlags)
461   {
462     communicator_=remoteIndices.communicator();
463 
464     assert(interfaces_.empty());
465 
466     // Build the send interface
467     InformationBuilder<true> sendInformation(interfaces_);
468     this->template buildInterface<R,T1,T2,InformationBuilder<true>,true>(remoteIndices, sourceFlags,
469                                                                          destFlags, sendInformation);
470 
471     // Build the receive interface
472     InformationBuilder<false> recvInformation(interfaces_);
473     this->template buildInterface<R,T1,T2,InformationBuilder<false>,false>(remoteIndices,sourceFlags,
474                                                                            destFlags, recvInformation);
475     strip();
476   }
strip()477   inline void Interface::strip()
478   {
479     typedef InformationMap::iterator const_iterator;
480     for(const_iterator interfacePair = interfaces_.begin(); interfacePair != interfaces_.end();)
481       if(interfacePair->second.first.size()==0 && interfacePair->second.second.size()==0) {
482         interfacePair->second.first.free();
483         interfacePair->second.second.free();
484         const_iterator toerase=interfacePair++;
485         interfaces_.erase(toerase);
486       }else
487         ++interfacePair;
488   }
489 
free()490   inline void Interface::free()
491   {
492     typedef InformationMap::iterator iterator;
493     typedef InformationMap::const_iterator const_iterator;
494     const const_iterator end = interfaces_.end();
495     for(iterator interfacePair = interfaces_.begin(); interfacePair != end; ++interfacePair) {
496       interfacePair->second.first.free();
497       interfacePair->second.second.free();
498     }
499     interfaces_.clear();
500   }
501 
~Interface()502   inline Interface::~Interface()
503   {
504     free();
505   }
506   /** @} */
507 
operator <<(std::ostream & os,const Interface & interface)508   inline std::ostream& operator<<(std::ostream& os, const Interface& interface)
509   {
510     typedef Interface::InformationMap InfoMap;
511     typedef InfoMap::const_iterator Iter;
512     for(Iter i=interface.interfaces().begin(), end = interface.interfaces().end();
513         i!=end; ++i)
514     {
515       os<<i->first<<": [ source=[";
516       for(std::size_t j=0; j < i->second.first.size(); ++j)
517         os<<i->second.first[j]<<" ";
518       os<<"] size="<<i->second.first.size()<<", target=[";
519       for(std::size_t j=0; j < i->second.second.size(); ++j)
520         os<<i->second.second[j]<<" ";
521       os<<"] size="<<i->second.second.size()<<"\n";
522     }
523     return os;
524   }
525 }
526 #endif // HAVE_MPI
527 
528 #endif
529