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