1 #ifndef DUNE_FEM_ADAPTATIONMANAGER_HH 2 #define DUNE_FEM_ADAPTATIONMANAGER_HH 3 4 //- system includes 5 #include <string> 6 7 //- local includes 8 #include <dune/common/timer.hh> 9 #include <dune/fem/space/common/dofmanager.hh> 10 #include <dune/fem/operator/common/objpointer.hh> 11 12 #include <dune/fem/misc/capabilities.hh> 13 #include <dune/fem/space/common/communicationmanager.hh> 14 #include <dune/fem/space/common/loadbalancer.hh> 15 #include <dune/fem/space/common/restrictprolonginterface.hh> 16 #include <dune/fem/storage/singletonlist.hh> 17 18 #include <dune/fem/space/common/adaptcallbackhandle.hh> 19 #include <dune/fem/io/parameter.hh> 20 #include <dune/fem/io/file/persistencemanager.hh> 21 #include <dune/fem/misc/threads/threadmanager.hh> 22 23 #include <dune/fem/space/common/dataprojection/dataprojection.hh> 24 25 namespace Dune 26 { 27 28 namespace Fem 29 { 30 31 /** @addtogroup Adaptation Adaptation 32 Here the interfaces and algorithms for adapatation of a grid are 33 described and implemented. 34 35 The strategy for restrict/prolong of data is chosen through the 36 parameter 37 \parametername \c fem.adaptation.method \n 38 method used for 39 prolongation/restriction of data during grid 40 refinement; 41 defaults to generic \n 42 Values are: 43 - 0 == none: no adaptation is performed 44 - 1 == generic: works on all grids 45 - 2 == callback: only AlbertaGrid and ALUGrid 46 . 47 48 \remarks 49 The Interface of Adaptation Manager is described by the class 50 AdaptationManagerInterface. 51 @{ 52 **/ 53 54 /** \brief AdaptationManagerInterface class. 55 56 This Class is the result of a combination of different 57 AdaptationOperators. It is the same principle as with Mapping. 58 */ 59 class AdaptationManagerInterface : virtual public LoadBalancerInterface 60 { 61 public: 62 //! \brief default constructor AdaptationManagerInterface()63 AdaptationManagerInterface () : am_ (0) {} 64 65 //! \brief destructor ~AdaptationManagerInterface()66 virtual ~AdaptationManagerInterface () {} 67 68 /** \brief on call of this method the internal adaptation operator is 69 called. 70 */ adapt()71 virtual void adapt () 72 { 73 //std::cout << "called AdaptationManagerInterface::adapt()" << std::endl; 74 if(am_) am_->adapt(); 75 else 76 { 77 std::cerr << "WARNING: AdaptationManagerInterface::adapt: no adaptation manager assigned! \n"; 78 } 79 } 80 81 /** \brief returns true if adaptation manager as adaptation method different to NONE 82 \return \b true if adaptation method is not NONE, \b false otherwise 83 */ adaptive() const84 virtual bool adaptive () const 85 { 86 return (am_) ? (am_->adaptive()) : false; 87 } 88 89 /** \brief returns name of adaptation method 90 \return name of adaptation method 91 */ methodName() const92 virtual const char * methodName() const 93 { 94 return (am_) ? (am_->methodName()) : "unknown method"; 95 } 96 97 /** \brief Assignment operator, pointer to adaptation manager is stored 98 \return reference to this (i.e. *this) 99 */ operator =(const AdaptationManagerInterface & am)100 AdaptationManagerInterface & operator = (const AdaptationManagerInterface & am) 101 { 102 /** \todo This const-casting seems strange to me! */ 103 am_ = const_cast<AdaptationManagerInterface *> (&am); 104 return (*this); 105 } 106 107 /** @copydoc LoadBalancerInterface::loadBalance */ loadBalance()108 virtual bool loadBalance () 109 { 110 return (am_) ? (am_->loadBalance()) : false; 111 } 112 113 /** @copydoc LoadBalancerInterface::balanceCounter */ balanceCounter() const114 virtual int balanceCounter () const 115 { 116 return (am_) ? (am_->balanceCounter()) : 0; 117 } 118 119 /** \brief time that last adaptation cycle took */ adaptationTime() const120 virtual double adaptationTime () const 121 { 122 return 0.0; 123 } 124 125 private: 126 //! pointer to adaptation manager 127 AdaptationManagerInterface* am_; 128 }; 129 130 /** \brief AdaptationMethod is a simple adaptation method reader class. */ 131 template <class GridType> 132 class AdaptationMethod : virtual public AdaptationManagerInterface 133 { 134 public: 135 //! type of adaptation method 136 enum AdaptationMethodType { none = 0, //!< no adaptation is performed 137 generic = 1, //!< a generic restriction and prolongation algorithm is used 138 callback = 2 //!< the callback mechanism from AlbertaGrid and ALUGrid is used 139 }; 140 141 public: 142 /** \brief constructor of AdaptationMethod 143 The following optional parameters are used 144 # 0 == none, 1 == generic, 2 == call back (only AlbertaGrid and ALUGrid) 145 AdaptationMethod: 1 # default value 146 \param grid Grid that adaptation method is read for 147 148 */ AdaptationMethod(const GridType & grid,const ParameterReader & parameter=Parameter::container ())149 AdaptationMethod ( const GridType &grid, const ParameterReader ¶meter = Parameter::container() ) 150 : adaptationMethod_(generic) 151 { 152 const bool output = ( Parameter :: verbose() && ThreadManager::isMaster() ); 153 int am = 1; 154 const std::string methodNames [] = { "none", "generic", "callback" }; 155 am = parameter.getEnum("fem.adaptation.method", methodNames, am); 156 init(am,output); 157 } 158 private: init(int am,const bool output)159 void init(int am,const bool output) 160 { 161 162 // chose adaptation method 163 if(am == 2) adaptationMethod_ = callback; 164 else if(am == 1) adaptationMethod_ = generic; 165 else adaptationMethod_ = none; 166 167 // for structred grid adaptation is disabled 168 if( ! Capabilities::isLocallyAdaptive<GridType>::v ) 169 { 170 adaptationMethod_ = none; 171 if( output ) 172 { 173 std::cerr << "WARNING: AdaptationMethod: adaptation disabled for structured grid! \n"; 174 } 175 } 176 177 if( output ) 178 { 179 std::cout << "Created AdaptationMethod: adaptation method = " << methodName() << std::endl; 180 } 181 } 182 public: 183 //! virtual destructor ~AdaptationMethod()184 virtual ~AdaptationMethod () {} 185 186 /** \copydoc Dune::Fem::AdaptationManagerInterface::methodName */ methodName() const187 virtual const char * methodName() const 188 { 189 switch (adaptationMethod_) { 190 case generic: return "generic"; 191 case callback: return "callback"; 192 case none: return "no adaptation"; 193 default: return "unknown method"; 194 } 195 } 196 197 /** \copydoc Dune::Fem::AdaptationManagerInterface::adaptive */ adaptive() const198 virtual bool adaptive () const { return adaptationMethod_ != none; } 199 200 protected: 201 //! method identifier 202 AdaptationMethodType adaptationMethod_; 203 }; 204 205 /*! \brief This class manages the adaptation process. 206 If the method adapt is called, then the grid is adapted and also 207 all the data belonging to the given dof manager will be rearranged 208 for data set where it is necessary to keep the data. 209 */ 210 template <class GridType, class RestProlOperatorImp > 211 class AdaptationManagerBase 212 : public AdaptationMethod< GridType >, 213 public ObjPointerStorage 214 { 215 typedef AdaptationMethod< GridType > BaseType; 216 typedef typename BaseType :: AdaptationMethodType AdaptationMethodType; 217 218 template <class AdaptManager, class GridImp, bool isGoodGrid> 219 struct CallAdaptationMethod 220 { 221 template <class DofManagerImp, class RPOpImp> adaptDune::Fem::AdaptationManagerBase::CallAdaptationMethod222 static void adapt(const AdaptManager& am, GridImp & grid, 223 DofManagerImp& dm , RPOpImp& rpop, 224 AdaptationMethodType adaptMethod) 225 { 226 // use generic adapt method 227 if( adaptMethod == BaseType :: generic ) 228 { 229 am.template genericAdapt<All_Partition> (); 230 return ; 231 } 232 233 // use grid call back adapt method 234 if( adaptMethod == BaseType :: callback ) 235 { 236 // combine dof manager and restrict prolong operator 237 typedef RestrictProlongWrapper< GridImp, DofManagerType, RPOpImp > RPType; 238 239 // create new handle 240 RPType restrictProlongHandle ( dm , rpop ); 241 242 // reserve memory 243 restrictProlongHandle.initialize(); 244 245 // call grid adaptation 246 grid.adapt( restrictProlongHandle ); 247 248 // do compress (if not already called) 249 restrictProlongHandle.finalize(); 250 return ; 251 } 252 } 253 }; 254 255 template <class AdaptManager, class GridImp> 256 struct CallAdaptationMethod<AdaptManager,GridImp,false> 257 { 258 template <class DofManagerImp, class RPOpImp> adaptDune::Fem::AdaptationManagerBase::CallAdaptationMethod259 static void adapt(const AdaptManager& am, GridImp & grid, 260 DofManagerImp& dm , RPOpImp& rpop, 261 AdaptationMethodType adaptMethod) 262 { 263 // use generic adapt method 264 if(adaptMethod != BaseType :: none ) 265 { 266 // use partition type All_Partition, 267 // since we also need to iterate on ghosts 268 // for wasChanged information gathering 269 am.template genericAdapt<All_Partition> (); 270 return ; 271 } 272 } 273 }; 274 275 //! type of this class 276 typedef AdaptationManagerBase<GridType,RestProlOperatorImp> ThisType; 277 278 //! type of dof manager 279 typedef DofManager< GridType > DofManagerType; 280 281 public: 282 typedef typename GridType :: Traits :: LocalIdSet LocalIdSet; 283 284 /** \brief constructor of AdaptationManagerBase 285 The following optional parameter can be used 286 # 0 == none, 1 == generic, 2 == call back (only AlbertaGrid and ALUGrid) 287 AdaptationMethod: 1 # default value 288 \param grid Grid that adaptation is done for 289 \param rpOp restriction and prlongation operator that describes how the 290 user data is projected to other grid levels 291 the following two lines: 292 */ AdaptationManagerBase(GridType & grid,RestProlOperatorImp & rpOp,const ParameterReader & parameter=Parameter::container ())293 AdaptationManagerBase ( GridType &grid, RestProlOperatorImp &rpOp, const ParameterReader ¶meter = Parameter::container() ) 294 : BaseType( grid, parameter ), 295 grid_( grid ), 296 dm_( DofManagerType::instance( grid_ ) ), 297 rpOp_( rpOp ), 298 adaptTime_( 0.0 ), 299 wasChanged_( false ) 300 {} 301 302 //! destructor ~AdaptationManagerBase()303 virtual ~AdaptationManagerBase () {} 304 305 //! no public method, but has to be public, because all AdaptationManagers 306 //! must be able to call this method and the template parameters are 307 //! allways different getRestProlOp()308 RestProlOperatorImp & getRestProlOp () 309 { 310 return rpOp_; 311 } 312 313 /** \brief 314 according to adaption method parameter 315 the adaption procedure is done, 316 0 == no adaptation 317 1 == generic adaption 318 2 == grid call back adaptation (only in AlbertaGrid and ALUGrid) 319 */ adapt()320 virtual void adapt () 321 { 322 // make sure this is only called in single thread mode 323 assert( Fem :: ThreadManager :: singleThreadMode() ); 324 325 // get stopwatch 326 Dune::Timer timer; 327 328 const bool supportsCallback = Capabilities :: supportsCallbackAdaptation< GridType > :: v; 329 CallAdaptationMethod< ThisType, GridType, supportsCallback > 330 :: adapt(*this,grid_,dm_,rpOp_,this->adaptationMethod_); 331 332 // take time 333 adaptTime_ = timer.elapsed(); 334 } 335 336 //! \brief default load balancing method which does nothing loadBalance()337 virtual bool loadBalance () 338 { 339 return false; 340 } 341 342 //! default load balancing counter is zero balanceCounter() const343 virtual int balanceCounter () const 344 { 345 return 0; 346 } 347 348 /** \copydoc Dune::Fem::AdaptationManagerInterface::adaptationTime */ adaptationTime() const349 virtual double adaptationTime() const 350 { 351 return adaptTime_; 352 } 353 354 protected: getDofManager(const GridType & grid)355 static DofManagerType& getDofManager(const GridType& grid) 356 { 357 return DofManagerType :: instance( grid ); 358 } 359 360 private: 361 /** \brief generic adaptation procedure 362 adapt defines the grid walkthrough before and after grid adaptation. 363 Note that the LocalOperator can be an combined Operator 364 Domain and Range are defined through class Operator 365 */ 366 template <PartitionIteratorType pitype> genericAdapt() const367 void genericAdapt () const 368 { 369 // initialize restrict prolong operator (e.g. PetscRestrictProlong... ) 370 rpOp_.initialize(); 371 372 // call pre-adapt, returns true if at least 373 // one element is marked for coarsening 374 bool restr = grid_.preAdapt(); 375 376 // get macro grid view 377 typedef typename GridType::LevelGridView MacroGridView; 378 typedef typename MacroGridView :: template Codim<0>:: 379 template Partition<pitype> :: Iterator MacroIterator; 380 381 // reset flag 382 wasChanged_ = false ; 383 384 if(restr) 385 { 386 387 // get macro grid view 388 MacroGridView macroView = grid_.levelGridView( 0 ); 389 390 // make a hierarchical to insert all elements 391 // that are father of elements that might be coarsened 392 393 { 394 // get macro iterator 395 MacroIterator endit = macroView.template end<0,pitype> (); 396 for(MacroIterator it = macroView.template begin<0,pitype>(); 397 it != endit; ++it ) 398 { 399 hierarchicRestrict( *it , dm_.indexSetRestrictProlongNoResize() ); 400 } 401 } 402 403 // if at least one element was found for restriction 404 if( wasChanged_ ) 405 { 406 // now resize memory 407 dm_.resizeForRestrict(); 408 409 // now project all data to fathers 410 { 411 // get macro iterator 412 MacroIterator endit = macroView.template end<0,pitype> (); 413 for(MacroIterator it = macroView.template begin<0,pitype>(); 414 it != endit; ++it ) 415 { 416 hierarchicRestrict( *it , rpOp_ ); 417 } 418 } 419 } 420 } 421 422 // adapt grid due to preset markers 423 // returns true if at least one element was refined 424 const bool refined = grid_.adapt(); 425 426 // if coarsening or refinement was done 427 // adjust sizes 428 if( refined || restr ) 429 { 430 // resizes the index sets (insert all new indices) 431 // and resizes the memory 432 dm_.resize(); 433 } 434 435 // in case elements were created do prolongation 436 if( refined ) 437 { 438 // get macro grid view 439 MacroGridView macroView = grid_.levelGridView( 0 ); 440 441 // make run through grid to project data 442 MacroIterator endit = macroView.template end<0,pitype> (); 443 for(MacroIterator it = macroView.template begin<0,pitype>(); 444 it != endit; ++it ) 445 { 446 hierarchicProlong( *it , rpOp_ ); 447 } 448 } 449 450 // notifyGlobalChange make wasChanged equal on all cores 451 if( dm_.notifyGlobalChange( wasChanged_ ) ) 452 { 453 // compress index sets and data 454 // this will increase the sequence counter 455 dm_.compress(); 456 } 457 458 // do cleanup 459 grid_.postAdapt(); 460 461 // finalize restrict prolong operator (e.g. PetscRestrictProlong... ) 462 rpOp_.finalize(); 463 } 464 465 private: 466 //! make hierarchic walk trough for restriction 467 template <class EntityType, class RestrictOperatorType > hierarchicRestrict(const EntityType & entity,RestrictOperatorType & restop) const468 bool hierarchicRestrict ( const EntityType& entity, RestrictOperatorType & restop ) const 469 { 470 if( ! entity.isLeaf() ) 471 { 472 // true means we are going to restrict data 473 bool doRestrict = true; 474 475 // check partition type 476 const bool isGhost = entity.partitionType() == GhostEntity ; 477 478 // if the children have children then we have to go deeper 479 const int childLevel = entity.level() + 1; 480 typedef typename EntityType::HierarchicIterator HierarchicIterator; 481 482 // check all children first 483 { 484 const HierarchicIterator endit = entity.hend( childLevel ); 485 for(HierarchicIterator it = entity.hbegin( childLevel ); it != endit; ++it) 486 { 487 doRestrict &= hierarchicRestrict( *it , restop ); 488 } 489 } 490 491 // if doRestrict is still true, restrict data 492 if(doRestrict) 493 { 494 // we did at least one restriction 495 wasChanged_ = true; 496 497 // do not restrict the solution on ghosts, this will 498 // fail, but we still need the wasChanged info, so simply 499 // calling hierarchicRestrict on interior won't work either 500 if( ! isGhost ) 501 { 502 // true for first child, otherwise false 503 bool initialize = true; 504 const HierarchicIterator endit = entity.hend( childLevel ); 505 for(HierarchicIterator it = entity.hbegin( childLevel ); it != endit; ++it) 506 { 507 // restrict solution 508 restop.restrictLocal( entity, *it , initialize); 509 // reset initialize flag 510 initialize = false; 511 } 512 restop.restrictFinalize(entity); 513 } 514 } 515 } 516 517 // if all children return mightBeCoarsened, 518 // then doRestrict on father remains true 519 return entity.mightVanish(); 520 } 521 522 template <class EntityType, class ProlongOperatorType > hierarchicProlong(const EntityType & entity,ProlongOperatorType & prolop) const523 void hierarchicProlong ( const EntityType &entity, ProlongOperatorType & prolop ) const 524 { 525 typedef typename EntityType::HierarchicIterator HierarchicIterator; 526 527 // NOTE: initialize not working here 528 // because we call hierarchically 529 530 // first call on this element 531 bool initialize = true; 532 533 // check partition type 534 const bool isGhost = entity.partitionType() == GhostEntity ; 535 536 const int maxLevel = grid_.maxLevel(); 537 const HierarchicIterator endit = entity.hend( maxLevel ); 538 for( HierarchicIterator it = entity.hbegin( maxLevel ); it != endit; ++it ) 539 { 540 // should only get here on non-leaf entities 541 assert( !entity.isLeaf() ); 542 543 const EntityType & son = *it; 544 if( son.isNew() ) 545 { 546 // the grid was obviously changed if we get here 547 wasChanged_ = true ; 548 549 // do not prolong the solution on ghosts, this will 550 // fail, but we still need the wasChanged info, so simply 551 // calling hierarchicRestrict on interior won't work either 552 if( ! isGhost ) 553 { 554 EntityType vati = son.father(); 555 prolop.prolongLocal( vati , son , initialize ); 556 initialize = false; 557 } 558 } 559 } 560 } 561 562 protected: 563 //! corresponding grid 564 GridType &grid_; 565 566 //! DofManager corresponding to grid 567 DofManagerType &dm_; 568 569 //! Restriction and Prolongation Operator 570 RestProlOperatorImp &rpOp_; 571 572 //! time that adaptation took 573 double adaptTime_; 574 575 //! flag for restriction 576 mutable bool wasChanged_; 577 }; 578 579 //! factory class to create adaptation manager reference counter 580 template <class KeyType, class ObjectType> 581 struct AdaptationManagerReferenceFactory 582 { createObjectDune::Fem::AdaptationManagerReferenceFactory583 static ObjectType* createObject(const KeyType& key) 584 { 585 return new ObjectType(0); 586 } deleteObjectDune::Fem::AdaptationManagerReferenceFactory587 static void deleteObject(ObjectType* obj) 588 { 589 delete obj; 590 } 591 }; 592 593 /*! \brief This class manages the adaptation process including a load 594 balancing after the adaptation step. This class is created by the 595 AdaptationManager for each grid instance. See AdaptationManager for 596 details. 597 */ 598 template <class GridType, class RestProlOperatorImp> 599 class AdaptationManager : 600 public AdaptationManagerBase<GridType,RestProlOperatorImp> , 601 public LoadBalancer<GridType>, 602 public AutoPersistentObject 603 { 604 // type of key 605 typedef const GridType* KeyType; 606 // object type 607 typedef size_t ObjectType; 608 // type of factory 609 typedef AdaptationManagerReferenceFactory<KeyType, ObjectType> FactoryType; 610 611 // type of singleton list 612 typedef SingletonList< KeyType, ObjectType, FactoryType > ProviderType; 613 614 typedef AdaptationManagerBase<GridType,RestProlOperatorImp> BaseType; 615 typedef LoadBalancer<GridType> Base2Type; 616 617 using BaseType :: rpOp_; 618 619 // reference counter to ensure only one instance per grid exists 620 ObjectType& referenceCounter_; 621 622 // do not copy 623 AdaptationManager(const AdaptationManager&); 624 625 public: 626 /** 627 \brief constructor of AdaptationManager 628 629 The following optional parameters are used: 630 \code 631 # 0 == none, 1 == generic, 2 == call back (only AlbertaGrid and ALUGrid) 632 fem.adaptation.method: 1 # default value 633 634 # balance every x-th call to adapt, 0 means no balancing 635 fem.loadbalancing.step: 1 # default value 636 \endcode 637 638 \param grid Grid that adaptation is done for 639 \param rpOp restriction and prlongation operator that describes how the 640 user data is projected to other grid levels 641 \param balanceCounter start counter for balance cycle (default = 0) 642 \param parameter Parameter class holding parameters 643 **/ AdaptationManager(GridType & grid,RestProlOperatorImp & rpOp,int balanceCounter,const ParameterReader & parameter=Parameter::container ())644 AdaptationManager ( GridType &grid, RestProlOperatorImp &rpOp, int balanceCounter, const ParameterReader ¶meter = Parameter::container() ) 645 : BaseType(grid,rpOp, parameter) 646 , Base2Type( grid, rpOp ) 647 , referenceCounter_( ProviderType :: getObject( &grid ) ) 648 , balanceStep_( parameter.getValue< int >( "fem.loadbalancing.step", 1 ) ) 649 , balanceCounter_( balanceCounter ) 650 { 651 if( ++referenceCounter_ > 1 ) 652 DUNE_THROW(InvalidStateException,"Only one instance of AdaptationManager allowed per grid instance"); 653 if( Parameter::verbose() ) 654 std::cout << "Created LoadBalancer: balanceStep = " << balanceStep_ << std::endl; 655 } 656 657 /** 658 \brief constructor of AdaptationManager 659 660 The following optional parameters are used: 661 \code 662 # 0 == none, 1 == generic, 2 == call back (only AlbertaGrid and ALUGrid) 663 fem.adaptation.method: 1 # default value 664 665 # balance every x-th call to adapt, 0 means no balancing 666 fem.loadbalancing.step: 1 # default value 667 \endcode 668 669 \param grid Grid that adaptation is done for 670 \param rpOp restriction and prlongation operator that describes how the 671 user data is projected to other grid levels 672 \param parameter Parameter class holding parameters 673 **/ AdaptationManager(GridType & grid,RestProlOperatorImp & rpOp,const ParameterReader & parameter=Parameter::container ())674 AdaptationManager ( GridType &grid, RestProlOperatorImp &rpOp, const ParameterReader ¶meter = Parameter::container() ) 675 : AdaptationManager( grid, rpOp, 0, parameter ) 676 { 677 } 678 679 //! destructor decreasing reference counter ~AdaptationManager()680 ~AdaptationManager() 681 { 682 -- referenceCounter_; 683 ProviderType :: removeObject( referenceCounter_ ); 684 } 685 686 /** @copydoc LoadBalancerInterface::loadBalance */ loadBalance()687 virtual bool loadBalance () 688 { 689 // same as for the adapt method 690 rpOp_.initialize () ; 691 692 // call load balance 693 const bool result = Base2Type :: loadBalance( ); 694 695 // finalize rp object (mostly RestrictProlongDefault for PetscDF) 696 rpOp_.finalize () ; 697 return result ; 698 } 699 700 /** @copydoc LoadBalancerInterface::loadBalanceTime */ loadBalanceTime() const701 virtual double loadBalanceTime() const 702 { 703 return Base2Type::loadBalanceTime(); 704 } 705 706 /** @copydoc AdaptationManagerInterface::adapt */ adapt()707 virtual void adapt () 708 { 709 // adapt grid 710 BaseType :: adapt (); 711 712 // if adaptation is enabled 713 if( this->adaptive() && (balanceStep_ > 0) ) 714 { 715 // if balance counter has readed balanceStep do load balance 716 const bool callBalance = (++balanceCounter_ >= balanceStep_); 717 718 #ifndef NDEBUG 719 // make sure load balance is called on every process 720 int willCall = (callBalance) ? 1 : 0; 721 const int iCall = willCall; 722 723 // send info from rank 0 to all other 724 Base2Type::grid_.comm().broadcast(&willCall, 1 , 0); 725 726 assert( willCall == iCall ); 727 #endif 728 729 if( callBalance ) 730 { 731 // balance work load and restore consistency in the data 732 loadBalance(); 733 balanceCounter_ = 0; 734 } 735 else 736 { 737 // only restore consistency in the data 738 Base2Type::communicate(); 739 } 740 } 741 } 742 743 //! returns actual balanceCounter for checkpointing balanceCounter() const744 int balanceCounter () const { return balanceCounter_; } 745 746 //! backup internal data backup() const747 void backup() const 748 { 749 std::tuple<const int& > value( balanceCounter_ ); 750 PersistenceManager::backupValue("loadbalancer",value); 751 } 752 753 //! retore internal data restore()754 void restore() 755 { 756 std::tuple< int& > value( balanceCounter_ ); 757 PersistenceManager::restoreValue("loadbalancer",value); 758 } 759 760 private: 761 // call loadBalance ervery balanceStep_ step 762 const int balanceStep_ ; 763 // count actual balance call 764 int balanceCounter_; 765 }; 766 767 namespace hpDG 768 { 769 770 // AdaptationManager 771 // ----------------- 772 773 /** \brief Manages the testriction and prolongation of discrete functions in \f$(h)p\f$-adaptive computations 774 * 775 * \tparam DiscreteFunctionSpace an adaptive discrete function space 776 * \tparam DataProjection a DataProjection type 777 * 778 * \ingroup DiscreteFunctionSpace_RestrictProlong 779 */ 780 template< class DiscreteFunctionSpace, class DataProjection > 781 class AdaptationManager 782 : public Dune::Fem::AdaptationManagerInterface 783 { 784 using ThisType = AdaptationManager< DiscreteFunctionSpace, DataProjection >; 785 786 public: 787 /** \brief discrete function space type */ 788 using DiscreteFunctionSpaceType = DiscreteFunctionSpace; 789 /** \brief data projection type */ 790 using DataProjectionType = DataProjection; 791 792 private: 793 using GridType = typename DiscreteFunctionSpaceType::GridType; 794 using DofManagerType = DofManager< GridType >; 795 796 class DataProjectionWrapper; 797 798 public: 799 /** \name Construction 800 * \{ 801 */ 802 AdaptationManager(DiscreteFunctionSpaceType & space,DataProjectionType && dataProjection)803 explicit AdaptationManager ( DiscreteFunctionSpaceType &space, DataProjectionType &&dataProjection ) 804 : space_( space ), 805 dataProjection_( std::forward< DataProjectionType >( dataProjection ) ), 806 dofManager_( DofManagerType::instance( space.gridPart().grid() ) ), 807 commList_( dataProjection_ ), 808 time_( 0. ) 809 {} 810 811 /** \} */ 812 813 /** \brief Deleted methods 814 * \{ 815 */ 816 817 /** \brief copy constructor */ 818 AdaptationManager ( const ThisType & ) = delete; 819 820 /** \brief assignment operator */ 821 ThisType &operator= ( const ThisType & ) = delete; 822 823 /** \} */ 824 825 /** \name Adaptation 826 * \{ 827 */ 828 829 /** \brief returns \b true */ adaptive() const830 bool adaptive () const { return true; } 831 832 /** \brief perform adaptation */ adapt()833 void adapt () 834 { 835 assert( Dune::Fem::ThreadManager::singleThreadMode() ); 836 837 Dune::Timer timer; 838 839 DataProjectionWrapper wrapper( dataProjection_, dofManager() ); 840 space().adapt( wrapper ); 841 842 if( dofManager().notifyGlobalChange( static_cast< bool >( wrapper ) ) ) 843 dofManager().compress(); 844 845 commList_.exchange(); 846 847 time_ = timer.elapsed(); 848 } 849 850 /** \brief return name of adaptation method */ methodName() const851 const char *methodName () const { return "discrete function space adaptation"; } 852 853 /** \brief return time spent on adaptation */ adaptationTime() const854 double adaptationTime () const { return time_; } 855 856 /** \} */ 857 858 /** \name Load balancing 859 * \{ 860 */ 861 862 /** \brief please doc me */ loadBalance()863 bool loadBalance () { return false; } 864 865 /** \brief please doc me */ balanceCounter() const866 int balanceCounter () const { return 0; } 867 868 /** \brief please doc me */ loadBalanceTime() const869 double loadBalanceTime () const { return 0.; } 870 871 /** \} */ 872 dataProjection()873 DataProjection& dataProjection() { return dataProjection_; } 874 private: space()875 DiscreteFunctionSpaceType &space () { return space_.get(); } 876 space() const877 const DiscreteFunctionSpaceType &space () const { return space_.get(); } 878 dofManager()879 DofManagerType &dofManager () { return dofManager_.get(); } 880 dofManager() const881 const DofManagerType &dofManager () const { return dofManager_.get(); } 882 883 std::reference_wrapper< DiscreteFunctionSpaceType > space_; 884 DataProjectionType dataProjection_; 885 std::reference_wrapper< DofManagerType > dofManager_; 886 mutable CommunicationManagerList commList_; 887 double time_; 888 }; 889 890 // AdaptationManager::DataProjectionWrapper 891 // ---------------------------------------- 892 893 template< class DiscreteFunctionSpace, class DataProjection > 894 class AdaptationManager< DiscreteFunctionSpace, DataProjection >::DataProjectionWrapper 895 : public Dune::Fem::hpDG::DataProjection< DiscreteFunctionSpace, DataProjectionWrapper > 896 { 897 using BaseType = Dune::Fem::hpDG::DataProjection< DiscreteFunctionSpace, DataProjectionWrapper >; 898 899 public: 900 using BasisFunctionSetType = typename BaseType::BasisFunctionSetType; 901 using EntityType = typename BaseType::EntityType; 902 DataProjectionWrapper(DataProjectionType & dataProjection,DofManagerType & dofManager)903 DataProjectionWrapper ( DataProjectionType &dataProjection, DofManagerType &dofManager ) 904 : dataProjection_( dataProjection ), 905 dofManager_( dofManager ), 906 modified_( false ) 907 {} 908 operator ()(const EntityType & entity,const BasisFunctionSetType & prior,const BasisFunctionSetType & present,const std::vector<std::size_t> & origin,const std::vector<std::size_t> & destination)909 void operator() ( const EntityType &entity, 910 const BasisFunctionSetType &prior, 911 const BasisFunctionSetType &present, 912 const std::vector< std::size_t > &origin, 913 const std::vector< std::size_t > &destination ) 914 { 915 dofManager_.get().resizeMemory(); 916 dataProjection_.get()( entity, prior, present, origin, destination ); 917 modified_ = true; 918 } 919 920 template <class TemporaryStorage> operator ()(TemporaryStorage & tmp)921 void operator() ( TemporaryStorage& tmp ) 922 { 923 dataProjection_.get()( tmp ); 924 modified_ = true; 925 } 926 operator bool() const927 explicit operator bool () const 928 { 929 return modified_; 930 } 931 932 private: 933 std::reference_wrapper< DataProjectionType > dataProjection_; 934 std::reference_wrapper< DofManagerType > dofManager_; 935 bool modified_; 936 }; 937 938 } // namespace hpDG 939 940 941 942 /** \brief A class with one static method apply to globally refine a grid. 943 All index sets are adapted to the new grid and the 944 managed dof storage is expanded - but no prolongation or 945 restriction of data is performed. 946 */ 947 struct GlobalRefine 948 { 949 /** \brief apply global refinement and also adjust index sets and 950 managed dof storage. However, user data stored before is lost. 951 \param grid Grid that is globally refined 952 \param step refinement steps that are applied 953 */ 954 template <class GridType> applyDune::Fem::GlobalRefine955 static void apply(GridType& grid, const int step) 956 { 957 typedef DofManager< GridType > DofManagerType; 958 DofManagerType& dm = DofManagerType :: instance(grid); 959 grid.globalRefine(step); 960 grid.loadBalance(); 961 dm.resize(); 962 dm.compress(); 963 } 964 }; 965 /** \brief A class with one static method apply for invoking the local 966 adaptation procedure on a given grid instance. 967 All index sets are adapted to the new grid and the 968 managed dof storage is expanded - but no prolongation or 969 restriction of data is performed. 970 */ 971 struct LocalRefine 972 { 973 /** \brief apply local refinement and also adjust index sets and 974 managed dof storage. However, user data stored before is lost. 975 \param grid Grid that is globally refined 976 */ 977 template <class GridType> applyDune::Fem::LocalRefine978 static void apply(GridType& grid) 979 { 980 typedef DofManager< GridType > DofManagerType; 981 DofManagerType& dm = DofManagerType :: instance(grid); 982 grid.preAdapt(); 983 grid.adapt(); 984 grid.postAdapt(); 985 grid.loadBalance(); 986 dm.resize(); 987 dm.compress(); 988 } 989 }; 990 991 /** @} end documentation group */ 992 993 } // namespace Fem 994 995 } // namespace Dune 996 997 #endif // #ifndef DUNE_FEM_ADAPTMANAGER_HH 998