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