1 #ifndef FVSCHEME_HH
2 #define FVSCHEME_HH
3 
4 #include <limits>
5 
6 #include <dune/common/version.hh>
7 #include <dune/common/fvector.hh>
8 
9 #include <dune/grid/common/gridenums.hh>
10 
11 #include "adaptation.hh"
12 
13 // GridMarker
14 // ----------
15 
16 /** \class GridMarker
17  *  \brief class for marking entities for adaptation.
18  *
19  *  This class provides some additional strategies for marking elements
20  *  which are not so much based on an indicator but more on mere
21  *  geometrical and run time considerations. If based on some indicator
22  *  an entity is to be marked, this class additionally tests for example
23  *  that a maximal or minimal level will not be exceeded.
24  */
25 template< class Grid >
26 struct GridMarker
27 {
28   typedef typename Grid::template Codim< 0 >::Entity        Entity;
29 
30   /** \brief constructor
31    *  \param grid     the grid. Here we can not use a grid view since they only
32    *                  a constant reference to the grid and the
33    *                  mark method can not be called.
34    *  \param minLevel the minimum refinement level
35    *  \param maxLevel the maximum refinement level
36    */
GridMarkerGridMarker37   GridMarker( Grid &grid, int minLevel, int maxLevel )
38   : grid_(grid),
39     minLevel_( minLevel ),
40     maxLevel_( maxLevel ),
41     wasMarked_( 0 ),
42     adaptive_( maxLevel_ > minLevel_ )
43   {}
44 
45   /** \brief mark an element for refinement
46    *  \param entity  the entity to mark; it will only be marked if its level is below maxLevel.
47    */
refineGridMarker48   void refine ( const Entity &entity )
49   {
50     if( entity.level() < maxLevel_ )
51     {
52       grid_.mark( 1, entity );
53       wasMarked_ = 1;
54     }
55   }
56 
57   /** \brief mark an element for coarsening
58    *  \param entity  the entity to mark; it will only be marked if its level is above minLevel.
59    */
coarsenGridMarker60   void coarsen ( const Entity &entity )
61   {
62     if( (get( entity ) <= 0) && (entity.level() > minLevel_) )
63     {
64       grid_.mark( -1, entity );
65       wasMarked_ = 1;
66     }
67   }
68 
69   /** \brief get the refinement marker
70    *  \param entity entity for which the marker is required
71    *  \return value of the marker
72    */
getGridMarker73   int get ( const Entity &entity ) const
74   {
75     if( adaptive_ )
76       return grid_.getMark( entity );
77     else
78     {
79       // return so that in scheme.mark we only count the elements
80       return 1;
81     }
82   }
83 
84   /** \brief returns true if any entity was marked for refinement
85    */
markedGridMarker86   bool marked()
87   {
88     if( adaptive_ )
89     {
90       wasMarked_ = grid_.comm().max (wasMarked_);
91       return (wasMarked_ != 0);
92     }
93     return false ;
94   }
95 
resetGridMarker96   void reset() { wasMarked_ = 0 ; }
97 
98 private:
99   Grid &grid_;
100   const int minLevel_;
101   const int maxLevel_;
102   int wasMarked_;
103   const bool adaptive_ ;
104 };
105 
106 // FiniteVolumeScheme
107 // ------------------
108 /** \class FiniteVolumeScheme
109  *  \brief the implementation of the finite volume scheme
110  *
111  *  \tparam  V    type of vector modelling a piecewise constant function
112  *  \tparam  Model  discretization of the Model.
113  *                  This template class must provide
114  *                  the following types and methods:
115  *  \code
116       typedef ... RangeType;
117       const ProblemData &problem () const;
118       double numericalFlux ( const DomainType &normal,
119                              const double time,
120                              const DomainType &xGlobal,
121                              const RangeType &uLeft,
122                              const RangeType &uRight,
123                              RangeType &flux ) const;
124       double boundaryFlux ( const int bndId,
125                             const DomainType &normal,
126                             const double time,
127                             const DomainType &xGlobal,
128                             const RangeType& uLeft,
129                             RangeType &flux ) const;
130   * \endcode
131   */
132 /** \class FiniteVolumeScheme
133  *  Additional methods on the model
134  *  class required for adaptation:
135  *  \code
136       double indicator ( const DomainType &normal,
137                          const double time,
138                          const DomainType &xGlobal,
139                          const RangeType &uLeft, const RangeType &uRight) const
140       double boundaryIndicator ( const int bndId,
141                                  const DomainType &normal,
142                                  const double time,
143                                  const DomainType &xGlobal,
144                                  const RangeType& uLeft) const
145  *  \endcode
146  */
147 template< class V, class Model >
148 struct FiniteVolumeScheme
149 {
150   // first we extract some types
151   typedef V Vector;
152   typedef typename Vector::GridView GridView;
153   typedef typename GridView::Grid Grid;
154   static const int dim = GridView::dimension;
155   static const int dimworld = GridView::dimensionworld;
156   static const int dimRange = Model::dimRange;
157   typedef typename Grid::ctype ctype;
158 
159   // only apply the scheme to interior elements
160   static const Dune :: PartitionIteratorType ptype = Dune :: InteriorBorder_Partition ;
161 
162   // types of codim zero entity iterator and geometry
163   typedef typename GridView::template Codim< 0 >:: template Partition< ptype > :: Iterator  Iterator;
164   typedef typename Iterator::Entity                         Entity;
165   typedef typename Entity::Geometry                         Geometry;
166 
167   // type of intersections and corresponding geometries
168   typedef typename GridView::IntersectionIterator       IntersectionIterator;
169   typedef typename IntersectionIterator::Intersection   Intersection;
170   typedef typename Intersection::Geometry               IntersectionGeometry;
171 
172   // types of vectors
173   typedef Dune::FieldVector< ctype, dim-1 >      FaceDomainType;
174   typedef Dune::FieldVector< ctype, dim >        DomainType;
175   typedef Dune::FieldVector< ctype, dimworld >   GlobalType;
176   typedef typename Model::RangeType              RangeType;
177 
178 public:
179   /** \brief constructor
180    *
181    *  \param[in]  gridView  gridView to operate on
182    *  \param[in]  model       discretization of the Model
183    */
FiniteVolumeSchemeFiniteVolumeScheme184   FiniteVolumeScheme ( const GridView &gridView, const Model &model )
185   : gridView_( gridView )
186     , model_( model )
187   {}
188 
189   /** \brief compute the update vector for one time step
190    *
191    *  \param[in]   time      current time
192    *  \param[in]   solution  solution at time <tt>time</tt>
193    *                         (arbitrary type with operator[](const Entity&) operator)
194    *  \param[out]  update    result of the flux computation
195    *
196    *  \returns maximal time step
197    */
198   template <class Arg>
199   double
200   operator() ( const double time, const Arg &solution, Vector &update ) const;
201   template <class Arg>
202   double
203   border ( const double time, const Arg &solution, Vector &update ) const;
204 
205   /** \brief set grid marker for refinement / coarsening
206    *
207    *  \param[in]  time      current time
208    *  \param[in]  solution  solution at time <tt>time</tt>
209    *  \param      marker    grid marker
210    *
211    *  \note The marker is responsible for limiting the grid depth.
212    *
213    *  \return number of interior elements
214    */
215   size_t
216   mark ( const double time, const Vector &solution, GridMarker< Grid > &marker ) const;
217 
218   /** \brief obtain the grid view for this scheme
219    *
220    *  \returns the grid view
221    */
gridViewFiniteVolumeScheme222   const GridView &gridView () const
223   {
224     return gridView_;
225   }
226 
227 private:
228   template <class Arg>
229   void apply (const Entity &entiy, const double time, const Arg &solution, Vector &update, double &dt ) const;
230 
231   const GridView gridView_;
232   const Model &model_;
233 }; // end FiniteVolumeScheme
234 
235 template< class V, class Model >
236 template< class Arg >
237 inline double FiniteVolumeScheme< V, Model >
border(const double time,const Arg & solution,Vector & update) const238   ::border ( const double time, const Arg &solution, Vector &update ) const
239 {
240   // if model does not have numerical flux we have nothing to do here
241   if( ! Model::hasFlux ) return model_.fixedDt();
242 
243   // time step size (using std:min(.,dt) so set to maximum)
244   double dt = std::numeric_limits<double>::infinity();
245 
246   static const Dune :: PartitionIteratorType pghosttype = Dune :: Ghost_Partition ;
247   typedef typename GridView::template Codim< 0 >:: template Partition< pghosttype > :: Iterator  Iterator;
248   // compute update vector and optimum dt in one grid traversal
249   const Iterator endit = gridView().template end< 0, pghosttype >();
250   for( Iterator it = gridView().template begin< 0, pghosttype >(); it != endit; ++it )
251   {
252     const Entity &entity = *it;
253     const IntersectionIterator iitend = gridView().iend( entity );
254     for( IntersectionIterator iit = gridView().ibegin( entity ); iit != iitend; ++iit )
255     {
256       apply( iit->outside(), time, solution, update, dt );
257     }
258   } // end grid traversal
259 
260   // return time step
261   return  dt;
262 }
263 
264 template< class V, class Model >
265 template< class Arg >
266 inline double FiniteVolumeScheme< V, Model >
operator ()(const double time,const Arg & solution,Vector & update) const267   ::operator() ( const double time, const Arg &solution, Vector &update ) const
268 {
269   // if model does not have numerical flux we have nothing to do here
270   if( ! Model::hasFlux ) return model_.fixedDt();
271 
272   // time step size (using std:min(.,dt) so set to maximum)
273   double dt = std::numeric_limits<double>::infinity();
274 
275   // compute update vector and optimum dt in one grid traversal
276   const Iterator endit = gridView().template end< 0, ptype >();
277   for( Iterator it = gridView().template begin< 0, ptype >(); it != endit; ++it )
278     apply( *it, time, solution, update, dt );
279 
280   // return time step
281   return  dt;
282 }
283 
284 template< class V, class Model >
285 template< class Arg >
286 inline void FiniteVolumeScheme< V, Model >
apply(const Entity & entity,const double time,const Arg & solution,Vector & update,double & dt) const287   ::apply ( const Entity &entity,
288               const double time, const Arg &solution, Vector &update, double &dt ) const
289 {
290   if ( ! update.visitElement( entity ) )
291     return;
292 
293   const Geometry &geo = entity.geometry();
294 
295   // estimate for wave speed
296   double waveSpeed = 0.0;
297 
298   // cell volume
299   const double enVolume = geo.volume();
300 
301   // 1 over cell volume
302   const double enVolume_1 = 1.0/enVolume;
303 
304   // run through all intersections with neighbors and boundary
305   const IntersectionIterator iitend = gridView().iend( entity );
306   for( IntersectionIterator iit = gridView().ibegin( entity ); iit != iitend; ++iit )
307   {
308     const Intersection &intersection = *iit;
309     /* Fetch the intersection's geometry and reference element */
310     const IntersectionGeometry &intersectionGeometry = intersection.geometry();
311 
312     /* Get some geometrical information about the intersection */
313     const GlobalType point = intersectionGeometry.center();
314     const GlobalType normal = intersection.centerUnitOuterNormal();
315     const double faceVolume = intersection.geometry().volume();
316 
317     // handle interior face
318     if( intersection.neighbor() )
319     {
320       // access neighbor
321       const Entity &neighbor = intersection.outside();
322 
323       // compute flux from one side only
324       if( update.visitElement( neighbor ) )
325       {
326         // calculate (1 / neighbor volume)
327         const double nbVolume = neighbor.geometry().volume();
328         const double nbVolume_1 = 1.0 / nbVolume;
329 
330         // evaluate data
331         const RangeType uLeft  = solution.evaluate( entity, point );
332         const RangeType uRight = solution.evaluate( neighbor, point );
333         // apply numerical flux
334         RangeType flux;
335         double ws = model_.numericalFlux( normal, time, point, uLeft, uRight, flux );
336         waveSpeed = ws * faceVolume;
337 
338         // calc update of entity
339         update[ entity ].axpy( -enVolume_1 * faceVolume, flux );
340         // calc update of neighbor
341         update[ neighbor ].axpy( nbVolume_1 * faceVolume, flux );
342 
343         // compute dt restriction
344         dt = std::min( dt, std::min( enVolume, nbVolume ) / waveSpeed );
345       }
346     }
347     // handle boundary face
348     else
349     {
350       // evaluate data
351       const RangeType uLeft = solution.evaluate( entity, point );
352       // apply boundary flux
353       RangeType flux;
354       double ws = model_.boundaryFlux( normal, time, point, uLeft, flux );
355       waveSpeed = ws * faceVolume;
356 
357       // calc update on entity
358       update[ entity ].axpy( -enVolume_1 * faceVolume, flux );
359 
360       // compute dt restriction
361       dt = std::min( dt, enVolume / waveSpeed );
362     }
363   } // end all intersections
364 
365   // mark entity as done
366   update.visited( entity );
367 }
368 
369 template< class V, class Model >
370 inline size_t FiniteVolumeScheme< V, Model >
mark(const double time,const Vector & solution,GridMarker<Grid> & marker) const371   ::mark ( const double time, const Vector &solution, GridMarker<Grid> &marker ) const
372 {
373   size_t elements = 0;
374 
375   // clear grid markers internal flags
376   marker.reset();
377 
378   // grid traversal
379   const Iterator endit = gridView().template end< 0, ptype >();
380   for( Iterator it = gridView().template begin< 0, ptype >(); it != endit; ++it, ++elements )
381   {
382     const Entity &entity = *it;
383 
384     // if marked for refinement nothing has to be done for this element
385     if( marker.get( entity ) > 0 )
386       continue;
387 
388     // maximum value of the indicator over all intersections
389     double entityIndicator = 0.0;
390 
391     // need the value on the entity
392     const RangeType &uLeft = solution[ entity ];
393 
394     // run through all intersections with neighbors and boundary
395     const IntersectionIterator iiterend = gridView().iend( entity );
396     for( IntersectionIterator iiter = gridView().ibegin( entity ); iiter != iiterend; ++iiter )
397     {
398       const Intersection &intersection = *iiter;
399 
400       // indicator for this intersection
401       double localIndicator = 0.0;
402 
403       // geometry for this intersection
404       const IntersectionGeometry &intersectionGeometry = intersection.geometry();
405       // no neighbor?
406       if( !intersection.neighbor() )
407       {
408         const GlobalType point = intersectionGeometry.center();
409         GlobalType normal = intersection.centerUnitOuterNormal();
410         // compute indicator for intersection
411         localIndicator = model_.boundaryIndicator( normal, time, point, uLeft );
412       }
413       else
414       {
415         // access neighbor
416         const Entity &neighbor = intersection.outside();
417 
418         const RangeType &uRight = solution[ neighbor ];
419 
420         const GlobalType point = intersectionGeometry.center();
421         GlobalType normal = intersection.centerUnitOuterNormal();
422         // compute indicator for this intersection
423         localIndicator  = model_.indicator( normal, time, point, uLeft, uRight );
424       }
425 
426       // for coarsening we need maximum indicator over all intersections
427       entityIndicator = std::max( entityIndicator, localIndicator );
428 
429       // test if we can mark for refinement and quit this entity
430       if( localIndicator > model_.problem().refineTol() )
431       {
432         marker.refine( entity );
433         // we can now continue with next entity
434         break;
435       }
436     } // end of loop over intersections
437 
438     // now see if this entity can be removed
439     if( entityIndicator < model_.problem().coarsenTol() )
440     {
441       marker.coarsen( entity );
442     }
443   } // end of loop over entities
444 
445   // return number of elements
446   return elements;
447 }
448 
449 #endif // #ifndef FVSCHEME_HH
450