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