LCOV - code coverage report
Current view: top level - /builds/ug4-project/ugcore/ug4-new/plugins/Limex/time_disc - limex_integrator.hpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 276 0
Test Date: 2026-06-01 23:54:59 Functions: 0.0 % 291 0

            Line data    Source code
       1              : /*
       2              :  * SPDX-FileCopyrightText: Copyright (c) 2014-2025:  G-CSC, Goethe University Frankfurt
       3              :  * SPDX-License-Identifier: LicenseRef-UG4-LGPL-3.0
       4              :  *
       5              :  * Author: Arne Naegel
       6              :  *
       7              :  * This file is part of UG4.
       8              :  *
       9              :  * UG4 is free software: you can redistribute it and/or modify it under the
      10              :  * terms of the GNU Lesser General Public License version 3 (as published by the
      11              :  * Free Software Foundation) with the following additional attribution
      12              :  * requirements (according to LGPL/GPL v3 §7):
      13              :  *
      14              :  * (1) The following notice must be displayed in the Appropriate Legal Notices
      15              :  * of covered and combined works: "Based on UG4 (www.ug4.org/license)".
      16              :  *
      17              :  * (2) The following notice must be displayed at a prominent place in the
      18              :  * terminal output of covered works: "Based on UG4 (www.ug4.org/license)".
      19              :  *
      20              :  * (3) The following bibliography is recommended for citation and must be
      21              :  * preserved in all covered files:
      22              :  * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively
      23              :  *   parallel geometric multigrid solver on hierarchically distributed grids.
      24              :  *   Computing and visualization in science 16, 4 (2013), 151-164"
      25              :  * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel
      26              :  *   flexible software system for simulating pde based models on high performance
      27              :  *   computers. Computing and visualization in science 16, 4 (2013), 165-179"
      28              :  *
      29              :  * This program is distributed in the hope that it will be useful,
      30              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      31              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      32              :  * GNU Lesser General Public License for more details.
      33              :  */
      34              : 
      35              : #ifndef LIMEX_INTEGRATOR_HPP_
      36              : #define LIMEX_INTEGRATOR_HPP_
      37              : /*
      38              : #define XMTHREAD_BOOST
      39              : #ifdef XMTHREAD_BOOST
      40              : #include <boost/thread/thread.hpp>
      41              : #endif
      42              : */
      43              : #include <string>
      44              : 
      45              : #include "common/stopwatch.h"
      46              : 
      47              : #include "lib_algebra/operator/interface/operator.h"
      48              : #include "lib_algebra/operator/interface/operator_inverse.h"
      49              : #include "lib_algebra/operator/linear_solver/linear_solver.h"
      50              : #include "lib_algebra/operator/debug_writer.h"
      51              : 
      52              : #include "lib_disc/function_spaces/grid_function.h"
      53              : #include "lib_disc/assemble_interface.h" // TODO: missing IAssemble in following file:
      54              : #include "lib_disc/operator/linear_operator/assembled_linear_operator.h"
      55              : #include "lib_disc/operator/non_linear_operator/assembled_non_linear_operator.h"
      56              : #include "lib_disc/spatial_disc/domain_disc.h"
      57              : #include "lib_disc/time_disc/time_disc_interface.h"
      58              : #include "lib_disc/time_disc/theta_time_step.h"
      59              : #include "lib_disc/time_disc/solution_time_series.h"
      60              : #include "lib_disc/function_spaces/grid_function_util.h" // SaveVectorForConnectionViewer
      61              : #include "lib_disc/function_spaces/metric_spaces.h"
      62              : #include "lib_disc/io/vtkoutput.h"
      63              : 
      64              : #include "lib_grid/refinement/refiner_interface.h"
      65              : 
      66              : 
      67              : // own headers
      68              : #include "time_extrapolation.h"
      69              : #include "time_integrator.hpp"
      70              : #include "../limex_tools.h"
      71              : //#include "../multi_thread_tools.h"
      72              : 
      73              : 
      74              : #ifdef UG_JSON
      75              : #include <nlohmann/json.hpp>
      76              : #endif
      77              : 
      78              : #undef LIMEX_MULTI_THREAD
      79              : 
      80              : namespace ug {
      81              : 
      82              : 
      83              : /*
      84              : template<class TI>
      85              : class TimeIntegratorThread : public TI
      86              : {
      87              :         TimeIntegratorThread(SmartPtr<grid_function_type> u1, number t1, ConstSmartPtr<grid_function_type> u0, number t0)
      88              :         {
      89              : 
      90              :         }
      91              : 
      92              :         // thre
      93              :         void apply()
      94              :         {
      95              :                 TI::apply(u1, t1, u0, t0);
      96              :         }
      97              : 
      98              : 
      99              : };*/
     100              : 
     101            0 : static void MyPrintError(UGError &err)
     102              : {
     103            0 :         for(size_t i=0;i<err.num_msg();++i)
     104              :         {
     105              :                 UG_LOG("MYERROR "<<i<<":"<<err.get_msg(i)<<std::endl);
     106            0 :                 UG_LOG("     [at "<<err.get_file(i)<<
     107              :                        ", line "<<err.get_line(i)<<"]\n");
     108              :         }
     109            0 : }
     110              : 
     111              : class ILimexRefiner
     112              : {
     113              :         virtual ~ILimexRefiner(){};
     114              : 
     115              : protected:
     116              :         SmartPtr<IRefiner> m_spRefiner;
     117              : };
     118              : 
     119              : //! Abstract class for the cost of a limex stage.
     120              : /*! The LimexTimeIntegrator requires a model for computing the cost per stage.  */
     121              : class ILimexCostStrategy
     122              : {
     123              : public:
     124              :         /// destructor
     125              :         virtual ~ILimexCostStrategy(){}
     126              : 
     127              :         /// provides the cost for all 0...nstages stages.
     128              :         virtual void update_cost(std::vector<number> &costA, const std::vector<size_t> &vSteps, const size_t nstages) = 0;
     129              : };
     130              : 
     131              : 
     132              : /// Cost is identical to (summation over) number of steps
     133              : class LimexDefaultCost : public ILimexCostStrategy
     134              : {
     135              : public:
     136            0 :         LimexDefaultCost(){};
     137            0 :         void update_cost(std::vector<number> &m_costA, const std::vector<size_t> &m_vSteps, const size_t nstages)
     138              :         {
     139              :                 UG_ASSERT(m_costA.size() >= nstages, "Huhh: Vectors match in size:" << m_costA.size() << "vs." << nstages);
     140              : 
     141            0 :                 UG_LOG("A_0="<< m_vSteps[0] << std::endl);
     142            0 :                 m_costA[0] = (1.0)*m_vSteps[0];
     143            0 :                 for (size_t i=1; i<nstages; ++i)
     144              :                 {
     145            0 :                         m_costA[i] = m_costA[i-1] + (1.0)*m_vSteps[i];
     146            0 :                         UG_LOG("A_i="<< m_vSteps[i] << std::endl);
     147              :                 }
     148            0 :         }
     149              : };
     150              : 
     151              : /// For
     152              : class LimexNonlinearCost : public ILimexCostStrategy
     153              : {
     154              : public:
     155            0 :         LimexNonlinearCost() :
     156            0 :         m_cAssemble (1.0), m_cMatAdd(0.0), m_cSolution(1.0), m_useGamma(1)
     157              :         {}
     158              : 
     159            0 :         void update_cost(std::vector<number> &m_costA, const std::vector<size_t> &nSteps, const size_t nstages)
     160              :         {
     161              :                 UG_ASSERT(m_costA.size() >= nstages, "Huhh: Vectors match in size:" << m_costA.size() << "vs." << nstages);
     162              : 
     163              :                 // 3 assemblies (M0, J0, Gamma0)
     164            0 :                 m_costA[0] = (2.0+m_useGamma)*m_cAssemble + nSteps[0]*((1.0+m_useGamma)*m_cMatAdd + m_cSolution);
     165            0 :                 for (size_t i=1; i<=nstages; ++i)
     166              :                 {
     167              :                         // n-1 assemblies for Mk, 2n MatAdds, n solutions
     168            0 :                         m_costA[i] = m_costA[i-1] + (nSteps[i]-1) * m_cAssemble + nSteps[i]*((1.0+m_useGamma)*m_cMatAdd + m_cSolution);
     169              :                 }
     170            0 :         }
     171              : 
     172              : protected:
     173              :         double m_cAssemble;  ///! Cost for matrix assembly
     174              :         double m_cMatAdd;        ///! Cost for J=A+B
     175              :         double m_cSolution;  ///! Cost for solving Jx=b
     176              : 
     177              :         int m_useGamma;
     178              : 
     179              : };
     180              : 
     181              : 
     182              : class LimexTimeIntegratorConfig
     183              : 
     184              : {
     185              : public:
     186              :         LimexTimeIntegratorConfig()
     187              :         : m_nstages(2),
     188              :           m_tol(0.01),
     189              :           m_rhoSafety(0.8),
     190              :           m_sigmaReduction(0.5),
     191              :           m_greedyOrderIncrease(2.0),
     192              :           m_max_reductions(2),
     193              :           m_asymptotic_order(1000),
     194              :           m_useCachedMatrices(false),
     195              :           m_conservative(0)
     196              :           {}
     197              : 
     198              :         LimexTimeIntegratorConfig(unsigned int nstages)
     199            0 :         : m_nstages(nstages),
     200            0 :           m_tol(0.01),
     201            0 :           m_rhoSafety(0.8),
     202            0 :           m_sigmaReduction(0.5),
     203            0 :           m_greedyOrderIncrease(2.0),
     204            0 :           m_max_reductions(2),
     205            0 :           m_asymptotic_order(1000),
     206            0 :           m_useCachedMatrices(false),
     207            0 :           m_conservative(0)
     208              :                 {}
     209              : 
     210              : 
     211              : protected:
     212              :         unsigned int m_nstages;                                 ///< Number of Aitken-Neville stages
     213              :         double m_tol;
     214              :         double m_rhoSafety;
     215              :         double m_sigmaReduction;
     216              : 
     217              :         double m_greedyOrderIncrease;
     218              : 
     219              :         size_t m_max_reductions;
     220              :         size_t m_asymptotic_order;                              ///< For PDEs, we may apply an symptotic order reduction
     221              : 
     222              :         bool m_useCachedMatrices;
     223              :         unsigned int m_conservative; // stepping back?
     224              : 
     225              : #ifdef UG_JSON
     226              :         NLOHMANN_DEFINE_TYPE_INTRUSIVE(LimexTimeIntegratorConfig,
     227              :                                         m_nstages, m_tol, m_rhoSafety,
     228              :                                         m_sigmaReduction, m_greedyOrderIncrease, m_max_reductions, m_asymptotic_order,
     229              :                                                 m_useCachedMatrices, m_conservative)
     230              : #endif
     231              : public:
     232              :         std::string config_string() const {
     233              :         #ifdef UG_JSON
     234              :                         try{
     235              :                                 nlohmann::json j(*this);
     236              :                                         //      to_json(j, *this);
     237              :                                 return j.dump();
     238              :                         } catch (...) {
     239              :                                 return std::string("EXCEPTION!!!");
     240              :                         }
     241              :         #else
     242            0 :                                         return std::string("LimexTimeIntegratorConfig::config_string()");
     243              :         #endif
     244              :                 }
     245              : 
     246              : };
     247              : 
     248              : //! Base class for LIMEX time integrator
     249              : template<class TDomain, class TAlgebra>
     250              : class LimexTimeIntegrator
     251              : : public INonlinearTimeIntegrator<TDomain, TAlgebra>,
     252              :   public DebugWritingObject<TAlgebra>,
     253              :   public LimexTimeIntegratorConfig // TODO: should become a 'has a'.
     254              : {
     255              : 
     256              : 
     257              : public:
     258              :                 typedef TAlgebra algebra_type;
     259              :                 typedef typename algebra_type::matrix_type matrix_type;
     260              :                 typedef typename algebra_type::vector_type vector_type;
     261              :                 typedef GridFunction<TDomain, TAlgebra> grid_function_type;
     262              :                 typedef INonlinearTimeIntegrator<TDomain, TAlgebra> base_type;
     263              :                 typedef typename base_type::solver_type solver_type;
     264              : 
     265              :                 typedef IDomainDiscretization<algebra_type>       domain_discretization_type;
     266              :                 typedef LinearImplicitEuler<algebra_type> timestep_type;
     267              :                 typedef AitkenNevilleTimex<vector_type> timex_type;
     268              :                 typedef INonlinearTimeIntegrator<TDomain, TAlgebra> itime_integrator_type;
     269              :                 typedef SimpleTimeIntegrator<TDomain, TAlgebra> time_integrator_type;
     270              :                 typedef ISubDiagErrorEst<vector_type> error_estim_type;
     271              : 
     272              :                 //! Contains all data for parallel execution of time steps
     273              :                 class ThreadData
     274              :                 {
     275              :                         //typedef boost::thread thread_type;
     276              :                 public:
     277              : 
     278            0 :                         ThreadData(SmartPtr<timestep_type> spTimeStep)
     279              :                         : m_stepper(spTimeStep)
     280              :                         {}
     281              : 
     282              :                         ThreadData(){}
     283              :                         SmartPtr<timestep_type> get_time_stepper()
     284              :                         { return m_stepper; }
     285              : 
     286              : 
     287              :                         void set_solver(SmartPtr<solver_type> solver)
     288            0 :                         { m_solver = solver;}
     289              : 
     290              :                         SmartPtr<solver_type> get_solver()
     291              :                         { return m_solver;}
     292              : 
     293              :                         void set_error(int e)
     294              :                         { m_error=e; }
     295              : 
     296              : 
     297              :                         void get_error()
     298              :                         { /*return m_error;*/ }
     299              : 
     300              : 
     301              :                         void set_solution(SmartPtr<grid_function_type> sol)
     302            0 :                         { m_sol = sol;}
     303              : 
     304              :                         SmartPtr<grid_function_type> get_solution()
     305              :                         { return m_sol;}
     306              : 
     307              :                         void set_derivative(SmartPtr<grid_function_type> sol)
     308            0 :                         { m_dot = sol;}
     309              : 
     310              :                         SmartPtr<grid_function_type> get_derivative()
     311              :                         { return m_dot;}
     312              : 
     313              :                 protected:
     314              :                          // includes time step series
     315              :                         SmartPtr<timestep_type> m_stepper;
     316              :                         SmartPtr<solver_type> m_solver;
     317              : 
     318              :                         SmartPtr<grid_function_type> m_sol;
     319              :                         SmartPtr<grid_function_type> m_dot;
     320              :                         int m_error;
     321              :                 };
     322              : 
     323              :                 typedef std::vector<SmartPtr<ThreadData> > thread_vector_type;
     324              : 
     325              : public:
     326              : 
     327              :         /// forward debug info to time integrators
     328            0 :         void set_debug_for_timestepper(SmartPtr<IDebugWriter<algebra_type> > spDebugWriter)
     329              :         {
     330            0 :                 for(size_t i=0; i<m_vThreadData.size(); ++i)
     331              :                 {
     332            0 :                                 m_vThreadData[i].get_time_stepper()->set_debug(spDebugWriter);
     333              :                 }
     334              :                 UG_LOG("set_debug:" << m_vThreadData.size());
     335            0 :         }
     336              : 
     337              :         //using VectorDebugWritingObject<vector_type>::set_debug;
     338              : protected:
     339              :         //using VectorDebugWritingObject<vector_type>::write_debug;
     340              : 
     341              : 
     342              : 
     343              : public:
     344            0 :                 LimexTimeIntegrator(int nstages):
     345              :                   LimexTimeIntegratorConfig(nstages),
     346            0 :                   m_gamma(m_nstages+1),
     347            0 :                   m_costA(m_nstages+1),
     348            0 :                   m_monitor(((m_nstages)*(m_nstages))), // TODO: wasting memory here!
     349            0 :                   m_workload(m_nstages),
     350            0 :                   m_lambda(m_nstages), 
     351            0 :                   m_num_reductions(m_nstages, 0),
     352            0 :                   m_consistency_error(m_nstages),
     353            0 :                   m_spCostStrategy(make_sp<LimexDefaultCost>(new LimexDefaultCost())),
     354            0 :                   m_spBanachSpace(new AlgebraicSpace<grid_function_type>()),              // default algebraic space
     355            0 :                   m_bInterrupt(false),
     356            0 :                   m_limex_step(1)
     357              :                 {
     358            0 :                         m_vThreadData.reserve(m_nstages);
     359            0 :                         m_vSteps.reserve(m_nstages);
     360              :                         init_gamma(); // init exponents (i.e. k+1, k, 2k+1, ...)
     361            0 :                 }
     362              : 
     363              : 
     364              : 
     365              :                 /// tolerance
     366            0 :                 void set_tolerance(double tol) { m_tol = tol;}
     367            0 :                 void set_stepsize_safety_factor(double rho) { m_rhoSafety = rho;}
     368            0 :                 void set_stepsize_reduction_factor(double sigma) { m_sigmaReduction = sigma;}
     369            0 :                 void set_stepsize_greedy_order_factor(double sigma) { m_greedyOrderIncrease = sigma;}
     370              : 
     371            0 :                 void set_max_reductions(size_t nred) { m_max_reductions = nred;}
     372            0 :                 void set_asymptotic_order(size_t q) { m_asymptotic_order = q;}
     373              : 
     374            0 :                 void set_start_step(size_t step){m_limex_step=step;}
     375              : 
     376              :                 /// add an error estimator
     377            0 :                 void add_error_estimator(SmartPtr<error_estim_type> spErrorEstim)
     378            0 :                 { m_spErrorEstimator = spErrorEstim; }
     379              : 
     380              :                 //! add a new stage (at end of list)
     381            0 :                 void add_stage_base(size_t nsteps, SmartPtr<solver_type> solver, SmartPtr<domain_discretization_type> spDD, SmartPtr<domain_discretization_type> spGamma=SPNULL)
     382              :                 {
     383              :                         UG_ASSERT(m_vThreadData.size() == m_vSteps.size(), "ERROR: m_vThreadData and m_vSteps differ in size!");
     384              : 
     385              :                         UG_ASSERT(m_vThreadData.empty() || m_vSteps.back()<nsteps, "ERROR: Sequence of steps must be increasing." );
     386              : 
     387              :                         // all entries have been set
     388            0 :                         if (m_vThreadData.size() == m_nstages)
     389            0 :                         { return; }
     390              : 
     391              : 
     392              :                         // a) set number of steps
     393            0 :                         m_vSteps.push_back(nsteps);
     394              : 
     395              :                         // b) set time-stepper
     396              :                         SmartPtr<timestep_type> limexStepSingleton;
     397              : #ifndef LIMEX_MULTI_THREAD
     398              : 
     399            0 :                         if(m_vThreadData.size()>0) {
     400              :                                 // re-use time-stepper (if applicable)
     401            0 :                                 limexStepSingleton = m_vThreadData.back().get_time_stepper();
     402              :                         }
     403              :                         else
     404              :                         {
     405              :                                 // create time-stepper
     406              : #endif
     407              :                                 // for mult-threading, each info object has own time-stepper
     408            0 :                                 if (spGamma.invalid()) {
     409            0 :                                         limexStepSingleton = make_sp(new timestep_type(spDD));
     410              :                                 } else {
     411            0 :                                         limexStepSingleton = make_sp(new timestep_type(spDD, spDD, spGamma));
     412              :                                 }
     413              :                                 UG_ASSERT(limexStepSingleton.valid(), "Huhh: Invalid pointer")
     414              : #ifndef LIMEX_MULTI_THREAD
     415              :                         }
     416              : #endif
     417              :                         // propagate debug info
     418            0 :                         limexStepSingleton->set_debug(VectorDebugWritingObject<vector_type>::vector_debug_writer());
     419            0 :                         m_vThreadData.push_back(ThreadData(limexStepSingleton));
     420              : 
     421              :                         // c) set solver
     422              :                         UG_ASSERT(solver.valid(), "Huhh: Need to supply solver!");
     423            0 :                         m_vThreadData.back().set_solver(solver);
     424              :                         UG_ASSERT(m_vThreadData.back().get_solver().valid(), "Huhh: Need to supply solver!");
     425              :                 }
     426              : 
     427            0 :                 void add_stage(size_t nsteps, SmartPtr<solver_type> solver, SmartPtr<domain_discretization_type> spDD)
     428            0 :                 { add_stage_base(nsteps, solver, spDD); }
     429              : 
     430            0 :                 void add_stage_ext(size_t nsteps, SmartPtr<solver_type> solver, SmartPtr<domain_discretization_type> spDD, SmartPtr<domain_discretization_type> spGamma)
     431            0 :                 { add_stage_base(nsteps, solver, spDD, spGamma); }
     432              : 
     433              :                 ///! TODO: remove this function!
     434            0 :                 void add_stage(size_t i, size_t nsteps, SmartPtr<domain_discretization_type> spDD, SmartPtr<solver_type> solver)
     435              :                 {
     436              :                         UG_LOG("WARNING: add_stage(i, nsteps ,...) is deprecated. Please use 'add_stage(nsteps ,...) instead!'");
     437            0 :                         add_stage(nsteps, solver, spDD);
     438            0 :                 }
     439              : 
     440              :                 //!
     441              :                 SmartPtr<timestep_type> get_time_stepper(size_t i)
     442              :                 {
     443              :                         UG_ASSERT(i<m_vThreadData.size(), "Huhh: Invalid entry");
     444              :                         return m_vThreadData[i].get_time_stepper();
     445              :                 }
     446              : 
     447              : 
     448              : 
     449              : 
     450              : protected:
     451              :                 //! Initialize integrator threads (w/ solutions)
     452              :                 void init_integrator_threads(ConstSmartPtr<grid_function_type> u);
     453              : 
     454              :                 //! (Tentatively) apply integrators
     455              :                 int apply_integrator_threads(number dtcurr, ConstSmartPtr<grid_function_type> u0, number t0, size_t nstages);
     456              : 
     457              :                 //! e.g. wait for all threads to complete
     458              :                 void join_integrator_threads();
     459              : 
     460              :                 //! Override thread-wise solutions with common solution
     461              :                 void update_integrator_threads(ConstSmartPtr<grid_function_type> ucommon, number t);
     462              : 
     463              :                 //! Dispose integrator threads (w/ solutions)
     464              :                 void dispose_integrator_threads();
     465              : 
     466              : public:
     467              :                 //! Integrating from t0 -> t1
     468              :                 bool apply(SmartPtr<grid_function_type> u, number t1, ConstSmartPtr<grid_function_type> u0, number t0);
     469              : 
     470              :                 number  get_cost(size_t i) { return m_costA[i]; }
     471              :                 number  get_gamma(size_t i) { return m_gamma[i]; }
     472              :                 number  get_workload(size_t i) { return m_workload[i]; }
     473              : 
     474              : 
     475              : protected:
     476              :                 number& monitor(size_t k, size_t q) {
     477              :                   UG_ASSERT(k<m_nstages, "Huhh: k mismatch");
     478              :                   UG_ASSERT(q<m_nstages, "Huhh: q mismatch");
     479            0 :                   return m_monitor[k+(m_nstages)*q]; 
     480              :                 }
     481              : 
     482              :                 /// aux: compute exponents gamma_k (for roots)
     483              :                 void init_gamma()
     484              :                 {
     485            0 :                         for (size_t k=0; k<=m_nstages; ++k)
     486              :                         {
     487            0 :                                 m_gamma[k] = 2.0+k;
     488              :                         }
     489              :                 }
     490              : 
     491              :                 /// Updating workloads A_i for computing T_ii
     492              :                 //  (depends on m_vSteps, which must have been initialized!)
     493              :                 void update_cost()
     494              :                 {
     495            0 :                         m_spCostStrategy->update_cost(m_costA, m_vSteps, m_nstages);
     496              :                 }
     497              : 
     498              :                 /// convergence monitor
     499              :                 // (depends on cost, which must have been initialized!)
     500            0 :                 void update_monitor()
     501              :                 {
     502              :                   UG_ASSERT(m_costA.size()>= m_nstages, "Cost vector too small!")
     503            0 :                   for (size_t k=0; k<m_nstages-1; ++k)
     504              :                   {
     505            0 :                     UG_LOG("k= "<< k<< ", A[k]=" << m_costA[k] << ", gamma[k]=" << m_gamma[k] << "\t");
     506            0 :                     for (size_t q=0; q<m_nstages-1; ++q)
     507              :                       {
     508              :                         // Deuflhard: Order and stepsize, ... eq. (3.7)
     509            0 :                         double gamma = (m_costA[k+1] - m_costA[0] + 1.0)/(m_costA[q+1] - m_costA[0] + 1.0);
     510            0 :                         double alpha = pow(m_tol, gamma);
     511              :                         
     512              :                         // for fixed order q, the monitor indicates the performance penalty compared to a strategy using k stages only
     513              :                         // cf. eq. (4.6)
     514            0 :                         monitor(k,q) = pow(alpha/(m_tol * m_rhoSafety), 1.0/m_gamma[k]);
     515            0 :                         UG_LOG(monitor(k,q) << "[" << pow(alpha/(m_tol), 1.0/m_gamma[k]) <<"," << gamma<< ","<< m_costA[k+1] << "," << m_costA[q+1]<< ","<< alpha << "]" << "\t");
     516              :                         // UG_LOG(  << "\t");
     517              :                         
     518              :                       }
     519              :                     UG_LOG(std::endl);
     520              :                   }
     521              : 
     522            0 :                 }
     523              : 
     524              :                 // Find row k=1, ..., ntest-1 minimizing (estimated) error eps[kmin]
     525              :                 // Also: predict column q with minimal workload W_{k+1,k} = A_{k+1} * lambda_{k+1}
     526              :                 size_t find_optimal_solution(const std::vector<number>& eps, size_t ntest, /*size_t &kf,*/ size_t &qpred);
     527              : 
     528              : public:
     529              :                 /// setter for time derivative info (optional for setting $\Gamma$)
     530            0 :                 void set_time_derivative(SmartPtr<grid_function_type> udot) {m_spDtSol = udot;}
     531              : 
     532              :                 /// getter for time derivative info (optional for setting $\Gamma$)
     533            0 :                 SmartPtr<grid_function_type> get_time_derivative() {return m_spDtSol;}
     534              : 
     535              :                 /// status for time derivative info (optional for setting $\Gamma$)
     536            0 :                 bool has_time_derivative() {return m_spDtSol!=SPNULL;}
     537              : 
     538              : 
     539            0 :                 void enable_matrix_cache() { m_useCachedMatrices = true; }      ///< Select classic LIMEX
     540            0 :                 void disable_matrix_cache() { m_useCachedMatrices = false; }    ///< Select approximate Newton (default)
     541              : 
     542            0 :                 void select_cost_strategy(SmartPtr<ILimexCostStrategy> cost)
     543            0 :                 { m_spCostStrategy = cost;}
     544              : 
     545              : 
     546              :                 /// set banach space (e.g. for computing consistency error)
     547            0 :                 void set_space(SmartPtr<IGridFunctionSpace<grid_function_type> > spSpace)
     548              :                 { 
     549            0 :                   m_spBanachSpace = spSpace;
     550            0 :                   UG_LOG("set_space:" << m_spBanachSpace->config_string()); 
     551            0 :                 }
     552              : 
     553              :                 /// interrupt execution of apply() by external call via observer
     554            0 :                 void interrupt() {m_bInterrupt = true;}
     555              : 
     556            0 :                 void set_conservative(bool c)
     557            0 :                 { m_conservative = (c) ? 1 : 0; }
     558              : 
     559            0 :                 std::string config_string() const
     560            0 :                 { return LimexTimeIntegratorConfig::config_string(); }
     561              : 
     562              : protected:
     563              : 
     564              :                 SmartPtr<error_estim_type> m_spErrorEstimator;     // (smart ptr for) error estimator
     565              : 
     566              :                 std::vector<size_t> m_vSteps;                     ///< generating sequence for extrapolation
     567              :                 std::vector<ThreadData> m_vThreadData;    ///< vector with thread information
     568              : 
     569              :                 std::vector<number> m_gamma;                      ///< gamma_i: exponent
     570              : 
     571              :                 std::vector<number> m_costA;                      ///< Cost A_i (for completing stage i)
     572              :                 std::vector<number> m_monitor;                    ///< Convergence monitor \alpha
     573              : 
     574              :                 std::vector<number> m_workload;
     575              :                 std::vector<number> m_lambda;
     576              : 
     577              :                 std::vector<size_t> m_num_reductions;             ///< history of reductions
     578              : 
     579              :                 std::vector<number> m_consistency_error;  ///<Consistency error
     580              : 
     581              :                 SmartPtr<grid_function_type> m_spDtSol;           ///< Time derivative
     582              : 
     583              :                 SmartPtr<ILimexCostStrategy> m_spCostStrategy;
     584              : 
     585              :                 /// metric space
     586              :                 SmartPtr<IGridFunctionSpace<grid_function_type> > m_spBanachSpace;
     587              : 
     588              :                 bool m_bInterrupt;
     589              :                 int m_limex_step;                                               ///<Current counter
     590              : 
     591              : 
     592              : };
     593              : 
     594              : 
     595              : /*! Create private solutions for each thread */
     596              : template<class TDomain, class TAlgebra>
     597            0 : void LimexTimeIntegrator<TDomain,TAlgebra>::init_integrator_threads(ConstSmartPtr<grid_function_type> u)
     598              : {
     599              :         PROFILE_FUNC_GROUP("limex");
     600            0 :         const int nstages = m_vThreadData.size()-1;
     601            0 :         for (int i=nstages; i>=0; --i)
     602              :         {
     603            0 :                 m_vThreadData[i].set_solution(u->clone());
     604            0 :                 m_vThreadData[i].set_derivative(u->clone());
     605            0 :                 m_vThreadData[i].get_time_stepper()->set_matrix_cache(m_useCachedMatrices);
     606              :         }
     607            0 : }
     608              : 
     609              : /*! Create private solutions for each thread */
     610              : template<class TDomain, class TAlgebra>
     611            0 : void LimexTimeIntegrator<TDomain,TAlgebra>::dispose_integrator_threads()
     612              : {
     613              :         PROFILE_FUNC_GROUP("limex");
     614            0 :         const int nstages = m_vThreadData.size()-1;
     615            0 :         for (int i=nstages; i>=0; --i)
     616              :         {
     617            0 :                 m_vThreadData[i].set_solution(SPNULL);
     618            0 :                 m_vThreadData[i].set_derivative(SPNULL);
     619              :                 // m_vThreadData[i].get_time_stepper()->set_matrix_cache(m_useCachedMatrices);
     620              :         }
     621            0 : }
     622              : 
     623              : 
     624              : // create (& execute) threads
     625              : /*boost::thread_group g;
     626              :                 typename thread_vector_type::reverse_iterator rit=m_vThreadData.rbegin();
     627              :                 for (rit++; rit!= m_vThreadData.rend(); ++rit)
     628              :                 {
     629              : 
     630              :                         boost::thread *t =new boost::thread(boost::bind(&ThreadSafeTimeIntegrator::apply, *rit));
     631              :                         //g.add_thread(t);
     632              : 
     633              :                         g.create_thread(boost::bind(&ThreadSafeTimeIntegrator::apply, *rit));
     634              : 
     635              :                 }*/
     636              : 
     637              : 
     638              : /* TODO: PARALLEL execution?*/
     639              : template<class TDomain, class TAlgebra>
     640            0 : int LimexTimeIntegrator<TDomain,TAlgebra>::apply_integrator_threads(number dtcurr, ConstSmartPtr<grid_function_type> u0, number t0, size_t nstages)
     641              : {
     642              :         PROFILE_FUNC_GROUP("limex");
     643              :         update_cost();          // compute cost A_i (alternative: measure times?)
     644            0 :         update_monitor();       // convergence monitor
     645              : 
     646              :         /*
     647              :                         int tn = omp_get_thread_num();
     648              :                         int nt = omp_get_num_threads();
     649              :                         omp_set_num_threads(nstages);
     650              :          */
     651              :         int error = 0;
     652              :         //const int nstages = m_vThreadData.size()-1;
     653              :         //      #pragma omp for private(i) // shared (nstages, u1) schedule(static)
     654            0 :         for (int i=0; i<=(int)nstages; ++i)
     655              :         {
     656              :                 /*
     657              :                                 std::cerr << "I am " << tn << " of " << nt << " ("<< i<< "/" << nstages<<")!" << std::endl;
     658              :                                 UGMultiThreadEnvironment mt_env;
     659              :                  */
     660              : 
     661              :                 // copy data to private structure (one-to-many)
     662              :                 //m_vThreadData[i].set_solution(u1->clone());
     663              : 
     664              :                 // switch to "child" comm
     665              :                 // mt_env.begin();
     666              : 
     667              :                 // integrate (t0, t0+dtcurr)
     668            0 :                 time_integrator_type integrator(m_vThreadData[i].get_time_stepper());
     669            0 :                 integrator.set_time_step(dtcurr/m_vSteps[i]);
     670              :                 integrator.set_dt_min(dtcurr/m_vSteps[i]);
     671              :                 integrator.set_dt_max(dtcurr/m_vSteps[i]);
     672              :                 integrator.set_reduction_factor(0.0);                 // quit immediately, if step fails
     673            0 :                 integrator.set_solver(m_vThreadData[i].get_solver());
     674            0 :                 integrator.set_derivative(m_vThreadData[i].get_derivative());
     675              :                 
     676            0 :                 if(this->debug_writer_valid())
     677              :                 {
     678            0 :                         integrator.set_debug(this->debug_writer());
     679              :                         char debug_name_ext[16]; snprintf(debug_name_ext, 16, "%04d", i);
     680            0 :                         this->enter_debug_writer_section(std::string("Stage_") + debug_name_ext);
     681              :                 }
     682              : 
     683              :                 UG_ASSERT(m_spBanachSpace.valid(), "Huhh: Need valid (default) banach space");
     684            0 :                 integrator.set_banach_space(m_spBanachSpace);
     685            0 :                 UG_LOG("Set space:" << m_spBanachSpace->config_string());
     686              : 
     687              :                 bool exec = true;
     688              :                 try
     689              :                 {
     690            0 :                         exec = integrator.apply(m_vThreadData[i].get_solution(), t0+dtcurr, u0, t0);
     691            0 :                         m_consistency_error[i] = integrator.get_consistency_error();
     692              :                 }
     693            0 :                 catch(ug::UGError& err)
     694              :                 {
     695              : 
     696              :                         exec = false;
     697            0 :                         error += (1 << i);
     698            0 :                         UG_LOGN("Step "<< i<< " failed on stage " << i << ": " << err.get_msg());
     699            0 :                         MyPrintError(err);
     700              : 
     701              :                 }
     702              :                 
     703            0 :                 this->leave_debug_writer_section();
     704              : 
     705            0 :                 if (!exec)
     706              :                 {
     707              :                         // Additional actions at failure
     708            0 :                         UG_LOGN("Step "<< i<< " failed on stage " << i << ": reason not clear!" );
     709              :                 }
     710              : 
     711              :                 // switch to "parent" comm
     712              :                 //mt_env.end();
     713              :         } /*for all stages loop*/
     714              : 
     715              : 
     716              : 
     717            0 :         return error;
     718              : }
     719              : 
     720              : 
     721              : template<class TDomain, class TAlgebra>
     722            0 : void LimexTimeIntegrator<TDomain,TAlgebra>::join_integrator_threads()
     723              : {
     724              :         // join all threads
     725              :         // g.join_all();
     726            0 :         const int nstages = m_vThreadData.size()-1;
     727            0 :         for (int i=nstages; i>=0; --i)
     728              :         {
     729            0 :                 m_vThreadData[i].get_time_stepper()->invalidate();
     730              :         }
     731            0 : }
     732              : 
     733              : 
     734              : template<class TDomain, class TAlgebra>
     735            0 : void LimexTimeIntegrator<TDomain,TAlgebra>::update_integrator_threads(ConstSmartPtr<grid_function_type> ucommon, number t)
     736              : {
     737            0 :         const int nstages = m_vThreadData.size()-1;
     738            0 :         for (int i=nstages; i>=0; --i)
     739              :         {
     740              :                 UG_ASSERT(m_vThreadData[i].get_solution()->size()==ucommon->size(), "LIMEX: Vectors must match in size!")
     741            0 :                 *m_vThreadData[i].get_solution() = *ucommon;
     742              :         }
     743            0 : }
     744              : 
     745              : template<class TDomain, class TAlgebra>
     746            0 : size_t LimexTimeIntegrator<TDomain,TAlgebra>::
     747              : find_optimal_solution(const std::vector<number>& eps, size_t ntest, /*size_t &kf,*/ size_t &qpred)
     748              : {
     749              : 
     750            0 :         const size_t qold=qpred;
     751              : 
     752              :         size_t jbest = 1;
     753            0 :         qpred = 1;
     754              : 
     755              :         size_t j=1;
     756              :         size_t k=j-1;
     757              : 
     758            0 :         m_lambda[k] = pow(m_rhoSafety*m_tol/eps[j], 1.0/m_gamma[k]);   // 1/epsilon(k)
     759            0 :         m_workload[k] = m_costA[j]/m_lambda[k];
     760            0 :         UG_LOG("j=" << j << ": eps=" << eps[j]  << ", lambda(j)=" <<m_lambda[k]  << ", epsilon(j)=" <<1.0/m_lambda[k] << "<= alpha(k, qcurr)=" << monitor(k,qold-1) << "< alpha(k, qcurr+1)=" << monitor(k,qold) <<", A="<< m_costA[j] << ", W="<< m_workload[k] <<std::endl);
     761              : 
     762            0 :         for (j=2; j<ntest; ++j)
     763              :         {
     764            0 :           k = j-1;
     765            0 :           m_lambda[k] = pow(m_rhoSafety*m_tol/eps[j], 1.0/m_gamma[k]);
     766            0 :           m_workload[k] = m_costA[j]/m_lambda[k];
     767            0 :           UG_LOG("j=" << j << ": eps=" << eps[j]  << ", lambda(j)=" <<m_lambda[k]  << ", epsilon(j)=" <<1.0/m_lambda[k] << "<= alpha(k, qcurr)=" << monitor(k,qold-1) << "< alpha(k, qcurr+1)=" << monitor(k,qold) <<", A="<< m_costA[j] << ", W="<< m_workload[k] <<std::endl);
     768              : 
     769              : 
     770              :           // TODO: Convergence monitor
     771              : 
     772            0 :           qpred = (m_workload[qpred-1] > m_workload[k]) ? j : qpred;
     773            0 :           jbest = (eps[jbest] > eps [j]) ? j : jbest;
     774              :         }
     775              : 
     776            0 :         return jbest;
     777              : }
     778              : 
     779              : template<class TDomain, class TAlgebra>
     780            0 : bool LimexTimeIntegrator<TDomain,TAlgebra>::
     781              : apply(SmartPtr<grid_function_type> u, number t1, ConstSmartPtr<grid_function_type> u0, number t0)
     782              : {
     783              :         PROFILE_FUNC_GROUP("limex");
     784              : #ifdef UG_OPENMP
     785              :         // create multi-threading environment
     786              :         //int nt = std::min(omp_get_max_threads(), m_nstages);
     787              : 
     788              : #endif
     789              : 
     790              :         // NOTE: we use u as common storage for future (and intermediate) solution(s)
     791            0 :         if (u.get() != u0.get())    // only copy if not already identical, otherwise: PST_UNDEFINED!
     792            0 :                 *u = *u0;
     793              : 
     794              :         // initialize integrator threads
     795              :         // (w/ solutions)
     796            0 :         init_integrator_threads(u0);
     797              : 
     798              : 
     799              :         // write_debug
     800            0 :         for (unsigned int i=0; i<m_vThreadData.size(); ++i)
     801              :         {
     802            0 :                 std::ostringstream ossName;
     803              :                 ossName << std::setfill('0') << std::setw(4);
     804            0 :                 ossName << "Limex_Init_iter" << 0 << "_stage" << i;
     805            0 :                 this->write_debug(*m_vThreadData[i].get_solution(), ossName.str().c_str());
     806              :         }
     807              : 
     808              :         number t = t0;
     809            0 :         double dtcurr = ITimeIntegrator<TDomain, TAlgebra>::get_time_step();
     810              : 
     811            0 :         size_t kmax = m_vThreadData.size();             // maximum number of stages
     812            0 :         size_t qpred = kmax-1;                                                          // predicted optimal order
     813              :         size_t qcurr = qpred;                                                           // current order
     814              : 
     815              :         // for Gustafsson/lundh/Soederlind type PID controller
     816              :         /*size_t qlast = 0;
     817              :         double dtlast = 0.0;
     818              :         std::vector<double> epslast(kmax, m_rhoSafety*m_tol);
     819              : */
     820              : 
     821              :         // time integration loop
     822              :         SmartPtr<grid_function_type> ubest = SPNULL;
     823              :         size_t limex_total = 1;
     824              :         size_t limex_success = 0;
     825              :         size_t ntest;    ///< active number of stages <= kmax
     826              :         size_t jbest;
     827              : 
     828            0 :         m_bInterrupt = false;
     829              :         //bool bProbation = false;
     830              :         bool bAsymptoticReduction = false;
     831              : 
     832              :         const size_t nSwitchHistory=16;
     833              :         const size_t nSwitchLookBack=5;
     834            0 :         int vSwitchHistory[nSwitchHistory] ={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
     835              : 
     836            0 :         timex_type timex(m_vSteps);
     837            0 :         while ((t < t1) && ((t1-t) > base_type::m_precisionBound))
     838              :         {
     839              :                 int err = 0;
     840              : 
     841              :                 //UG_DLOG(LIB_LIMEX, 5, "+++ LimexTimestep +++" << limex_step << "\n");
     842            0 :                 UG_LOG("+++ LimexTimestep +++" << m_limex_step << "\n");
     843              : 
     844              : 
     845              :                 // save time stamp for limex step start
     846              :                 Stopwatch stopwatch;
     847              :                 stopwatch.start();
     848              : 
     849              : 
     850              :                 // determine step size
     851            0 :                 number dt = std::min(dtcurr, t1-t);
     852            0 :                 UG_COND_THROW(dt < base_type::get_dt_min(), "Time step size below minimum. ABORTING! dt=" << dt << "; dt_min=" << base_type::get_dt_min() << "\n");
     853              : 
     854              : 
     855              :                 // Notify init observers. (NOTE: u = u(t))¸
     856            0 :                 itime_integrator_type::notify_init_step(u, m_limex_step, t, dt);
     857              : 
     858              : 
     859              :                 // determine number of stages to investigate
     860            0 :                 qcurr = qpred;
     861            0 :                 ntest = std::min(kmax, qcurr+1);
     862              :                 UG_LOG("ntest="<< ntest << std::endl);
     863              : 
     864              :                 // checks
     865              :                 UG_ASSERT(m_vSteps.size() >= ntest, "Huhh: sizes do not match: " << m_vSteps.size() << "<"<<ntest);
     866              :                 UG_ASSERT(m_vThreadData.size() >= ntest, "Huhh: sizes do not match: " << m_vThreadData.size() << "< "<< ntest);
     867              : 
     868              :                 ///////////////////////////////////////
     869              :                 // PARALLEL EXECUTION: BEGIN
     870              : 
     871              :                 // write_debug
     872            0 :                 for (size_t i=0; i<ntest; ++i)
     873              :                 {
     874            0 :                         std::ostringstream ossName;
     875              :                         ossName << std::setfill('0') << std::setw(4);
     876            0 :                         ossName << "Limex_BeforeSerial_iter" << m_limex_step << "_stage" << i << "_total" << limex_total;
     877            0 :                         this->write_debug(*m_vThreadData[i].get_solution(), ossName.str().c_str());
     878              :                 }
     879            0 :                 if(this->debug_writer_valid())
     880              :                 {
     881            0 :                         char debug_step_id_ext[16]; snprintf(debug_step_id_ext, 16, "%04d", m_limex_step);
     882            0 :                         char debug_total_id_ext[16]; snprintf(debug_total_id_ext, 16, "%04d", (int) limex_total);
     883            0 :                         this->enter_debug_writer_section(std::string("LimexTimeIntegrator_iter") + debug_step_id_ext + "_total" + debug_total_id_ext);
     884              :                 }
     885              : 
     886              :                 // integrate: t -> t+dt
     887            0 :                 err = apply_integrator_threads(dt, u, t, ntest-1);
     888              :                 
     889            0 :                 this->leave_debug_writer_section();
     890              : 
     891              :                 // write_debug
     892            0 :                 for (size_t i=0; i<ntest; ++i)
     893              :                 {
     894            0 :                         std::ostringstream ossName;
     895              :                         ossName << std::setfill('0') << std::setw(4);
     896            0 :                         ossName << "Limex_AfterSerial_iter" << m_limex_step << "_stage" << i << "_total" << limex_total;
     897            0 :                         this->write_debug(*m_vThreadData[i].get_solution(), ossName.str().c_str());
     898              :                 }
     899              : 
     900            0 :                 join_integrator_threads();
     901              :                 // PARALLEL EXECUTION: END
     902              :                 ///////////////////////////////////////
     903              : 
     904              : 
     905              :                 ///////////////////////////////////////
     906              :                 // SERIAL EXECUTION: BEGIN
     907              : 
     908              :                 // sanity checks
     909              :                 UG_ASSERT(m_spErrorEstimator.valid(), "Huhh: Invalid Error estimator?");
     910              : 
     911              :                 double epsmin = 0.0;
     912              : 
     913              :                 bool limexConverged = false;
     914            0 :                 if (err==0)
     915              :                 {       // Compute extrapolation at t+dtcurr (SERIAL)
     916              :                         // Consistency check.
     917            0 :                         for (unsigned int i=1; i<ntest; ++i)
     918              :                         {
     919            0 :                                 UG_LOG("Checking consistency:" <<m_consistency_error[i] <<"/" << m_consistency_error[i-1] << "="<< m_consistency_error[i]/m_consistency_error[i-1] << std::endl);
     920              :                         }
     921              : 
     922              :                         // Extrapolation.
     923            0 :                         timex.set_error_estimate(m_spErrorEstimator);
     924            0 :                         for (unsigned int i=0; i<ntest; ++i)
     925              :                         {
     926              :                                 UG_ASSERT(m_vThreadData[i].get_solution().valid(), "Huhh: no valid solution?");
     927            0 :                                 timex.set_solution(m_vThreadData[i].get_solution(), i);
     928              :                         }
     929            0 :                         timex.apply(ntest);
     930              : 
     931              :                         // write_debug
     932            0 :                         for (size_t i=0; i<ntest; ++i)
     933              :                         {
     934            0 :                                 std::ostringstream ossName;
     935              :                                 ossName << std::setfill('0') << std::setw(4);
     936            0 :                                 ossName << "Limex_Extrapolates_iter" << m_limex_step << "_stage" << i << "_total" << limex_total;
     937            0 :                                 this->write_debug(*m_vThreadData[i].get_solution(), ossName.str().c_str());
     938              :                         }
     939            0 :                         limex_total++;
     940              : 
     941              :                         // Obtain sub-diagonal error estimates.
     942              :                         const std::vector<number>& eps = timex.get_error_estimates();
     943              :                         UG_ASSERT(ntest<=eps.size(), "Huhh: Not enough solutions?");
     944              : 
     945              :                         // select optimal solution (w.r.t error) AND
     946              :                         // predict optimal order (w.r.t. workload) for next step
     947            0 :                         jbest = find_optimal_solution(eps, ntest, qpred);
     948              :                         UG_ASSERT(jbest < ntest, "Huhh: Not enough solutions?");
     949              : 
     950              :                         // best solution
     951            0 :                         ubest  = timex.get_solution(jbest-m_conservative).template cast_dynamic<grid_function_type>();
     952            0 :                         epsmin = eps[jbest];
     953              : 
     954              :                         // check for convergence
     955            0 :                         limexConverged = (epsmin <= m_tol) ;
     956              : 
     957              : 
     958            0 :                         if (limex_success>3)
     959              :                         {
     960              : 
     961            0 :                                 vSwitchHistory[m_limex_step%nSwitchHistory] = (qpred - qcurr);
     962              :                                 UG_DLOG(LIB_LIMEX, 5, "LIMEX-ASYMPTOTIC-ORDER switch:  = " <<  (qpred - qcurr)<< std::endl);
     963              : 
     964              :                                 size_t nSwitches=0;
     965            0 :                                 for (int s=nSwitchLookBack-1; s>=0; s--)
     966              :                                 {
     967            0 :                                         nSwitches += std::abs(vSwitchHistory[(m_limex_step-s)%nSwitchHistory]);
     968              :                                         UG_DLOG(LIB_LIMEX, 6, "LIMEX-ASYMPTOTIC-ORDER: s[" << s<< "] = " <<  vSwitchHistory[(m_limex_step-s)%nSwitchHistory] << std::endl);
     969              :                                 }
     970              :                                 UG_DLOG(LIB_LIMEX, 5,"LIMEX-ASYMPTOTIC-ORDER: nSwitches = " <<  nSwitches << std::endl);
     971              : 
     972              : 
     973              :                         /*
     974              :                         if (bProbation)
     975              :                         {
     976              : 
     977              :                                 if ((qpred < qcurr)  || (!limexConverged))   // consecutive (follow-up) order decrease
     978              :                                 {
     979              :                                         bProbation = true;
     980              :                                         m_num_reductions[0]++;
     981              :                                         UG_LOG("LIMEX-ASYMPTOTIC-ORDER: Decrease on parole detected: "<< qcurr << " -> " << qpred << "("<< m_num_reductions[0]<<")"<<std::endl);
     982              : 
     983              :                                 }
     984              :                                 else
     985              :                                 {
     986              :                                         // reset all counters
     987              :                                         bProbation = false;
     988              :                                         UG_LOG("LIMEX-ASYMPTOTIC-ORDER: Probation off!"<<std::endl);
     989              : 
     990              :                                 }
     991              :                         }
     992              :                         else
     993              :                         {
     994              :                                 if ((qpred < qcurr)  || (!limexConverged))// 1st order decrease
     995              :                                 {
     996              :                                         bProbation = true;
     997              :                                         m_num_reductions[0]++;
     998              :                                         UG_LOG("LIMEX-ASYMPTOTIC-ORDER:  Decrease detected: "<< qcurr << " -> " << qpred << "("<< m_num_reductions[0]<<")"<<std::endl);
     999              :                                 }
    1000              :                                 else
    1001              :                                 {
    1002              :                                         m_num_reductions[0] = 0;
    1003              :                                         UG_LOG("LIMEX-ASYMPTOTIC-ORDER: I am totally free!"<<std::endl);
    1004              :                                 }
    1005              : 
    1006              : 
    1007              :                         }
    1008              : */
    1009              : 
    1010              :                         // bAsymptoticReduction = (m_num_reductions[0] >= m_max_reductions) || bAsymptoticReduction;
    1011              : 
    1012              :                         // bAsymptoticReduction = (nSwitches >= m_max_reductions) || bAsymptoticReduction;
    1013              : 
    1014            0 :                         if (nSwitches >= m_max_reductions) {
    1015              : 
    1016              : 
    1017            0 :                                 m_asymptotic_order = std::min<size_t>(m_asymptotic_order-1, 2);
    1018              :                                 bAsymptoticReduction = true;
    1019              : 
    1020            0 :                                 for (int s=nSwitchLookBack-1; s>=0; s--)
    1021            0 :                                 { vSwitchHistory[(m_limex_step-s)%nSwitchHistory]=0; }
    1022              : 
    1023              : 
    1024              :                         }
    1025              : 
    1026              : 
    1027              : 
    1028              :                         // asymptotic order reduction
    1029              :                         //if (m_num_reductions[0] >= m_max_reductions)
    1030            0 :                         if      (bAsymptoticReduction)
    1031              :                         {
    1032            0 :                                 kmax = (kmax >= m_asymptotic_order ) ? m_asymptotic_order : kmax;
    1033            0 :                                 qpred = kmax - 1;
    1034              :                                 UG_DLOG(LIB_LIMEX, 5, "LIMEX-ASYMPTOTIC-ORDER: Reduction: "<< qpred );
    1035              :                                 UG_DLOG(LIB_LIMEX, 5, "(kmax=" << kmax << ", asymptotic"<<  m_asymptotic_order <<") after "<<m_max_reductions<< std::endl);
    1036              :                         }
    1037              : 
    1038              :                         } // (limex_success>3)
    1039              : 
    1040              :                         /*
    1041              :                         // adjust for order bound history
    1042              :                         if ((m_num_reductions[qpred] > m_max_reductions) && (qpred > 1))
    1043              :                         {
    1044              :                                         UG_LOG("prohibited  q:"<< qpred << "(" << m_num_reductions[qpred] << ")"<<std::endl);
    1045              :                                         //qpred--;
    1046              :                                         qpred = kmax = 2;
    1047              :                         } else
    1048              :                         {
    1049              :                                 UG_LOG("keeping  q:"<< qpred << "(" << m_num_reductions[qpred] << ")"<<std::endl);
    1050              :                         }
    1051              :                         */
    1052              : 
    1053              :                         //double pid = 1.0;
    1054              : 
    1055              :                         // constant order?
    1056              :                         /*if (qcurr == qlast)
    1057              :                         {
    1058              :                                 double dtRatio =dtcurr/dtlast;
    1059              :                                 // Dd, Band 3 (DE), p. 360
    1060              :                                 int k = ntest-1;
    1061              :                                 while (k--) {
    1062              :                                         double epsRatio =eps[k+1]/epslast[k+1];
    1063              : 
    1064              :                                         double qopt = log(epsRatio) / log(dtRatio);  // take dtcurr here, as dt may be smaller
    1065              : 
    1066              :                                         UG_LOG("effective p["<< k << "]="<< qopt-1.0 <<","<< eps[k+1] <<","<< epslast[k+1] <<","  <<  epsRatio << "("<<  log(epsRatio)  << ","<<  pow(epsRatio, 1.0/m_gamma[k])  <<")"<< dtcurr <<","<< dtlast   << "," << dtRatio << "," <<log(dtRatio) << std::endl);
    1067              :                                 }
    1068              : 
    1069              : 
    1070              :                                 double epsRatio = eps[qcurr]/epslast[qcurr];
    1071              :                                 pid = dtRatio/pow(epsRatio, 1.0/m_gamma[qcurr-1]);
    1072              : 
    1073              :                                 UG_LOG("pid=" << pid << std::endl);
    1074              : 
    1075              :                         }*/
    1076              : 
    1077              : 
    1078              :                         // select (predicted) order for next step//double dtpred = dtcurr*std::min(m_lambda[qpred-1], itime_integrator_type::get_increase_factor());
    1079            0 :                         double dtpred = dtcurr*std::min(m_lambda[qpred-1], itime_integrator_type::get_increase_factor());
    1080              :                         //double dtpred = dtcurr*m_lambda[qpred-1];
    1081              :                         UG_LOG("+++++\nget_increase_factor() gives "<<itime_integrator_type::get_increase_factor()<<" \n+++++++")
    1082            0 :                         UG_LOG("koptim=\t" << jbest << ",\t eps(k)=" << epsmin << ",\t q=\t" << qpred<< "("<<  ntest << "), lambda(q)=" << m_lambda[qpred-1] << ", alpha(q-1,q)=" << monitor(qpred-1, qpred) << "dt(q)=" << dtpred<< std::endl);
    1083              : 
    1084              :                         // EXTENSIONS: convergence model
    1085            0 :                         if (limexConverged)
    1086              :                         {
    1087            0 :                                 limex_success++;
    1088              : 
    1089              :                                 // a) aim for order increase in next step
    1090            0 :                           if ((qpred+1==ntest)  /* increase by one possible? */
    1091              :                               //    && (m_lambda[qpred-1]>1.0)
    1092              :                                   // && (m_num_reductions[qpred+1] <= m_max_reductions)
    1093            0 :                               && (kmax>ntest)) /* still below max? */
    1094              :                                 {
    1095            0 :                                         const double alpha = monitor(qpred-1, qpred);
    1096            0 :                                         UG_LOG("CHECKING for order increase: "<< m_costA[qpred] << "*" << alpha << ">" << m_costA[qpred+1]);
    1097              :                                         // check, whether further increase could still be efficient
    1098            0 :                                         if (m_costA[qpred] * alpha > m_costA[qpred+1])
    1099              :                                         {
    1100            0 :                                                 qpred++;                        // go for higher order
    1101            0 :                                                 if (m_greedyOrderIncrease >0.0) {
    1102            0 :                                                   dtpred *= (1.0-m_greedyOrderIncrease) + m_greedyOrderIncrease*alpha;          // & adapt time step  // TODO: check required!
    1103              :                                                 }
    1104              :                                                 UG_LOG("... yes.\n")
    1105              : 
    1106              :                                                 // update history
    1107            0 :                                                 vSwitchHistory[m_limex_step%nSwitchHistory] = (qpred - qcurr);
    1108            0 :                                                 UG_LOG("LIMEX-ASYMPTOTIC-ORDER switch update:  = " <<  (qpred - qcurr)<< std::endl);
    1109              : 
    1110              :                                         } else {
    1111              :                                                 UG_LOG("... nope.\n")
    1112              :                                         }
    1113              : 
    1114              :                                 }
    1115              : 
    1116              : 
    1117              :                                 // b) monitor convergence (a-priori check!)
    1118              : 
    1119              :                         }
    1120              : 
    1121              :                         // parameters for subsequent step
    1122            0 :                         dtcurr = std::min(dtpred, itime_integrator_type::get_dt_max());
    1123              : 
    1124              : 
    1125              :                 }
    1126              :                 else
    1127              :                 {
    1128              :                         // solver failed -> cut time step //
    1129              :                         number base_dtmin=base_type::get_dt_min();
    1130            0 :                         if(dtcurr <= base_dtmin)
    1131            0 :                                         base_type::set_dt_min(base_dtmin*m_sigmaReduction);
    1132              :                         
    1133            0 :                         dtcurr=std::max(base_type::get_dt_min(), dtcurr*m_sigmaReduction);
    1134              :                         
    1135              :                         //dtcurr=std:max(base_type::get_dt_min(), dtcurr);
    1136              :                 }
    1137              : 
    1138              :                 // output compute time for Limex step
    1139            0 :                 number watchTime = stopwatch.ms()/1000.0;
    1140              :                 UG_LOGN("Time: " << std::setprecision(3) << watchTime << "s");
    1141              : 
    1142            0 :                 if ((err==0) && limexConverged)
    1143              :                 {
    1144              :                         // ACCEPT time step
    1145            0 :                         UG_LOG("+++ LimexTimestep +++" << m_limex_step << " ACCEPTED"<< std::endl);
    1146              :                         UG_LOG("               :\t time \t dt (success) \t dt (pred) \tq=\t order (curr)" << qcurr+1 << std::endl);
    1147            0 :                         UG_LOG("LIMEX-ACCEPTING:\t" << t <<"\t"<< dt << "\t" << dtcurr << "\tq=\t" << qcurr+1 << std::endl);
    1148              : 
    1149              :                         // update PID controller
    1150              :                         /*qlast = qcurr;
    1151              :                         epslast =  timex.get_error_estimates();  // double check ???
    1152              :                         dtlast = dt;*/
    1153              :                         // Compute time derivatives (by extrapolation)
    1154            0 :                         if (this->has_time_derivative())
    1155              :                         {
    1156              :                                 UG_LOG("Computing derivative" << std::endl);
    1157            0 :                                 grid_function_type &udot = *get_time_derivative();
    1158              : 
    1159            0 :                                 for (size_t i=0; i<=jbest; ++i)
    1160              :                                 {
    1161            0 :                                         timex.set_solution(m_vThreadData[i].get_derivative(), i);
    1162              :                                 }
    1163            0 :                                 timex.apply(jbest+1, false); // do not compute error
    1164              : 
    1165            0 :                                 udot = *timex.get_solution(jbest).template cast_dynamic<grid_function_type>();
    1166              : 
    1167            0 :                                 std::ostringstream ossName;
    1168              :                                 ossName << std::setfill('0');
    1169            0 :                                 ossName << "Limex_Derivative_iter" << m_limex_step << "_total" << limex_total;
    1170            0 :                                 this->write_debug(udot, ossName.str().c_str());
    1171            0 :                         }
    1172              : 
    1173              : 
    1174              :                         // Copy best solution.
    1175              :                         UG_ASSERT(ubest.valid(), "Huhh: Invalid error estimate?");
    1176            0 :                         *u = *ubest;
    1177            0 :                         t += dt;
    1178              : 
    1179              :                         // Initiate post process.
    1180            0 :                         itime_integrator_type::notify_finalize_step(u, m_limex_step++, t, dt);
    1181              : 
    1182              :                         // make sure that all threads continue
    1183              :                         // with identical initial value u(t)
    1184              :                         // update_integrator_threads(ubest, t);
    1185              : 
    1186              : 
    1187              :                         // working on last row => increase order
    1188              :                         //if (ntest == q+1) ntest++;
    1189              :                 }
    1190              :                 else
    1191              :                 {
    1192              :                         // DISCARD time step
    1193            0 :                         UG_LOG("+++ LimexTimestep +++" << m_limex_step << " FAILED" << std::endl);
    1194            0 :                         UG_LOG("               :\t time \t dt (failed) \t dt (curr) \teps=\t" << epsmin <<"\t(tol="<<m_tol<<")\terr="<<err<< std::endl);
    1195            0 :                         UG_LOG("LIMEX-REJECTING:\t" << t <<"\t"<< dt << "\t" << dtcurr <<std::endl);
    1196              : 
    1197            0 :                         itime_integrator_type::notify_rewind_step(ubest, m_limex_step, t+dt, dt);
    1198              : 
    1199              :                 }
    1200              : 
    1201              :                 // interrupt if interruption flag set
    1202            0 :                 if (m_bInterrupt)
    1203              :                 {
    1204              :                         UG_LOGN("Limex interrupted by external command.");
    1205            0 :                         break;
    1206              :                 }
    1207              : 
    1208              :                 // SERIAL EXECUTION: END
    1209              :                 ///////////////////////////////////////
    1210            0 :                 update_integrator_threads(u, t);
    1211              : 
    1212              : 
    1213              :                 // SOLVE
    1214              : 
    1215              :                 // ESTIMATE
    1216              : 
    1217              :                 // MARK
    1218              : 
    1219              :                 // REFINE
    1220              : 
    1221              : 
    1222              :         } // time integration loop
    1223              : 
    1224            0 :         dispose_integrator_threads();
    1225              : 
    1226            0 :         return true;
    1227            0 : } // apply
    1228              : 
    1229              : 
    1230              : } // namespace ug
    1231              : 
    1232              : #endif /* TIME_INTEGRATOR_HPP_ */
        

Generated by: LCOV version 2.0-1