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