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_CHECKTWISTS_HH
4 #define DUNE_GRID_TEST_CHECKTWISTS_HH
5 
6 #include <dune/geometry/referenceelements.hh>
7 
applyTwist(const int twist,const int i,const int numCorners)8 int applyTwist ( const int twist, const int i, const int numCorners )
9 {
10   return (twist < 0 ? (2*numCorners + 1 - i + twist) : i + twist) % numCorners;
11 }
12 
inverseTwist(const int twist,const int numCorners)13 int inverseTwist ( const int twist, const int numCorners )
14 {
15   return (twist <= 0 ? twist : numCorners - twist);
16 }
17 
18 
19 struct NoMapTwist
20 {
operator ()NoMapTwist21   int operator() ( const int twist ) const
22   {
23     return twist;
24   }
25 };
26 
27 
28 template< class Intersection, class MapTwist >
checkTwistOnIntersection(const Intersection & intersection,const MapTwist & mapTwist)29 int checkTwistOnIntersection ( const Intersection &intersection, const MapTwist &mapTwist )
30 {
31   const int dimension = Intersection::dimension;
32 
33   typedef typename Intersection::Entity Entity;
34   typedef typename Entity::Geometry Geometry;
35   typedef typename Geometry::ctype ctype;
36 
37   typedef typename Intersection::LocalGeometry LocalGeometry;
38 
39   typedef Dune::FieldVector< typename Geometry::ctype, Geometry::coorddimension >
40   WorldVector;
41   typedef Dune::FieldVector< typename LocalGeometry::ctype, LocalGeometry::coorddimension >
42   LocalVector;
43 
44   if( !intersection.neighbor() || intersection.boundary() || !intersection.conforming() )
45     return 0;
46 
47   int errors = 0;
48   const ctype tolerance = std::numeric_limits< ctype >::epsilon();
49 
50   const int tIn = mapTwist( intersection.twistInInside() );
51   const int tOut = mapTwist( intersection.twistInOutside() );
52 
53   const Entity entityIn = intersection.inside();
54   const Entity entityOut = intersection.outside();
55 
56   const Geometry &geoIn = entityIn.geometry();
57   const Geometry &geoOut = entityOut.geometry();
58 
59   const int nIn = intersection.indexInInside();
60   const int nOut = intersection.indexInOutside();
61 
62   auto refIn = referenceElement( geoIn );
63   auto refOut = referenceElement( geoOut );
64 
65   const int numCorners = refIn.size( nIn, 1, dimension );
66   assert( refOut.size( nOut, 1, dimension ) == numCorners );
67   for( int i = 0; i < numCorners; ++i )
68   {
69     const int iIn = applyTwist( inverseTwist( tIn, numCorners ), i, numCorners );
70     const int iOut = applyTwist( inverseTwist( tOut, numCorners ), i, numCorners );
71 
72     WorldVector xIn = geoIn.corner( refIn.subEntity( nIn, 1, iIn, dimension ) );
73     WorldVector xOut = geoOut.corner( refOut.subEntity( nOut, 1, iOut, dimension ) );
74 
75     if( (xIn - xOut).two_norm() < tolerance )
76       continue;
77 
78     std::cout << "Error: corner( " << iIn << " ) = " << xIn
79               << " != " << xOut << " = corner( " << iOut << " )."
80               << std::endl;
81     ++errors;
82   }
83 
84   const LocalGeometry &lGeoIn = intersection.geometryInInside();
85   const LocalGeometry &lGeoOut = intersection.geometryInOutside();
86 
87   bool twistInside = true ;
88   bool twistOutside = true;
89   for( int i = 0; i < numCorners; ++i )
90   {
91     const int gi = i;
92 
93     const int iIn = applyTwist( inverseTwist( tIn, numCorners ), i, numCorners );
94     LocalVector xIn = refIn.position( refIn.subEntity( nIn, 1, iIn, dimension ), dimension );
95     if( (xIn - lGeoIn.corner( gi )).two_norm() >= tolerance )
96     {
97       std::cout << "Error: twisted inside reference corner( " << iIn << " ) = " << xIn
98                 << " != " << lGeoIn.corner( gi ) << " = local corner( " << i << " )."
99                 << std::endl;
100       twistInside = false ;
101       ++errors;
102     }
103 
104     const int iOut = applyTwist( inverseTwist( tOut, numCorners ), i, numCorners );
105     LocalVector xOut = refOut.position( refOut.subEntity( nOut, 1, iOut, dimension ), dimension );
106     if( (xOut - lGeoOut.corner( gi )).two_norm() >= tolerance )
107     {
108       std::cout << "Error: twisted outside reference corner( " << iOut << " ) = " << xOut
109                 << " != " << lGeoOut.corner( gi ) << " = local corner( " << i << " )."
110                 << std::endl;
111       twistOutside = false;
112       ++errors;
113     }
114   }
115 
116   // calculate inside twist
117   if( ! twistInside )
118   {
119     for( int nTwist = numCorners-1; nTwist>= -numCorners; --nTwist )
120     {
121       twistInside = true ;
122       for( int i = 0; i < numCorners; ++i )
123       {
124         const int gi = i;
125         const int iIn = applyTwist( inverseTwist( nTwist, numCorners ), i, numCorners );
126         LocalVector xIn = refIn.position( refIn.subEntity( nIn, 1, iIn, dimension ), dimension );
127         if( (xIn - lGeoIn.corner( gi )).two_norm() >= tolerance )
128         {
129           twistInside = false ;
130         }
131       }
132 
133       if( twistInside )
134       {
135         std::cout << "\ninside " << nIn << "\n";
136         std::cout << "twist " << tIn << " should be replaced by " << nTwist << "\n";
137         break ;
138       }
139     }
140   }
141 
142   // calculate outside twist
143   if( ! twistOutside )
144   {
145     for( int nTwist = numCorners-1; nTwist>=-numCorners; --nTwist )
146     {
147       twistOutside = true ;
148       for( int i = 0; i < numCorners; ++i )
149       {
150         const int gi = i;
151         const int iOut = applyTwist( inverseTwist( nTwist, numCorners ), i, numCorners );
152         LocalVector xOut = refOut.position( refOut.subEntity( nOut, 1, iOut, dimension ), dimension );
153         if( (xOut - lGeoOut.corner( gi )).two_norm() >= tolerance )
154         {
155           twistOutside = false;
156         }
157       }
158 
159       if( twistOutside )
160       {
161         std::cout << "\noutside " << nOut << " (inside = " << nIn << ")\n";
162         std::cout << "twist " << tOut << " should be replaced by " << nTwist << "\n";
163         break ;
164       }
165     }
166   }
167 
168   return errors;
169 }
170 
171 
172 template< class GridView, class MapTwist >
checkTwists(const GridView & gridView,const MapTwist & mapTwist)173 void checkTwists ( const GridView &gridView, const MapTwist &mapTwist )
174 {
175   typedef typename GridView::template Codim< 0 >::Iterator Iterator;
176   typedef typename GridView::IntersectionIterator IntersectionIterator;
177 
178   int errors = 0;
179 
180   const Iterator end = gridView.template end< 0 >();
181   for( Iterator it = gridView.template begin< 0 >(); it != end; ++it )
182   {
183     const IntersectionIterator iend = gridView.iend( *it );
184     for( IntersectionIterator iit = gridView.ibegin( *it ); iit != iend; ++iit )
185       errors += checkTwistOnIntersection( iit->impl(), mapTwist );
186   }
187 
188   if( errors > 0 )
189     std::cerr << "Error: Intersection twists contain errors." << std::endl;
190 }
191 
192 #endif // DUNE_GRID_TEST_CHECKTWISTS_HH
193