1 #include <config.h>
2 
3 #include <algorithm>
4 #include <cstdlib>
5 #include <ctime>
6 #include <iostream>
7 
8 #include <dune/common/exceptions.hh>
9 #include <dune/common/fmatrix.hh>
10 #include <dune/common/fvector.hh>
11 
12 #include <dune/fem/gridpart/adaptiveleafgridpart.hh>
13 #include <dune/fem/io/parameter.hh>
14 #include <dune/fem/misc/mpimanager.hh>
15 #include <dune/fem/quadrature/cachingquadrature.hh>
16 #include <dune/fem/space/basisfunctionset/vectorial.hh>
17 #include <dune/fem/space/common/adaptationmanager.hh>
18 #include <dune/fem/space/common/functionspace.hh>
19 #include <dune/fem/space/lagrange.hh>
20 #include <dune/fem/test/testgrid.hh>
21 
22 
23 
24 // Evaluate
25 // --------
26 
27 template< class FunctionSpace >
28 struct Evaluate
29 {
30   typedef FunctionSpace FunctionSpaceType;
31   typedef typename FunctionSpaceType::RangeType Vector;
32 
33   template< class BasisFunctionSet, class Point, class DofVector >
applyEvaluate34   static void apply ( const BasisFunctionSet &basisFunctionSet,
35                       const Point &x, const DofVector &dofs, Vector &vector )
36   {
37     basisFunctionSet.evaluateAll( x, dofs, vector );
38   }
39 
40   template< class BasisFunctionSet, class Point, class Array >
applyEvaluate41   static void apply ( const BasisFunctionSet &basisFunctionSet,
42                       const Point &x, Array &array )
43   {
44     basisFunctionSet.evaluateAll( x, array );
45   }
46 };
47 
48 
49 
50 // Jacobian
51 // --------
52 
53 template< class FunctionSpace >
54 struct Jacobian
55 {
56   typedef FunctionSpace FunctionSpaceType;
57   typedef typename FunctionSpaceType::JacobianRangeType Vector;
58 
59   template< class BasisFunctionSet, class Point, class DofVector >
applyJacobian60   static void apply ( const BasisFunctionSet &basisFunctionSet,
61                       const Point &x, const DofVector &dofs, Vector &vector )
62   {
63     basisFunctionSet.jacobianAll( x, dofs, vector );
64   }
65 
66   template< class BasisFunctionSet, class Point, class Array >
applyJacobian67   static void apply ( const BasisFunctionSet &basisFunctionSet,
68                       const Point &x, Array &array )
69   {
70     basisFunctionSet.jacobianAll( x, array );
71   }
72 };
73 
74 
75 
76 // Hessian
77 // -------
78 
79 template< class FunctionSpace >
80 struct Hessian
81 {
82   typedef FunctionSpace FunctionSpaceType;
83   typedef typename FunctionSpaceType::HessianRangeType Vector;
84 
85   template< class BasisFunctionSet, class Point, class DofVector >
applyHessian86   static void apply ( const BasisFunctionSet &basisFunctionSet,
87                       const Point &x, const DofVector &dofs, Vector &vector )
88   {
89     basisFunctionSet.hessianAll( x, dofs, vector );
90   }
91 
92   template< class BasisFunctionSet, class Point, class Array >
applyHessian93   static void apply ( const BasisFunctionSet &basisFunctionSet,
94                       const Point &x, Array &array )
95   {
96     basisFunctionSet.hessianAll( x, array );
97   }
98 };
99 
100 
101 
102 // DofConversion
103 // -------------
104 
105 template< class DofAlignmentType >
106 struct DofConversion;
107 
108 template< class ShapeFunctionSet, class Range >
109 struct DofConversion< Dune::Fem::HorizontalDofAlignment< ShapeFunctionSet, Range > >
110 {
111   typedef Dune::Fem::HorizontalDofAlignment< ShapeFunctionSet, Range > DofAlignmentType;
applyDofConversion112   static std::size_t apply ( const DofAlignmentType &dofAlignment, std::size_t globalDof )
113   {
114     Dune::Fem::VerticalDofAlignment< ShapeFunctionSet, Range > conversion;
115     return dofAlignment.globalDof( conversion.localDof( globalDof ) );
116   }
117 };
118 
119 template< class ShapeFunctionSet, class Range >
120 struct DofConversion< Dune::Fem::VerticalDofAlignment< ShapeFunctionSet, Range > >
121 {
122   typedef Dune::Fem::VerticalDofAlignment< ShapeFunctionSet, Range > DofAlignmentType;
123 
applyDofConversion124   static std::size_t apply ( const DofAlignmentType &, std::size_t globalDof )
125   {
126     return globalDof;
127   }
128 };
129 
130 
131 
132 // Error
133 // -----
134 
135 template< class Vector >
136 struct Error;
137 
138 template< class RangeFieldType, int dim >
139 struct Error< Dune::FieldVector< RangeFieldType, dim > >
140 {
141   typedef Dune::FieldVector< RangeFieldType, dim > Vector;
142 
applyError143   static RangeFieldType apply ( const Vector &a, const Vector &b )
144   {
145     return (a - b).two_norm();
146   }
147 };
148 
149 template< class RangeFieldType, int dimDomain, int dimRange >
150 struct Error< Dune::FieldMatrix< RangeFieldType, dimRange, dimDomain > >
151 {
152   typedef Dune::FieldMatrix< RangeFieldType, dimRange, dimDomain > Vector;
153 
applyError154   static RangeFieldType apply ( const Vector &a, const Vector &b )
155   {
156     Vector c = a;
157     c -= b;
158     return c.frobenius_norm();
159   }
160 };
161 
162 template< class RangeFieldType, int dimDomain, int dimRange >
163 struct Error< Dune::Fem::ExplicitFieldVector< Dune::FieldMatrix< RangeFieldType, dimDomain, dimDomain >, dimRange > >
164 {
165   typedef Dune::FieldVector< Dune::FieldMatrix< RangeFieldType, dimDomain, dimDomain >, dimRange > Vector;
166 
applyError167   static RangeFieldType apply ( const Vector &a, const Vector &b )
168   {
169     Dune::FieldVector< RangeFieldType, dimRange > error;
170     for( int r = 0; r < dimRange; ++r )
171       error[ r ] = Error< Dune::FieldMatrix< RangeFieldType, dimDomain, dimDomain > >::apply( a[ r ], b[ r ] );
172     return error.infinity_norm();
173   }
174 };
175 
176 
177 
178 // random
179 // ------
180 
181 template< class FieldType >
random(FieldType a,FieldType b)182 FieldType random ( FieldType a, FieldType b )
183 {
184   FieldType delta = FieldType( rand() )/FieldType( RAND_MAX );
185   return ( a + delta*( b - a ) );
186 }
187 
188 
189 
190 // evaluateAll
191 // -----------
192 
193 template< class Evaluate,
194           class BasisFunctionSet, class VectorialBasisFunctionSet,
195           class Point, class DofVector >
196 typename Evaluate::FunctionSpaceType::RangeFieldType
evaluateAll(const BasisFunctionSet & basisFunctionSet,const VectorialBasisFunctionSet & vectorialBasisFunctionSet,const Point & x,const DofVector & dofs)197   evaluateAll ( const BasisFunctionSet &basisFunctionSet,
198                 const VectorialBasisFunctionSet &vectorialBasisFunctionSet,
199                 const Point &x, const DofVector &dofs )
200 {
201   typedef typename Evaluate::FunctionSpaceType FunctionSpaceType;
202 
203   typedef typename VectorialBasisFunctionSet::DofAlignmentType DofAlignmentType;
204   DofAlignmentType dofAlignment = vectorialBasisFunctionSet.dofAlignment();
205 
206   const std::size_t size = dofs.size();
207   std::vector< typename FunctionSpaceType::RangeFieldType > convertedDofs( size );
208   for( std::size_t i = 0; i < size; ++i )
209   {
210     const std::size_t j = DofConversion< DofAlignmentType >::apply( dofAlignment, i );
211     convertedDofs.at( j ) = dofs[ i ];
212   }
213 
214   typename Evaluate::Vector a, b;
215   Evaluate::apply( basisFunctionSet, x, dofs, a );
216   Evaluate::apply( vectorialBasisFunctionSet, x, convertedDofs, b );
217 
218   return Error< typename Evaluate::Vector >::apply( a, b );
219 }
220 
221 
222 
223 // evaluateAll
224 // -----------
225 
226 template< class Evaluate,
227           class BasisFunctionSet, class VectorialBasisFunctionSet,
228           class Point >
229 typename Evaluate::FunctionSpaceType::RangeFieldType
evaluateAll(const BasisFunctionSet & basisFunctionSet,const VectorialBasisFunctionSet & vectorialBasisFunctionSet,const Point & x)230   evaluateAll ( const BasisFunctionSet &basisFunctionSet,
231                 const VectorialBasisFunctionSet &vectorialBasisFunctionSet,
232                 const Point &x )
233 {
234   typedef typename Evaluate::Vector Vector;
235   const std::size_t size = basisFunctionSet.size();
236   std::vector< Vector > a( size ), b( size );
237 
238   Evaluate::apply( basisFunctionSet, x, a );
239   Evaluate::apply( vectorialBasisFunctionSet, x, b );
240 
241   typedef typename VectorialBasisFunctionSet::DofAlignmentType DofAlignmentType;
242   DofAlignmentType dofAlignment = vectorialBasisFunctionSet.dofAlignment();
243 
244   typedef typename Evaluate::FunctionSpaceType::RangeFieldType RangeFieldType;
245   RangeFieldType error( 0 );
246   for( std::size_t i = 0; i < size; ++i )
247   {
248     std::size_t j = DofConversion< DofAlignmentType >::apply( dofAlignment, i );
249     error = std::max( error, Error< Vector >::apply( a[ i ], b[ j ] ) );
250   }
251   return error;
252 }
253 
254 
255 // compareQuadrature
256 // -----------------
257 
258 template< class BasisFunctionSetType, class VectorialBasisFunctionSetType, class QuadratureType >
259 Dune::FieldVector< typename BasisFunctionSetType::RangeType::value_type, 3 >
compareQuadrature(const BasisFunctionSetType & basisFunctionSet,const VectorialBasisFunctionSetType & vectorialBasisFunctionSet,const QuadratureType & quadrature)260   compareQuadrature ( const BasisFunctionSetType &basisFunctionSet,
261                       const VectorialBasisFunctionSetType &vectorialBasisFunctionSet,
262                       const QuadratureType &quadrature )
263 {
264   // check order of basis function set
265   if( vectorialBasisFunctionSet.order() != basisFunctionSet.order() )
266     DUNE_THROW( Dune::InvalidStateException, "order() does not match" );
267 
268   // check size of basis function set
269   const std::size_t size = basisFunctionSet.size();
270   if( vectorialBasisFunctionSet.size() != basisFunctionSet.size() )
271     DUNE_THROW( Dune::InvalidStateException, "size() does not match" );
272 
273   // get types
274   typedef typename BasisFunctionSetType::FunctionSpaceType FunctionSpaceType;
275   typedef typename FunctionSpaceType::RangeFieldType RangeFieldType;
276 
277   // init random dof vectors
278   std::vector< RangeFieldType > dofs( size );
279   for( std::size_t i = 0; i < size; ++i )
280     dofs[ i ] = random< RangeFieldType >( 1e-3, 1e3 );
281 
282   // return value
283   Dune::FieldVector< RangeFieldType, 3 > ret;
284 
285   const std::size_t nop = quadrature.nop();
286   for( std::size_t qp = 0; qp < nop; ++qp )
287   {
288     // check evaluate methods
289     {
290       RangeFieldType error = 0;
291       error += evaluateAll< Evaluate< FunctionSpaceType > >( basisFunctionSet, vectorialBasisFunctionSet, quadrature[ qp ], dofs );
292       error += evaluateAll< Evaluate< FunctionSpaceType > >( basisFunctionSet, vectorialBasisFunctionSet, quadrature[ qp ] );
293       ret[ 0 ] = std::max( ret[ 0 ], error );
294     }
295 
296     // check jacobian methods
297     {
298       RangeFieldType error = 0;
299       error += evaluateAll< Jacobian< FunctionSpaceType > >( basisFunctionSet, vectorialBasisFunctionSet, quadrature[ qp ], dofs );
300       error += evaluateAll< Jacobian< FunctionSpaceType > >( basisFunctionSet, vectorialBasisFunctionSet, quadrature[ qp ] );
301       ret[ 1 ] = std::max( ret[ 1 ], error );
302     }
303 
304     // check hessian methods
305     {
306       RangeFieldType error = 0;
307       error += evaluateAll< Hessian< FunctionSpaceType > >( basisFunctionSet, vectorialBasisFunctionSet, quadrature[ qp ], dofs );
308       error += evaluateAll< Hessian< FunctionSpaceType > >( basisFunctionSet, vectorialBasisFunctionSet, quadrature[ qp ] );
309       ret[ 2 ] = std::max( ret[ 1 ], error );
310     }
311   }
312 
313   return ret;
314 }
315 
316 
317 template< class GridPartType >
traverse(GridPartType & gridPart)318 void traverse ( GridPartType &gridPart )
319 {
320   static const int dimDomain = GridPartType::dimensionworld;
321   static const int dimRange = DIMRANGE;
322 
323   typedef Dune::Fem::FunctionSpace< typename GridPartType::ctype, double, dimDomain, dimRange > FunctionSpaceType;
324 
325   // create discrete function space
326   typedef Dune::Fem::LagrangeDiscreteFunctionSpace< FunctionSpaceType, GridPartType, POLORDER > DiscreteFunctionSpaceType;
327   DiscreteFunctionSpaceType space( gridPart );
328 
329   // create scalar discrete function space
330   typedef Dune::Fem::LagrangeDiscreteFunctionSpace< typename FunctionSpaceType::ScalarFunctionSpaceType, GridPartType, POLORDER > ScalarDiscreteFunctionSpaceType;
331   ScalarDiscreteFunctionSpaceType scalarSpace( gridPart );
332 
333   typedef Dune::FieldVector< typename FunctionSpaceType::RangeFieldType, 3 > ErrorType;
334   ErrorType error( 0 );
335 
336   for( const auto& entity : space )
337   {
338     // get basis function set
339     typedef typename DiscreteFunctionSpaceType::BasisFunctionSetType BasisFunctionSetType;
340     const BasisFunctionSetType basisFunctionSet = space.basisFunctionSet( entity );
341 
342     // get scalar basis function set
343     typedef typename ScalarDiscreteFunctionSpaceType::BasisFunctionSetType ScalarBasisFunctionSetType;
344     const ScalarBasisFunctionSetType scalarBasisFunctionSet = scalarSpace.basisFunctionSet( entity );
345 
346     // create vectorial basis function set
347 #if USE_VERTICAL_DOF_ALIGNMENT == 1
348     typedef Dune::Fem::VectorialBasisFunctionSet< ScalarBasisFunctionSetType, typename BasisFunctionSetType::RangeType, Dune::Fem::VerticalDofAlignment > VectorialBasisFunctionSetType;
349 #else
350     typedef Dune::Fem::VectorialBasisFunctionSet< ScalarBasisFunctionSetType, typename BasisFunctionSetType::RangeType, Dune::Fem::HorizontalDofAlignment > VectorialBasisFunctionSetType;
351 #endif
352     VectorialBasisFunctionSetType vectorialBasisFunctionSet( scalarBasisFunctionSet );
353 
354     // create quadrature
355     assert( basisFunctionSet.order() == vectorialBasisFunctionSet.order() );
356     typedef Dune::Fem::CachingQuadrature< GridPartType, 0 > QuadratureType;
357     QuadratureType quadrature( basisFunctionSet.entity(), basisFunctionSet.order() );
358 
359     // compare basis function sets in quadrature points
360     ErrorType localError = compareQuadrature( basisFunctionSet, vectorialBasisFunctionSet, quadrature );
361 
362     // update error
363     for( int i = 0; i < 3; ++i )
364       error[ i ] = std::max( error[ i ], localError[ i ] );
365   }
366 
367 
368   const double eps = 1e-8;
369   // print error
370   if( error.two_norm() > eps )
371   {
372     std::cerr << "Errors( evaluateAll, jacobianAll, hessianAll ): " << error << std::endl;
373 #if USE_VERTICAL_DOF_ALIGNMENT == 1
374     DUNE_THROW( Dune::InvalidStateException, "VectorialBasisFunctionSet< VerticalDofAlignment > test failed." );
375 #else
376     DUNE_THROW( Dune::InvalidStateException, "VectorialBasisFunctionSet< HorizontalDofAlignment > test failed." );
377 #endif
378   }
379 }
380 
381 
main(int argc,char ** argv)382 int main ( int argc, char **argv )
383 {
384   Dune::Fem::MPIManager::initialize( argc, argv );
385 
386   Dune::Fem::Parameter::append( argc, argv );
387   Dune::Fem::Parameter::append( argc >= 2 ? argv[ 1 ] : "parameter" );
388 
389   srand( time( NULL ) );
390 
391   typedef Dune::GridSelector::GridType GridType;
392   GridType &grid = Dune::Fem::TestGrid::grid();
393 
394   int refCount = Dune::Fem::Parameter::getValue< int >( "startLevel", 0 );
395   const int refineStepsForHalf = Dune::Fem::TestGrid::refineStepsForHalf();
396   Dune::Fem::GlobalRefine::apply( grid, refCount*refineStepsForHalf );
397 
398   typedef Dune::Fem::LeafGridPart< GridType > GridPartType;
399   GridPartType gridPart( grid );
400   traverse( gridPart );
401 
402   return 0;
403 }
404