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_GRID_TEST_CHECKINDEXSET_HH
4 #define DUNE_GRID_TEST_CHECKINDEXSET_HH
5 
6 #include <algorithm>
7 #include <iostream>
8 #include <limits>
9 #include <map>
10 #include <set>
11 #include <vector>
12 
13 #include <dune/common/fvector.hh>
14 #include <dune/common/stdstreams.hh>
15 #include <dune/geometry/referenceelements.hh>
16 #include <dune/grid/common/capabilities.hh>
17 #include <dune/grid/common/exceptions.hh>
18 
19 /** @file
20    @author Robert Kloefkorn
21    @brief Provides a check of the grids index set.
22  */
23 
24 template< class Grid >
25 struct EnableLevelIntersectionIteratorCheck
26 {
27   static const bool v = true;
28 };
29 
30 template< class Grid >
31 struct EnableLevelIntersectionIteratorCheck< const Grid >
32 {
33   static const bool v = EnableLevelIntersectionIteratorCheck< Grid >::v;
34 };
35 
36 
37 namespace Dune
38 {
39 
40   // Check whether two FieldVectors are equal in the max norm
41   template <typename ctype, int dim>
compareVec(const FieldVector<ctype,dim> & vx1,const FieldVector<ctype,dim> & vx2)42   bool compareVec(const FieldVector<ctype,dim> & vx1 , const FieldVector<ctype,dim> & vx2 )
43   {
44     const ctype eps = 1e5 * std::numeric_limits<ctype>::epsilon();
45     return (vx1-vx2).infinity_norm() < eps;
46   }
47 
48   /** \brief Check various features of codim-0 entities (elements)
49       \param grid The grid we are testing
50       \param en The grid element we are testing
51       \param lset The corresponding level set
52       \param sout The output stream that status (non-error) messages will go to
53       \param setOfVerticesPerSubEntity A map that associates a vector of vertex indices to a subEntity
54       \param subEntityPerSetOfVertices The reverse: a map that associates a subEntity to a vector of vertex indices
55       \param vertexCoordsMap Map that associates vertex positions to indices (integers)
56    */
57   template <int codim, class GridType,
58       class IndexSetType, class OutputStreamImp,
59       class MapType1 , class MapType2 , class MapType3 >
checkSubEntity(const GridType &,const typename GridType::template Codim<0>::Entity & en,const IndexSetType & lset,OutputStreamImp & sout,MapType1 & setOfVerticesPerSubEntity,MapType2 & subEntityPerSetOfVertices,const MapType3 & vertexCoordsMap)60   void checkSubEntity ( const GridType &,
61                         const typename GridType::template Codim<0>::Entity &en , const IndexSetType & lset,
62                         OutputStreamImp & sout , MapType1 & setOfVerticesPerSubEntity ,
63                         MapType2 & subEntityPerSetOfVertices,
64                         const MapType3 & vertexCoordsMap )
65   {
66     enum { dim = GridType::dimension };
67     const int dimworld = GridType::dimensionworld;
68     typedef typename GridType::ctype coordType;
69 
70     const GeometryType type = en.type();
71     assert( type == en.geometry().type() );
72 
73     if( type.isNone() )
74       return;
75 
76     auto refElem = referenceElement( en.geometry() );
77 
78     // check whether the element has the number of codim-subentities mandated by the reference element
79     if(int(en.subEntities(codim)) != refElem.size(0,0,codim))
80     {
81       std::cerr << "entity index = " << lset.index(en)
82                 << ", type = " << type
83                 << std::endl
84                 << "codim = " << codim
85                 << std::endl
86                 << "subEntities(codim) = " << en.subEntities(codim)
87                 << std::endl
88                 << "refElem.size(codim) = " << refElem.size(0,0,codim)
89                 << std::endl;
90       DUNE_THROW(GridError,
91                  "wrong number of subEntities of codim " << codim);
92     }
93 
94     for( int subEntity = 0; subEntity < refElem.size( 0, 0, codim ); ++subEntity )
95     {
96 
97       // Number of vertices of the current subentity
98       int numVertices = refElem.size( subEntity, codim, dim );
99 
100       // every entity must have at least one vertex
101       assert( numVertices > 0 );
102 
103       // The local vertex numbers
104       std::vector<int> local (numVertices);
105 
106       for( int j = 0; j < numVertices; ++j )
107         local[ j ] = refElem.subEntity ( subEntity, codim, j, dim );
108 
109       sout << numVertices << " vertices on subEntity< codim = " << codim << " >" << std::endl;
110       sout << "check subentity [" << local[ 0 ];
111       for( int j = 1; j < numVertices; ++j )
112         sout << ", " << local[ j ];
113       sout << "]" << std::endl;
114 
115       // The global vertex numbers
116       std::vector<int> global(numVertices);
117       for( int j = 0; j < numVertices; ++j )
118         global[ j ] = lset.subIndex( en, local[ j ], dim );
119 
120       sout << "Found global numbers of entity [ ";
121       for( int j = 0; j < numVertices; ++j )
122         sout << global[ j ] << " ";
123       sout << "]" << std::endl;
124 
125       // Check whether we get the same index if we
126       // -- ask for the subEntity itself and then its index
127       // -- ask for the subIndex directly
128       typedef typename GridType::template Codim< codim >::Entity SubE;
129       SubE subE = en.template subEntity< codim >( subEntity );
130 
131       if( lset.subIndex( en, subEntity, codim ) != lset.index( subE) )
132       {
133         std::cerr << "Index for subEntity does not match." << std::endl;
134         assert( lset.subIndex( en, subEntity, codim ) == lset.index( subE) );
135       }
136 
137       // Make a unique identifier for the subEntity.  Since indices are unique only per GeometryType,
138       // we need a (index,GeometryType)-pair.
139       std::pair<int, GeometryType> globalSubEntity( lset.index( subE ), subE.type() );
140       assert( globalSubEntity.first >= 0 );
141       sout << "local subentity " << subEntity << " consider subentity with global key (" << globalSubEntity.first << ","
142            << globalSubEntity.second << ") on en = " << lset.index(en) << std::endl;
143 
144       if( subE.type() != subE.geometry().type() )
145       {
146         std::cerr << "Geometry types for subEntity don't match." << std::endl;
147         assert( subE.type() == subE.geometry().type() );
148       }
149 
150       // assert that all sub entities have the same level
151       assert( subE.level() == en.level() );
152 
153       // Loop over all vertices
154       for( int j = 0; j < numVertices; ++j )
155       {
156 
157         // get entity pointer to subEntity vertex
158         typedef typename GridType::template Codim< dim >::Entity VertexE;
159         VertexE vxE = en.template subEntity< dim >( local[ j ] );
160 
161         // Find the global coordinate of the vertex by its index
162         if(vertexCoordsMap.find(global[j]) != vertexCoordsMap.end())
163         {
164           // Check whether index and coordinate match
165           FieldVector<coordType,dimworld> vxcheck ( vertexCoordsMap.find(global[j])->second );
166           FieldVector< coordType, dimworld > vx1 = vxE.geometry().corner( 0 );
167           if( ! compareVec( vxcheck, vx1 ) )
168           {
169             std::cerr << "ERROR map global vertex [" << global[j] << "] vx " << vxcheck << " is not " << vx1 << "\n";
170             assert( compareVec( vxcheck, vx1 ) );
171           }
172         }
173         sout << "vx[" << global[j] << "] = "  <<  subE.geometry().corner( j ) << "\n";
174       }
175       sout << "sort vector of global vertex\n";
176 
177       // sort vector of global vertex number for storage in map
178       // the smallest entry is the first entry
179       std::sort( global.begin(), global.end() );
180 
181       // check whether vertex key is already stored in map
182       if(subEntityPerSetOfVertices.find(global) == subEntityPerSetOfVertices.end())
183       {
184         subEntityPerSetOfVertices[global] = globalSubEntity;
185       }
186       else
187       {
188         assert( globalSubEntity == subEntityPerSetOfVertices[global] );
189       }
190 
191       // check whether subEntity is already stored in map
192       if(setOfVerticesPerSubEntity.find(globalSubEntity) == setOfVerticesPerSubEntity.end() )
193       {
194         setOfVerticesPerSubEntity[globalSubEntity] = global;
195       }
196       else
197       {
198         std::vector<int> globalcheck = setOfVerticesPerSubEntity[globalSubEntity];
199         if(! (global == globalcheck ))
200         {
201           std::cerr << "For subEntity key (" << globalSubEntity.first << "," << globalSubEntity.second << ") \n";
202           std::cerr << "Got ";
203           for(int j=0 ; j<numVertices; j++ )
204           {
205             std::cerr << global[j] << " ";
206           }
207           std::cerr << "\n";
208           std::cerr << "Found ";
209           for(int j=0 ; j<numVertices; j++ )
210           {
211             std::cerr << globalcheck [j] << " ";
212           }
213           std::cerr << "\n";
214           DUNE_THROW(Dune::GridError, "global != globalcheck");
215         }
216       }
217 
218     }   // end check sub entities
219     sout << "end check sub entities\n";
220   }
221 
222 
223   // check some functionality of grid
224   template< int codim, class Grid, class GridView, class OutputStream >
checkIndexSetForCodim(const Grid & grid,const GridView & view,OutputStream & sout,bool levelIndex)225   void checkIndexSetForCodim ( const Grid &grid, const GridView &view,
226                                OutputStream &sout, bool levelIndex )
227   {
228     enum { dim = Grid :: dimension };
229     enum { dimworld = Grid :: dimensionworld };
230 
231     typedef typename Grid :: ctype coordType;
232 
233     //typedef typename GridView :: template Codim< 0 > :: Entity EntityCodim0Type;
234     typedef typename GridView :: IndexSet IndexSetType;
235     typedef typename GridView :: template Codim< codim > :: Iterator IteratorType;
236 
237     const IndexSetType &lset = view.indexSet();
238 
239     sout <<"\n\nStart consistency check of index set \n\n";
240 
241     // ////////////////////////////////////////////////////////////////
242     //   Check whether geomTypes() returns correct result
243     // ////////////////////////////////////////////////////////////////
244 
245     std :: set< GeometryType > geometryTypes;
246 
247     const IteratorType endit = view.template end< codim >();
248     IteratorType it = view.template begin< codim >();
249 
250     if (it == endit) return;
251 
252     for (; it!=endit; ++it) {
253       // while we're here: check whether the GeometryTypes returned by the entity
254       // and the Geometry match
255       assert(it->type()==it->type());
256       geometryTypes.insert(it->type());
257     }
258 
259     const typename IndexSetType::Types types = lset.types( codim );
260     bool geomTypesError = false;
261 
262     // Check whether all entries in the official geometry types list are contained in our self-computed one
263     for( auto itT = types.begin(); itT != types.end(); ++itT )
264       if( geometryTypes.find( *itT ) == geometryTypes.end() )
265         geomTypesError = true;
266 
267 
268     // And vice versa
269     for( std::set<GeometryType>::iterator itG = geometryTypes.begin(); itG != geometryTypes.end(); ++itG )
270     {
271       if( std::find( types.begin(), types.end(), *itG ) == types.end() )
272         geomTypesError = true;
273     }
274 
275 
276 
277     if (geomTypesError) {
278 
279       std::cerr << "There is a mismatch in the list of geometry types of codim " << codim << "." << std::endl;
280       std::cerr << "Geometry types present in the grid are:" << std::endl;
281       for (std::set<GeometryType>::iterator itG = geometryTypes.begin(); itG!=geometryTypes.end(); ++itG)
282         std::cerr << "  " << *itG << std::endl;
283 
284       std::cerr << std::endl << "but the method types() returned:" << std::endl;
285       for( auto itT = types.begin(); itT != types.end(); ++itT )
286         std::cerr << "  " << *itT << std::endl;
287 
288       DUNE_THROW(GridError, "!");
289     }
290 
291     //*****************************************************************
292     // check size of index set
293     int gridsize = 0;
294     {
295       using  IteratorTypeV = typename GridView :: template Codim< codim > :: Iterator;
296 
297       int count = 0;
298       const IteratorTypeV enditV = view.template end< codim >();
299       for( IteratorTypeV itV = view.template begin< codim >(); itV != enditV; ++itV )
300         ++count;
301 
302       int lsetsize = lset.size(codim);
303       if( count != lsetsize)
304       {
305         derr << "WARNING: walk = "<< count << " entities | set = "
306              << lsetsize << " for codim " << codim << std::endl;
307       }
308       gridsize = count;
309       // lsetsize should be at least the size of iterated entities
310       assert( count <= gridsize );
311     }
312 
313     {
314       using IteratorTypeC  = typename GridView :: template Codim< 0 > :: Iterator;
315       using LocalIdSetType = typename Grid :: Traits :: LocalIdSet;
316       using IdType = typename LocalIdSetType :: IdType;
317       std::set< IdType > entityfound;
318 
319       const IteratorTypeC enditC = view.template end< 0 >();
320       auto itC = view.template begin< 0 >();
321       if( itC == enditC )
322         return;
323 
324       const auto &localIdSet = grid.localIdSet();
325       for( ; itC != enditC; ++itC )
326       {
327         const auto &entity = *itC;
328         if( !lset.contains( entity ) )
329         {
330           std::cerr << "Error: IndexSet does not contain all entities." << std::endl;
331           assert( false );
332         }
333         const int subcount = entity.subEntities(codim);
334         for( int i = 0; i < subcount; ++i )
335         {
336           const auto id = localIdSet.id( entity.template subEntity< codim >( i ) );
337           entityfound.insert( id );
338         }
339       }
340 
341       if( (size_t)gridsize != entityfound.size() )
342       {
343         std::cerr << "Warning: gridsize = " << gridsize << " entities"
344                   << ", set of entities = " << entityfound.size()
345                   << " [codim " << codim << "]" << std::endl;
346       }
347 
348       // gridsize should be at least the size of found entities
349       //assert( gridsize <= (int) entityfound.size() );
350     }
351 
352     //******************************************************************
353 
354     typedef std::pair < int , GeometryType > SubEntityKeyType;
355     //typedef std::map < int , std::pair<int,int> > subEntitymapType;
356     std::map < SubEntityKeyType , std::vector<int> > setOfVerticesPerSubEntity;
357     std::map < std::vector<int> , SubEntityKeyType > subEntityPerSetOfVertices;
358 
359     std::map < int , FieldVector<coordType,dimworld> > vertexCoordsMap;
360     // setup vertex map , store vertex coords for vertex number
361     {
362       unsigned int count = 0;
363       using VxIterator = typename GridView :: template Codim< dim > :: Iterator;
364       const VxIterator endV = view.template end< dim >();
365       for( auto itV = view.template begin< dim >(); itV != endV; ++itV )
366       {
367         ++count;
368         // get coordinates of vertex
369         FieldVector< coordType, dimworld > vx ( itV->geometry().corner( 0 ) );
370 
371         // get index of vertex
372         sout << "Vertex " << vx << "\n";
373         assert( lset.contains ( *itV ) );
374         int idx = lset.index( *itV );
375 
376         sout << "Vertex " << idx << " = [" << vx << "]\n";
377 
378         // if vertex not in map insert it
379         if( vertexCoordsMap.find(idx) == vertexCoordsMap.end())
380           vertexCoordsMap[idx] = vx;
381       }
382       sout << "Found " << vertexCoordsMap.size() << " vertices for that index set!\n\n";
383 
384       // check whether size of map equals all found vertices
385       assert( vertexCoordsMap.size() == count );
386 
387       // check whether size of vertices of set equals all found vertices
388       sout << "Checking size of vertices "
389            << count
390            << " equals all found vertices "
391            << (unsigned int)lset.size(Dune::GeometryTypes::vertex)
392            << "\n";
393       // assertion goes wrong:
394       // - for parallel grid since no iteration over ghost subentities
395       // - if there are vertices with geometry type 'none'
396       //assert( count == (unsigned int)lset.size(Dune::GeometryTypes::vertex) );
397     }
398 
399     {
400       typedef typename GridView :: template Codim< 0 > :: Iterator Iterator;
401       // choose the right reference element
402     #ifndef NDEBUG
403       const Iterator refend = view.template end< 0 >();
404     #endif
405       Iterator refit = view.template begin< 0 >();
406       assert( refit != refend );
407 
408       auto refElem = referenceElement( refit->geometry() );
409 
410       // print dune reference element
411       sout << "Dune reference element provides: \n";
412       for(int i = 0; i < refElem.size( codim ); ++i )
413       {
414         sout << i << " subEntity [";
415         int s = refElem.size(i,codim,dim);
416         for(int j=0; j<s; j++)
417         {
418           sout << refElem.subEntity(i , codim , j , dim );
419           if(j != s-1) sout << ",";
420         }
421         sout << "]\n";
422       }
423     }
424 
425     {
426       using Iterator = typename GridView :: template Codim< 0 > :: Iterator;
427       const Iterator enditC = view.template end< 0 >();
428       for( Iterator itC = view.template begin< 0 >(); itC != enditC; ++itC )
429       {
430         // if (it->partitionType()==4) continue;
431         sout << "****************************************\n";
432         sout << "Element = " << lset.index(*itC) << " on level " << itC->level () << "\n";
433         sout << "Vertices      = [";
434         int svx = itC->subEntities(dim);
435 
436         // print all vertex numbers
437         for( int i = 0; i < svx; ++i )
438         {
439           const typename IndexSetType::IndexType idx = lset.subIndex( *itC, i, dim );
440           sout << idx << (i < svx-1 ? ", " : "]\n");
441         }
442 
443         // print all vertex coordinates
444         sout << "Vertex Coords = [";
445         for( int i = 0; i < svx; ++i )
446         {
447           // get entity pointer of sub entity codim=dim (Vertex)
448           typedef typename GridView::template Codim< dim >::Entity VertexE;
449           VertexE vxE = itC->template subEntity< dim >( i );
450 
451           // get coordinates of entity pointer
452           FieldVector< coordType, dimworld > vx( vxE.geometry().corner( 0 ) );
453 
454           // output vertex coordinates
455           sout << vx << (i < svx-1 ? ", " : "]\n");
456 
457           const typename IndexSetType::IndexType vxidx = lset.subIndex( *itC, i, dim );
458 
459           // the subIndex and the index for subEntity must be the same
460           if( vxidx != lset.index( vxE ) )
461           {
462             std::cerr << "Error: index( *subEntity< dim >( i ) ) != subIndex( entity, i, dim )" << std::endl;
463             assert( vxidx == lset.index( vxE ) );
464           }
465 
466           // check whether the coordinates are the same
467           assert(vertexCoordsMap.find(vxidx)!=vertexCoordsMap.end());
468           FieldVector<coordType,dimworld> vxcheck ( vertexCoordsMap[vxidx] );
469           if( !compareVec( vxcheck, vx ) )
470           {
471             std::cerr << "Error: Inconsistent map of global vertex " << vxidx
472                       << ": " << vxcheck << " != " << vx
473                       << "  (type = " << itC->partitionType() << ")" << std::endl;
474             assert( compareVec( vxcheck, vx ) );
475           }
476         }
477 
478         ////////////////////////////////////////////////////////////
479         // check sub entities
480         ////////////////////////////////////////////////////////////
481         checkSubEntity< codim >( grid, *itC, lset, sout,
482                                  setOfVerticesPerSubEntity, subEntityPerSetOfVertices, vertexCoordsMap );
483 
484         // check neighbors
485         if( codim == 1 )
486         {
487           typedef typename GridView :: IntersectionIterator IntersectionIterator;
488 
489           if( !levelIndex || EnableLevelIntersectionIteratorCheck< typename GridView::Grid >::v )
490           {
491             const IntersectionIterator endnit = view.iend( *itC );
492             for( IntersectionIterator nit = view.ibegin( *itC ); nit != endnit; ++nit )
493             {
494               if( !nit->neighbor() )
495                 continue;
496 
497               checkSubEntity< codim >( grid, nit->outside(), lset, sout,
498                                        setOfVerticesPerSubEntity, subEntityPerSetOfVertices, vertexCoordsMap );
499             }
500           }
501           else
502           {
503             static int called = 0;
504             if( called++ == 0 )
505               std::cerr << "Warning: Skipping index test using LevelIntersectionIterator." << std::endl;
506           }
507         }
508       }
509     }
510   }
511 
512   template< class Grid, class GridView, class OutputStream >
checkIndexSet(const Grid & grid,const GridView & view,OutputStream & sout,bool levelIndex=false)513   void checkIndexSet ( const Grid &grid, const GridView &view,
514                        OutputStream &sout,  bool levelIndex = false )
515   {
516     Hybrid::forEach( std::make_index_sequence< Grid :: dimension+1 >{},
517       [ & ]( auto codim )
518     {
519       if constexpr (Capabilities :: hasEntityIterator< Grid, codim>::v)
520         checkIndexSetForCodim< codim >( grid, view, sout, levelIndex );
521       else
522         derr << "WARNING: Entities for codim " << codim
523              << " are not being tested!" << std::endl;
524     });
525   }
526 
527 } // end namespace Dune
528 
529 #endif // DUNE_GRID_TEST_CHECKINDEXSET_HH
530