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