1 // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi: set et ts=4 sw=2 sts=2:
3 
4 #ifndef DUNE_GRID_TEST_CHECKPARTITION_HH
5 #define DUNE_GRID_TEST_CHECKPARTITION_HH
6 
7 #include <cstddef>
8 
9 #include <bitset>
10 #include <set>
11 #include <map>
12 #include <utility>
13 
14 #include <dune/common/hybridutilities.hh>
15 #include <dune/common/typetraits.hh>
16 
17 #include <dune/grid/common/capabilities.hh>
18 #include <dune/grid/common/datahandleif.hh>
19 #include <dune/grid/common/gridenums.hh>
20 #include <dune/grid/utility/entitycommhelper.hh>
21 
22 template< Dune::PartitionIteratorType pitype >
23 struct PartitionFilter;
24 
25 template<>
26 struct PartitionFilter< Dune::Interior_Partition >
27 {
containsPartitionFilter28   static bool contains ( const Dune::PartitionType partitionType )
29   {
30     return (partitionType == Dune::InteriorEntity);
31   }
32 };
33 
34 template<>
35 struct PartitionFilter< Dune::InteriorBorder_Partition >
36 {
containsPartitionFilter37   static bool contains ( const Dune::PartitionType partitionType )
38   {
39     return (partitionType == Dune::InteriorEntity) || (partitionType == Dune::BorderEntity);
40   }
41 };
42 
43 template<>
44 struct PartitionFilter< Dune::Overlap_Partition >
45 {
containsPartitionFilter46   static bool contains ( const Dune::PartitionType partitionType )
47   {
48     return (partitionType != Dune::FrontEntity) && (partitionType != Dune::GhostEntity);
49   }
50 };
51 
52 template<>
53 struct PartitionFilter< Dune::OverlapFront_Partition >
54 {
containsPartitionFilter55   static bool contains ( const Dune::PartitionType partitionType )
56   {
57     return (partitionType != Dune::GhostEntity);
58   }
59 };
60 
61 template<>
62 struct PartitionFilter< Dune::All_Partition >
63 {
containsPartitionFilter64   static bool contains ([[maybe_unused]] const Dune::PartitionType partitionType)
65   {
66     return true;
67   }
68 };
69 
70 template<>
71 struct PartitionFilter< Dune::Ghost_Partition >
72 {
containsPartitionFilter73   static bool contains ( const Dune::PartitionType partitionType )
74   {
75     return (partitionType == Dune::GhostEntity);
76   }
77 };
78 
79 
80 
possibleSubPartitionType(Dune::PartitionType ept,Dune::PartitionType pt)81 inline bool possibleSubPartitionType ( Dune::PartitionType ept, Dune::PartitionType pt )
82 {
83   switch( ept )
84   {
85   case Dune::InteriorEntity :
86     return (pt == Dune::InteriorEntity) || (pt == Dune::BorderEntity);
87   case Dune::OverlapEntity :
88     return (pt == Dune::BorderEntity) || (pt == Dune::OverlapEntity) || (pt == Dune::FrontEntity);
89   case Dune::GhostEntity :
90     return (pt == Dune::BorderEntity) || (pt == Dune::FrontEntity) || (pt == Dune::GhostEntity);
91   default :
92     std::cerr << "Error: Codimension 0 entity cannot be of partition type " << ept << "." << std::endl;
93     return false;
94   }
95 }
96 
97 
98 
99 template< class GridView, Dune::PartitionIteratorType pitype >
100 class CheckPartitionType
101 {
102   template< int codim >
103   struct CheckCodim;
104 
105 public:
apply(const GridView & gridView)106   static void apply ( const GridView &gridView )
107   {
108     std::cout << "Checking iterators for " << pitype << "..." << std::endl;
109     Dune::Hybrid::forEach( std::make_index_sequence< GridView::dimension+1 >{}, [ & ]( auto i ){ CheckCodim< i >::apply( gridView ); } );
110   }
111 };
112 
113 
114 template< class GridView, Dune::PartitionIteratorType pitype >
115 template< int codim >
116 struct CheckPartitionType< GridView, pitype >::CheckCodim
117 {
118   typedef typename GridView::template Codim< codim >::template Partition< pitype >::Iterator Iterator;
119   typedef typename GridView::template Codim< 0 >::template Partition< Dune::All_Partition >::Iterator AllIterator;
120 
121   template< class IdSet >
checkCheckPartitionType::CheckCodim122   static void check ( const std::true_type &, const GridView &gridView,
123                       const IdSet &idSet )
124   {
125     typedef std::map< typename IdSet::IdType, Dune::PartitionType > Map;
126     typedef typename Map::iterator MapIterator;
127     Map map;
128 
129     try {
130       const Iterator end = gridView.template end< codim, pitype >();
131       for( Iterator it = gridView.template begin< codim, pitype >(); it != end; ++it )
132       {
133         Dune::PartitionType pt = it->partitionType();
134         if( !PartitionFilter< pitype >::contains( pt ) )
135         {
136           std::cerr << "Error: Codim " << codim << " iterator for the " << pitype
137                     << " visited entity " << idSet.id( *it )
138                     << " with partition type " << pt << "." << std::endl;
139         }
140         map[ idSet.id( *it ) ] = pt;
141       }
142 
143       const AllIterator allEnd = gridView.template end< 0, Dune::All_Partition >();
144       for( AllIterator it = gridView.template begin< 0, Dune::All_Partition >(); it != allEnd; ++it )
145       {
146         Dune::PartitionType ept = it->partitionType();
147         const int subEntities = it->subEntities(codim);
148         for( int i = 0; i < subEntities; ++i )
149         {
150           Dune::PartitionType pt = it->template subEntity< codim >( i ).partitionType();
151           if( !possibleSubPartitionType( ept, pt ) )
152           {
153             std::cerr << "Error: Codim " << codim << " entity " << idSet.subId( *it, i, codim )
154                       << " with partition type " << pt << " is a subentity of entity "
155                       << idSet.id( *it ) << " with partition type " << ept << "." << std::endl;
156           }
157 
158           const MapIterator mapIt = map.find( idSet.subId( *it, i, codim ) );
159           if( mapIt == map.end() )
160           {
161             if( PartitionFilter< pitype >::contains( pt ) )
162             {
163               std::cerr << "Error: Codim " << codim << " entity " << idSet.subId( *it, i, codim )
164                         << " with partition type " << pt << " is not visited by codim " << codim
165                         << " iterator for the " << pitype << "." << std::endl;
166             }
167           }
168           else
169           {
170             if( pt != mapIt->second )
171             {
172               std::cerr << "Error: Codim " << codim << " entity " << idSet.subId( *it, i, codim )
173                         << " with partition type " << pt << " reported partition type "
174                         << mapIt->second << " when accessed with the codim " << codim
175                         << " iterator for the " << pitype << "." << std::endl;
176             }
177           }
178         }
179       }
180     }
181     catch( const Dune::Exception &exception )
182     {
183       std::cerr << "Error: Caught  exception when testing partition iterator for the " << pitype
184                 << "(" << exception << ")." << std::endl;
185     }
186   }
187 
188   template< class IdSet >
checkCheckPartitionType::CheckCodim189   static void check (const std::false_type &,
190                      [[maybe_unused]] const GridView &gridView,
191                      [[maybe_unused]] const IdSet &idSet)
192   {}
193 
applyCheckPartitionType::CheckCodim194   static void apply ( const GridView &gridView )
195   {
196     std::integral_constant<
197         bool, Dune::Capabilities::hasEntity< typename GridView::Grid, codim >::v && Dune::Capabilities::hasEntityIterator< typename GridView::Grid, codim >::v
198         > capabilityVariable;
199     check( capabilityVariable, gridView, gridView.grid().localIdSet() );
200   }
201 };
202 
203 
204 
205 template< class GridView, Dune::InterfaceType iftype  >
206 class CheckPartitionDataHandle
207   : public Dune::CommDataHandleIF< CheckPartitionDataHandle< GridView, iftype >, int >
208 {
209   static const int dimension = GridView::dimension;
210 
211   typedef typename GridView::Grid Grid;
212   typedef typename Grid::LocalIdSet IdSet;
213 
214   typedef std::set< typename IdSet::IdType > CommSet;
215 
216 public:
CheckPartitionDataHandle(const GridView & gridView)217   explicit CheckPartitionDataHandle ( const GridView &gridView )
218     : gridView_( gridView ),
219       rank_( gridView_.comm().rank() ),
220       idSet_( gridView_.grid().localIdSet() ),
221       invalidDimension_( false ),
222       invalidCodimension_( false ),
223       invalidEntity_( false ),
224       invalidSendEntity_( false ),
225       invalidReceiveEntity_( false ),
226       invalidSize_( false ),
227       selfReceive_( false ),
228       doubleInterior_( false ),
229       interiorBorder_( false )
230   {
231     Dune::Hybrid::forEach( std::make_index_sequence< dimension+1 >{},
232       [ & ]( auto i ){ contains_[ i ] = Dune::Capabilities::canCommunicate< Grid, i >::v; } );
233   }
234 
~CheckPartitionDataHandle()235   ~CheckPartitionDataHandle ()
236   {
237     bool sendFailure = false;
238     bool receiveFailure = false;
239 
240     typedef typename GridView::template Codim< 0 >::Iterator Iterator;
241     typedef typename GridView::template Codim< 0 >::Entity Entity;
242     const Iterator end = gridView_.template end< 0 >();
243     for( Iterator it = gridView_.template begin< 0 >(); it != end; ++it )
244     {
245       const Entity entity = *it;
246 
247       if( entity.partitionType() == Dune::InteriorEntity )
248         continue;
249 
250       const bool wasSent = (sendSet_.find( idSet_.id( entity ) ) != sendSet_.end());
251       if( Dune::EntityCommHelper< iftype >::send( entity.partitionType() ) && !wasSent )
252       {
253         std::cout << "[ " << rank_ << " ] Error: No data sent on non-interior entity "
254                   << grid().globalIdSet().id( entity ) << " of partition type "
255                   << entity.partitionType() << " contained in the send set." << std::endl;
256         sendFailure = true;
257       }
258 
259       const bool wasReceived = (receiveSet_.find( idSet_.id( entity ) ) != receiveSet_.end());
260       if( Dune::EntityCommHelper< iftype >::receive( entity.partitionType() ) && !wasReceived )
261       {
262         std::cout << "[ " << rank_ << " ] Error: No data received on non-interior entity "
263                   << grid().globalIdSet().id( entity ) << " of partition type "
264                   << entity.partitionType() << " contained in the receive set." << std::endl;
265         receiveFailure = true;
266       }
267     }
268 
269     if( invalidDimension_ )
270       std::cerr << "[ " << rank_ << " ] Error: Invalid dimension passed during communication." << std::endl;
271     if( invalidCodimension_ )
272       std::cerr << "[ " << rank_ << " ] Error: Invalid codimension passed during communication." << std::endl;
273     if( invalidEntity_ )
274       std::cerr << "[ " << rank_ << " ] Error: Uncontained entity passed during communication." << std::endl;
275     if( invalidSendEntity_ )
276       std::cerr << "[ " << rank_ << " ] Error: Sent data on entity not contained in communication interface." << std::endl;
277     if( invalidReceiveEntity_ )
278       std::cerr << "[ " << rank_ << " ] Error: Received data on entity not contained in communication interface." << std::endl;
279     if( invalidSize_ )
280       std::cerr << "[ " << rank_ << " ] Error: Wrong size passed during communication." << std::endl;
281     if( selfReceive_ )
282       std::cerr << "[ " << rank_ << " ] Warning: Received data from own process during communication." << std::endl;
283     if( doubleInterior_ )
284       std::cerr << "[ " << rank_ << " ] Error: Received interior data on interior entity." << std::endl;
285     if( interiorBorder_ )
286       std::cerr << "[ " << rank_ << " ] Error: Received interior data on border entity / border data on interior entity." << std::endl;
287     if( sendFailure )
288       std::cerr << "[ " << rank_ << " ] Error: No data sent on a non-interior entity within the send set." << std::endl;
289     if( receiveFailure )
290       std::cerr << "[ " << rank_ << " ] Error: No data received on a non-interior entity within the receive set." << std::endl;
291   }
292 
contains(const int dim,const int codim) const293   bool contains ( const int dim, const int codim ) const
294   {
295     invalidDimension_ |= (dim != dimension);
296     invalidCodimension_ |= ((codim < 0) || (codim > dimension));
297     return ((codim >= 0) && (codim <= dimension) ? contains_[ codim ] : false);
298   }
299 
fixedSize(const int dim,const int codim) const300   bool fixedSize ( const int dim, const int codim ) const
301   {
302     invalidDimension_ |= (dim != dimension);
303     invalidCodimension_ |= ((codim < 0) || (codim > dimension));
304     return true;
305   }
306 
307   template< class Entity >
size(const Entity & entity) const308   std::size_t size ([[maybe_unused]] const Entity &entity) const
309   {
310     static_assert( (Entity::dimension == dimension), "Entity has invalid dimension." );
311     static_assert( (Entity::codimension >= 0) || (Entity::codimension <= dimension), "Entity has invalid codimension." );
312     return (contains_[ Entity::codimension ] ? 2 : 0);
313   }
314 
315   template< class Buffer, class Entity >
gather(Buffer & buffer,const Entity & entity) const316   void gather ( Buffer &buffer, const Entity &entity ) const
317   {
318     static_assert( (Entity::dimension == dimension), "Entity has invalid dimension." );
319     static_assert( (Entity::codimension >= 0) || (Entity::codimension <= dimension), "Entity has invalid codimension." );
320 
321     invalidEntity_ |= !contains_[ Entity::codimension ];
322     invalidSendEntity_ |= !Dune::EntityCommHelper< iftype >::send( entity.partitionType() );
323 
324     buffer.write( rank_ );
325     buffer.write( int( entity.partitionType() ) );
326 
327     sendSet_.insert( idSet_.id( entity ) );
328   }
329 
330   template< class Buffer, class Entity >
scatter(Buffer & buffer,const Entity & entity,std::size_t n)331   void scatter ( Buffer &buffer, const Entity &entity, std::size_t n )
332   {
333     static_assert( (Entity::dimension == dimension), "Entity has invalid dimension." );
334     static_assert( (Entity::codimension >= 0) || (Entity::codimension <= dimension), "Entity has invalid codimension." );
335 
336     invalidEntity_ |= !contains_[ Entity::codimension ];
337     invalidSize_ |= (n != size( entity ));
338     invalidReceiveEntity_ |= !Dune::EntityCommHelper< iftype >::receive( entity.partitionType() );
339 
340     int rank, partitionType;
341     buffer.read( rank );
342     buffer.read( partitionType );
343 
344     receiveSet_.insert( idSet_.id( entity ) );
345 
346     selfReceive_ |= (rank == rank_);
347     if( (partitionType == int( Dune::InteriorEntity )) && (entity.partitionType() == Dune::InteriorEntity) )
348     {
349       std::cout << "[ " << rank_ << " ] Error: Receive interior data from process " << rank
350                 << " on interior entity " << grid().globalIdSet().id( entity ) << "." << std::endl;
351       doubleInterior_ = true;
352     }
353     if( (partitionType == int( Dune::BorderEntity )) && (entity.partitionType() == Dune::InteriorEntity) )
354     {
355       std::cout << "[ " << rank_ << " ] Error: Receive border data from process " << rank
356                 << " on interior entity " << grid().globalIdSet().id( entity ) << "." << std::endl;
357       interiorBorder_ = true;
358     }
359     if( (partitionType == int( Dune::InteriorEntity )) && (entity.partitionType() == Dune::BorderEntity) )
360     {
361       std::cout << "[ " << rank_ << " ] Error: Receive interior data from process " << rank
362                 << " on border entity " << grid().globalIdSet().id( entity ) << "." << std::endl;
363       interiorBorder_ = true;
364     }
365   }
366 
apply(const GridView & gridView)367   static void apply ( const GridView &gridView )
368   {
369     std::cout << "Checking communication for " << iftype << "..." << std::endl;
370     CheckPartitionDataHandle handle( gridView );
371     auto commFuture = gridView.communicate( handle, iftype, Dune::ForwardCommunication );
372     if( ! commFuture.ready() )
373       commFuture.wait();
374   }
375 
grid() const376   const Grid &grid () const { return gridView_.grid(); }
377 
378 private:
379   const GridView &gridView_;
380   const int rank_;
381   const IdSet &idSet_;
382   std::bitset< dimension+1 > contains_;
383   mutable CommSet sendSet_, receiveSet_;
384   mutable bool invalidDimension_;
385   mutable bool invalidCodimension_;
386   mutable bool invalidEntity_;
387   mutable bool invalidSendEntity_;
388   bool invalidReceiveEntity_;
389   bool invalidSize_;
390   bool selfReceive_;
391   bool doubleInterior_;
392   bool interiorBorder_;
393 };
394 
395 
396 
397 template< class GridView >
checkPartitionType(const GridView & gridView)398 inline void checkPartitionType ( const GridView &gridView )
399 {
400   CheckPartitionType< GridView, Dune::Interior_Partition >::apply( gridView );
401   CheckPartitionType< GridView, Dune::InteriorBorder_Partition >::apply( gridView );
402   CheckPartitionType< GridView, Dune::Overlap_Partition >::apply( gridView );
403   CheckPartitionType< GridView, Dune::OverlapFront_Partition >::apply( gridView );
404   CheckPartitionType< GridView, Dune::Ghost_Partition >::apply( gridView );
405 
406   CheckPartitionDataHandle< GridView, Dune::InteriorBorder_InteriorBorder_Interface >::apply( gridView );
407   CheckPartitionDataHandle< GridView, Dune::InteriorBorder_All_Interface >::apply( gridView );
408   CheckPartitionDataHandle< GridView, Dune::Overlap_OverlapFront_Interface >::apply( gridView );
409   CheckPartitionDataHandle< GridView, Dune::Overlap_All_Interface >::apply( gridView );
410   CheckPartitionDataHandle< GridView, Dune::All_All_Interface >::apply( gridView );
411 }
412 
413 #endif // DUNE_GRID_TEST_CHECKPARTITION_HH
414