1 #ifndef DUNE_FEM_SPACE_COMMON_AUXILIARYDOFS_HH 2 #define DUNE_FEM_SPACE_COMMON_AUXILIARYDOFS_HH 3 4 #include <cassert> 5 #include <cstddef> 6 7 #include <algorithm> 8 #include <iostream> 9 #include <iterator> 10 #include <limits> 11 #include <map> 12 #include <memory> 13 #include <set> 14 15 #include <dune/common/exceptions.hh> 16 #include <dune/common/genericiterator.hh> 17 #include <dune/common/ftraits.hh> 18 #include <dune/common/typetraits.hh> 19 20 #include <dune/grid/common/gridenums.hh> 21 #include <dune/grid/common/datahandleif.hh> 22 23 #include <dune/fem/storage/singletonlist.hh> 24 #include <dune/fem/misc/mpimanager.hh> 25 #include <dune/fem/space/common/commindexmap.hh> 26 #include <dune/fem/storage/envelope.hh> 27 28 namespace Dune 29 { 30 31 namespace Fem 32 { 33 34 /** @addtogroup Communication Communication 35 @{ 36 **/ 37 38 /** \brief @ingroup Communication 39 * 40 * In parallel computations the dofs of a discrete function are made up by 41 * all primary dofs. For technical reasons some dofs exists on multiply 42 * processes but are only primary on exactly one process. Dofs on processes 43 * that are not primary are called auxiliary. 44 */ 45 template< class GridPart, class Mapper > 46 class AuxiliaryDofs 47 { 48 typedef AuxiliaryDofs< GridPart, Mapper > ThisType; 49 50 class LinkBuilder; 51 52 public: 53 /** \brief type of grid part **/ 54 typedef GridPart GridPartType; 55 56 //! type of used mapper 57 typedef Mapper MapperType; 58 59 protected: 60 typedef Fem :: CommunicationIndexMap IndexMapType; 61 62 const GridPartType &gridPart_; 63 const MapperType &mapper_; 64 65 // type of communication indices 66 IndexMapType auxiliarys_; 67 68 public: 69 struct ConstIterator 70 : public std::iterator< std::forward_iterator_tag, const int, int > 71 { 72 ConstIterator () = default; ConstIteratorDune::Fem::AuxiliaryDofs::ConstIterator73 ConstIterator ( const IndexMapType &auxiliarys, int index ) : auxiliarys_( &auxiliarys ), index_( index ) {} 74 operator *Dune::Fem::AuxiliaryDofs::ConstIterator75 const int &operator* () const { return (*auxiliarys_)[ index_ ]; } operator ->Dune::Fem::AuxiliaryDofs::ConstIterator76 const int *operator-> () const { return &(*auxiliarys_)[ index_ ]; } 77 operator []Dune::Fem::AuxiliaryDofs::ConstIterator78 const int &operator[] ( int n ) const noexcept { return (*auxiliarys_)[ index_ + n ]; } 79 operator ==Dune::Fem::AuxiliaryDofs::ConstIterator80 bool operator== ( const ConstIterator &other ) const { return (index_ == other.index_); } operator !=Dune::Fem::AuxiliaryDofs::ConstIterator81 bool operator!= ( const ConstIterator &other ) const { return (index_ != other.index_); } 82 operator ++Dune::Fem::AuxiliaryDofs::ConstIterator83 ConstIterator &operator++ () { ++index_; return *this; } operator ++Dune::Fem::AuxiliaryDofs::ConstIterator84 ConstIterator operator++ ( int ) { ConstIterator copy( *this ); ++(*this); return copy; } 85 operator --Dune::Fem::AuxiliaryDofs::ConstIterator86 ThisType &operator-- () noexcept { --index_; return *this; } operator --Dune::Fem::AuxiliaryDofs::ConstIterator87 ThisType operator-- ( int ) noexcept { ThisType copy( *this ); --(*this); return copy; } 88 operator +=Dune::Fem::AuxiliaryDofs::ConstIterator89 ThisType &operator+= ( int n ) noexcept { index_ += n; return *this; } operator -=Dune::Fem::AuxiliaryDofs::ConstIterator90 ThisType &operator-= ( int n ) noexcept { index_ -= n; return *this; } 91 operator +Dune::Fem::AuxiliaryDofs::ConstIterator92 ThisType operator+ ( int n ) const noexcept { return ThisType( index_ + n ); } operator -Dune::Fem::AuxiliaryDofs::ConstIterator93 ThisType operator- ( int n ) const noexcept { return ThisType( index_ - n ); } 94 operator +(int n,const ThisType & i)95 friend ThisType operator+ ( int n, const ThisType &i ) noexcept { return i + n; } 96 operator -Dune::Fem::AuxiliaryDofs::ConstIterator97 int operator- ( const ThisType &other ) const noexcept { return (index_ - other.index_); } 98 operator <Dune::Fem::AuxiliaryDofs::ConstIterator99 bool operator< ( const ThisType &other ) const noexcept { return (index_ < other.index_); } operator <=Dune::Fem::AuxiliaryDofs::ConstIterator100 bool operator<= ( const ThisType &other ) const noexcept { return (index_ <= other.index_); } operator >=Dune::Fem::AuxiliaryDofs::ConstIterator101 bool operator>= ( const ThisType &other ) const noexcept { return (index_ >= other.index_); } operator >Dune::Fem::AuxiliaryDofs::ConstIterator102 bool operator> ( const ThisType &other ) const noexcept { return (index_ > other.index_); } 103 104 private: 105 const IndexMapType *auxiliarys_ = nullptr; 106 int index_ = 0; 107 }; 108 AuxiliaryDofs(const GridPartType & gridPart,const MapperType & mapper)109 AuxiliaryDofs ( const GridPartType &gridPart, const MapperType &mapper ) 110 : gridPart_( gridPart ), mapper_( mapper ) 111 {} 112 113 AuxiliaryDofs ( const AuxiliaryDofs& ) = delete; 114 115 //! return dof number of auxiliary for index operator [](const int index) const116 int operator [] ( const int index ) const 117 { 118 return auxiliarys_[ index ]; 119 } 120 121 //! return number of auxiliary dofs size() const122 int size () const 123 { 124 return auxiliarys_.size(); 125 } 126 begin() const127 ConstIterator begin () const { return ConstIterator( auxiliarys_, 0 ); } end() const128 ConstIterator end () const { assert( size() > 0 ); return ConstIterator( auxiliarys_, size()-1 ); } 129 130 //! return true if index is contained, meaning it is a auxiliary dof contains(int index) const131 bool contains ( int index ) const { return std::binary_search( begin(), end(), index ); } 132 133 [[deprecated("Use contains instead")]] isSlave(int index) const134 bool isSlave ( int index ) const { return contains( index ); } 135 rebuild()136 void rebuild () 137 { 138 std::set< int > auxiliarySet; 139 buildMaps( auxiliarySet ); 140 auxiliarys_.clear(); 141 auxiliarys_.set( auxiliarySet ); 142 } 143 gridPart() const144 const GridPartType &gridPart () const { return gridPart_; } 145 146 protected: buildMaps(std::set<int> & auxiliarySet)147 void buildMaps ( std::set< int > &auxiliarySet ) 148 { 149 // build linkage and index maps 150 for( int codim = 1; codim <= GridPartType::dimension; ++codim ) 151 { 152 if( mapper_.contains( codim ) ) 153 return buildCommunicatedMaps( auxiliarySet ); 154 } 155 return buildDiscontinuousMaps( auxiliarySet ); 156 } 157 buildDiscontinuousMaps(std::set<int> & auxiliarySet)158 void buildDiscontinuousMaps ( std::set< int > &auxiliarySet ) 159 { 160 // if DoFs are only attached to codimension 0, we do not have to communicate 161 const auto idxpitype = GridPartType::indexSetPartitionType; 162 for( auto it = gridPart().template begin< 0, idxpitype >(), end = gridPart().template end< 0, idxpitype >(); it != end; ++it ) 163 { 164 const auto& entity = *it; 165 if( entity.partitionType() != Dune::InteriorEntity ) 166 mapper_.mapEachEntityDof( entity, [ &auxiliarySet ] ( int, int value ) { auxiliarySet.insert( value ); } ); 167 } 168 // insert overall size at the end 169 auxiliarySet.insert( mapper_.size() ); 170 } 171 buildCommunicatedMaps(std::set<int> & auxiliarySet)172 void buildCommunicatedMaps ( std::set< int > &auxiliarySet ) 173 { 174 // we have to skip communication when parallel program is executed only on one processor 175 // otherwise YaspGrid and Lagrange polorder=2 fails :( 176 if( gridPart().comm().size() > 1 ) 177 { 178 try 179 { 180 LinkBuilder handle( auxiliarySet, gridPart(), mapper_ ); 181 gridPart().communicate( handle, GridPartType::indexSetInterfaceType, ForwardCommunication ); 182 } 183 catch( const Exception &e ) 184 { 185 std::cerr << e << std::endl << "Exception thrown in: " << __FILE__ << " line:" << __LINE__ << std::endl; 186 std::abort(); 187 } 188 } 189 // insert overall size at the end 190 auxiliarySet.insert( mapper_.size() ); 191 } 192 }; 193 194 195 196 // AuxiliaryDofs::LinkBuilder 197 // ---------------------- 198 199 template< class GridPart, class Mapper > 200 class AuxiliaryDofs< GridPart, Mapper >::LinkBuilder 201 : public CommDataHandleIF< LinkBuilder, int > 202 { 203 public: LinkBuilder(std::set<int> & auxiliarySet,const GridPartType & gridPart,const MapperType & mapper)204 LinkBuilder( std::set< int > &auxiliarySet, const GridPartType &gridPart, const MapperType &mapper ) 205 : myRank_( gridPart.comm().rank() ), mySize_( gridPart.comm().size() ), 206 auxiliarySet_( auxiliarySet ), mapper_( mapper ) 207 {} 208 contains(int dim,int codim) const209 bool contains ( int dim, int codim ) const { return mapper_.contains( codim ); } fixedSize(int dim,int codim) const210 bool fixedSize ( int dim, int codim ) const { return false; } 211 212 //! read buffer and apply operation 213 template< class MessageBuffer, class Entity > gather(MessageBuffer & buffer,const Entity & entity) const214 void gather ( MessageBuffer &buffer, const Entity &entity ) const 215 { 216 // for sending ranks write rank 217 if( sendRank( entity ) ) 218 buffer.write( myRank_ ); 219 } 220 221 //! read buffer and apply operation 222 //! scatter is called for one every entity 223 //! several times depending on how much data 224 //! was gathered 225 template< class MessageBuffer, class EntityType > scatter(MessageBuffer & buffer,const EntityType & entity,std::size_t n)226 void scatter ( MessageBuffer &buffer, const EntityType &entity, std::size_t n ) 227 { 228 if( n == 1 ) 229 { 230 int rank; 231 buffer.read( rank ); 232 233 assert( (rank >= 0) && (rank < mySize_) ); 234 235 // if entity in not interiorBorder insert anyway 236 if ( rank < myRank_ || ! sendRank( entity ) ) 237 mapper_.mapEachEntityDof( entity, [this]( const int , const auto& value ){auxiliarySet_.insert( value );} ); 238 } 239 } 240 241 //! return local dof size to be communicated 242 template< class Entity > size(const Entity & entity) const243 std::size_t size ( const Entity &entity ) const 244 { 245 return (sendRank( entity )) ? 1 : 0; 246 } 247 248 protected: 249 template <class Entity> sendRank(const Entity & entity) const250 bool sendRank(const Entity& entity) const 251 { 252 const PartitionType ptype = entity.partitionType(); 253 return (ptype == InteriorEntity) || (ptype == BorderEntity); 254 } 255 256 private: 257 int myRank_, mySize_; 258 std::set< int > &auxiliarySet_; 259 const MapperType &mapper_; 260 }; 261 262 263 264 // PrimaryDofs 265 // ----------- 266 267 /** \brief @ingroup Communication 268 * 269 * In parallel computations the dofs of a discrete function are made up by 270 * all primary dofs. For technical reasons some dofs exists on multiply 271 * processes but are only primary on exactly one process. 272 */ 273 template< class AuxiliaryDofs > 274 struct PrimaryDofs; 275 276 template< class GridPart, class Mapper > 277 struct PrimaryDofs< AuxiliaryDofs< GridPart, Mapper > > 278 { 279 typedef AuxiliaryDofs< GridPart, Mapper > AuxiliaryDofsType; 280 281 struct ConstIterator 282 : public std::iterator< std::forward_iterator_tag, int, std::ptrdiff_t, Envelope< int >, int > 283 { 284 ConstIterator () = default; 285 ConstIteratorDune::Fem::PrimaryDofs::ConstIterator286 ConstIterator ( int index, int auxiliary ) 287 : index_( index ), auxiliary_( auxiliary ) 288 {} 289 ConstIteratorDune::Fem::PrimaryDofs::ConstIterator290 ConstIterator ( const AuxiliaryDofsType &auxiliaryDofs, int index, int auxiliary ) 291 : auxiliaryDofs_( &auxiliaryDofs ), index_( index ), auxiliary_( auxiliary ) 292 { 293 skipAuxiliarys(); 294 } 295 operator *Dune::Fem::PrimaryDofs::ConstIterator296 int operator* () const { return index_; } operator ->Dune::Fem::PrimaryDofs::ConstIterator297 Envelope< int > operator-> () const { return Envelope< int >( index_ ); } 298 operator ==Dune::Fem::PrimaryDofs::ConstIterator299 bool operator== ( const ConstIterator &other ) const { return (index_ == other.index_); } operator !=Dune::Fem::PrimaryDofs::ConstIterator300 bool operator!= ( const ConstIterator &other ) const { return (index_ != other.index_); } 301 operator ++Dune::Fem::PrimaryDofs::ConstIterator302 ConstIterator &operator++ () { ++index_; skipAuxiliarys(); return *this; } operator ++Dune::Fem::PrimaryDofs::ConstIterator303 ConstIterator operator++ ( int ) { ConstIterator copy( *this ); ++(*this); return copy; } 304 auxiliaryDofsDune::Fem::PrimaryDofs::ConstIterator305 const AuxiliaryDofsType &auxiliaryDofs () const { assert( auxiliaryDofs_ ); return *auxiliaryDofs_; } 306 containsDune::Fem::PrimaryDofs::ConstIterator307 bool contains( const int index ) const { return ! auxiliaryDofs().contains( index ); } 308 309 private: skipAuxiliarysDune::Fem::PrimaryDofs::ConstIterator310 void skipAuxiliarys () 311 { 312 const int aSize = auxiliaryDofs().size(); 313 assert( auxiliary_ < aSize ); 314 for( ; (index_ == auxiliaryDofs()[ auxiliary_ ]) && (++auxiliary_ != aSize); ++index_ ) 315 continue; 316 } 317 318 const AuxiliaryDofsType *auxiliaryDofs_ = nullptr; 319 int index_ = 0, auxiliary_ = 0; 320 }; 321 PrimaryDofsDune::Fem::PrimaryDofs322 explicit PrimaryDofs ( const AuxiliaryDofsType &auxiliaryDofs ) 323 : auxiliaryDofs_( auxiliaryDofs ) 324 {} 325 beginDune::Fem::PrimaryDofs326 ConstIterator begin () const { return ConstIterator( auxiliaryDofs_, 0, 0 ); } endDune::Fem::PrimaryDofs327 ConstIterator end () const { return ConstIterator( auxiliaryDofs_[ auxiliaryDofs_.size()-1 ], auxiliaryDofs_.size() ); } 328 sizeDune::Fem::PrimaryDofs329 int size () const { return auxiliaryDofs_[ auxiliaryDofs_.size()-1 ] - (auxiliaryDofs_.size()-1); } 330 331 private: 332 const AuxiliaryDofsType &auxiliaryDofs_; 333 }; 334 335 336 337 // primaryDofs 338 // ----------- 339 340 template< class AuxiliaryDofs > primaryDofs(const AuxiliaryDofs & auxiliaryDofs)341 inline static PrimaryDofs< AuxiliaryDofs > primaryDofs ( const AuxiliaryDofs &auxiliaryDofs ) 342 { 343 return PrimaryDofs< AuxiliaryDofs >( auxiliaryDofs ); 344 } 345 346 template< class AuxiliaryDofs > 347 [[deprecated("Use primaryDofs instead!" )]] masterDofs(const AuxiliaryDofs & auxiliaryDofs)348 inline static PrimaryDofs< AuxiliaryDofs > masterDofs ( const AuxiliaryDofs &auxiliaryDofs ) 349 { 350 return PrimaryDofs< AuxiliaryDofs >( auxiliaryDofs ); 351 } 352 353 //@} 354 355 } // end namespace Fem 356 357 } // end namespace Dune 358 #endif // #ifndef DUNE_FEM_SPACE_COMMON_AUXILIARYDOFS_HH 359