Discontinuous Galerkin Library
#include "dg/algorithm.h"
multistep.h
Go to the documentation of this file.
1#pragma once
2
3#include <map>
4#include <tuple>
5#include "ode.h"
6#include "runge_kutta.h"
7#include "multistep_tableau.h"
8
12namespace dg{
13
14
26template<class ContainerType>
27struct FilteredExplicitMultistep;
29//
32
58template<class ContainerType>
60{
62 using container_type = ContainerType;
64 ExplicitMultistep() = default;
66 ExplicitMultistep( ConvertsToMultistepTableau<value_type> tableau, const ContainerType& copyable): m_fem( tableau, copyable){ }
68 template<class ...Params>
69 void construct(Params&& ...ps)
70 {
71 //construct and swap
72 *this = ExplicitMultistep( std::forward<Params>(ps)...);
73 }
75 const ContainerType& copyable()const{ return m_fem.copyable();}
76
89 template< class ExplicitRHS>
90 void init( ExplicitRHS& rhs, value_type t0, const ContainerType& u0, value_type dt){
92 m_fem.init( std::tie(rhs, id), t0, u0, dt);
93 }
94
106 template< class ExplicitRHS>
107 void step( ExplicitRHS& rhs, value_type& t, ContainerType& u){
109 m_fem.step( std::tie(rhs, id), t, u);
110 }
111
112 private:
114};
115
116
154template<class ContainerType>
156{
158 using container_type = ContainerType;
160 ImExMultistep() = default;
161
170 const ContainerType& copyable):
171 m_t(tableau)
172 {
173 //only store implicit part if needed
174 unsigned size_f = 0;
175 for( unsigned i=0; i<m_t.steps(); i++ )
176 {
177 if( m_t.im( i+1) != 0 )
178 size_f = i+1;
179 }
180 m_im.assign( size_f, copyable);
181 m_u.assign( m_t.steps(), copyable);
182 m_ex.assign( m_t.steps(), copyable);
183 m_tmp = copyable;
184 m_counter = 0;
185 }
187 template<class ...Params>
188 void construct( Params&& ...ps)
189 {
190 //construct and swap
191 *this = ImExMultistep( std::forward<Params>( ps)...);
192 }
194 const ContainerType& copyable()const{ return m_tmp;}
195
213 template< class ExplicitRHS, class ImplicitRHS, class Solver>
214 void init( const std::tuple<ExplicitRHS, ImplicitRHS, Solver>& ode,
215 value_type t0, const ContainerType& u0, value_type dt);
216
238 template< class ExplicitRHS, class ImplicitRHS, class Solver>
239 void step( const std::tuple<ExplicitRHS, ImplicitRHS, Solver>& ode,
240 value_type& t, ContainerType& u);
241
242 private:
244 std::vector<ContainerType> m_u, m_ex, m_im;
245 ContainerType m_tmp;
246 value_type m_tu, m_dt;
247 unsigned m_counter; //counts how often step has been called after init
248};
249
251template< class ContainerType>
252template< class RHS, class Diffusion, class Solver>
253void ImExMultistep<ContainerType>::init( const std::tuple<RHS, Diffusion, Solver>& ode, value_type t0, const ContainerType& u0, value_type dt)
254{
255 m_tu = t0, m_dt = dt;
256 unsigned s = m_t.steps();
257 blas1::copy( u0, m_u[s-1]);
258 m_counter = 0;
259 if( s-1-m_counter < m_im.size())
260 std::get<1>(ode)( m_tu, m_u[s-1-m_counter], m_im[s-1-m_counter]);
261 std::get<0>(ode)( t0, u0, m_ex[s-1]); //f may not destroy u0
262}
263
264template<class ContainerType>
265template< class RHS, class Diffusion, class Solver>
266void ImExMultistep<ContainerType>::step( const std::tuple<RHS, Diffusion, Solver>& ode, value_type& t, ContainerType& u)
267{
268 unsigned s = m_t.steps();
269 if( m_counter < s - 1)
270 {
271 std::map<unsigned, std::string> order2method{
272 {1, "ARK-4-2-3"},
273 {2, "ARK-4-2-3"},
274 {3, "ARK-4-2-3"},
275 {4, "ARK-6-3-4"},
276 {5, "ARK-8-4-5"},
277 {6, "ARK-8-4-5"},
278 {7, "ARK-8-4-5"}
279 };
280 ARKStep<ContainerType> ark( order2method.at( m_t.order()), u);
281 ContainerType tmp ( u);
282 ark.step( ode, t, u, t, u, m_dt, tmp);
283 m_counter++;
284 m_tu = t;
285 dg::blas1::copy( u, m_u[s-1-m_counter]);
286 if( s-1-m_counter < m_im.size())
287 std::get<1>(ode)( m_tu, m_u[s-1-m_counter], m_im[s-1-m_counter]);
288 std::get<0>(ode)( m_tu, m_u[s-1-m_counter], m_ex[s-1-m_counter]);
289 return;
290 }
291 //compute right hand side of inversion equation
292 dg::blas1::axpbypgz( m_t.a(0), m_u[0], m_dt*m_t.ex(0), m_ex[0], 0., m_tmp);
293 for (unsigned i = 1; i < s; i++)
294 dg::blas1::axpbypgz( m_t.a(i), m_u[i], m_dt*m_t.ex(i), m_ex[i], 1., m_tmp);
295 for (unsigned i = 0; i < m_im.size(); i++)
296 dg::blas1::axpby( m_dt*m_t.im(i+1), m_im[i], 1., m_tmp);
297 t = m_tu = m_tu + m_dt;
298
299 //Rotate 1 to the right (note the reverse iterator here!)
300 std::rotate( m_u.rbegin(), m_u.rbegin() + 1, m_u.rend());
301 std::rotate( m_ex.rbegin(), m_ex.rbegin() + 1, m_ex.rend());
302 if( !m_im.empty())
303 std::rotate( m_im.rbegin(), m_im.rbegin() + 1, m_im.rend());
304 //compute implicit part
305 value_type alpha = m_dt*m_t.im(0);
306 std::get<2>(ode)( alpha, t, u, m_tmp);
307
308 blas1::copy( u, m_u[0]); //store result
309 if( 0 < m_im.size())
310 dg::blas1::axpby( 1./alpha, u, -1./alpha, m_tmp, m_im[0]);
311 std::get<0>(ode)(m_tu, m_u[0], m_ex[0]); //call f on new point
312}
314
344template<class ContainerType>
346{
347
349 using container_type = ContainerType;
351 ImplicitMultistep() = default;
352
361 ContainerType& copyable): m_t( tableau)
362 {
363 unsigned size_f = 0;
364 for( unsigned i=0; i<m_t.steps(); i++ )
365 {
366 if( m_t.im( i+1) != 0 )
367 size_f = i+1;
368 }
369 m_f.assign( size_f, copyable);
370 m_u.assign( m_t.steps(), copyable);
371 m_tmp = copyable;
372 m_counter = 0;
373 }
374
376 template<class ...Params>
377 void construct(Params&& ...ps)
378 {
379 //construct and swap
380 *this = ImplicitMultistep( std::forward<Params>(ps)...);
381 }
383 const ContainerType& copyable()const{ return m_tmp;}
384
402 template<class ImplicitRHS, class Solver>
403 void init(const std::tuple<ImplicitRHS, Solver>& ode, value_type t0, const ContainerType& u0, value_type dt);
404
424 template<class ImplicitRHS, class Solver>
425 void step(const std::tuple<ImplicitRHS, Solver>& ode, value_type& t, container_type& u);
426 private:
428 value_type m_tu, m_dt;
429 std::vector<ContainerType> m_u;
430 std::vector<ContainerType> m_f;
431 ContainerType m_tmp;
432 unsigned m_counter = 0; //counts how often step has been called after init
433};
435template< class ContainerType>
436template<class ImplicitRHS, class Solver>
437void ImplicitMultistep<ContainerType>::init(const std::tuple<ImplicitRHS, Solver>& ode,
438 value_type t0, const ContainerType& u0, value_type dt)
439{
440 m_tu = t0, m_dt = dt;
441 dg::blas1::copy( u0, m_u[m_u.size()-1]);
442 m_counter = 0;
443 //only assign to f if we actually need to store it
444 unsigned s = m_t.steps();
445 if( s-1-m_counter < m_f.size())
446 std::get<0>(ode)( m_tu, m_u[s-1-m_counter], m_f[s-1-m_counter]);
447}
448
449template< class ContainerType>
450template<class ImplicitRHS, class Solver>
451void ImplicitMultistep<ContainerType>::step(const std::tuple<ImplicitRHS, Solver>& ode,
452 value_type& t, container_type& u)
453{
454 unsigned s = m_t.steps();
455 if( m_counter < s - 1)
456 {
457 std::map<unsigned, enum tableau_identifier> order2method{
459 {2, SDIRK_2_1_2},
460 {3, SDIRK_4_2_3},
461 {4, SDIRK_5_3_4},
462 {5, SANCHEZ_6_5},
463 {6, SANCHEZ_7_6},
464 {7, SANCHEZ_7_6}
465 };
466 ImplicitRungeKutta<ContainerType> dirk(
467 order2method.at(m_t.order()), u);
468 dirk.step( ode, t, u, t, u, m_dt);
469 m_counter++;
470 m_tu = t;
471 dg::blas1::copy( u, m_u[s-1-m_counter]);
472 //only assign to f if we actually need to store it
473 if( s-1-m_counter < m_f.size())
474 std::get<0>(ode)( m_tu, m_u[s-1-m_counter], m_f[s-1-m_counter]);
475 return;
476 }
477 //compute right hand side of inversion equation
478 dg::blas1::axpby( m_t.a(0), m_u[0], 0., m_tmp);
479 for (unsigned i = 1; i < s; i++)
480 dg::blas1::axpby( m_t.a(i), m_u[i], 1., m_tmp);
481 for (unsigned i = 0; i < m_f.size(); i++)
482 dg::blas1::axpby( m_dt*m_t.im(i+1), m_f[i], 1., m_tmp);
483 t = m_tu = m_tu + m_dt;
484
485 //Rotate 1 to the right (note the reverse iterator here!)
486 std::rotate(m_u.rbegin(), m_u.rbegin() + 1, m_u.rend());
487 if( !m_f.empty())
488 std::rotate(m_f.rbegin(), m_f.rbegin() + 1, m_f.rend());
489 value_type alpha = m_dt*m_t.im(0);
490 std::get<1>(ode)( alpha, t, u, m_tmp);
491
492 dg::blas1::copy( u, m_u[0]);
493 if( 0 < m_f.size())
494 dg::blas1::axpby( 1./alpha, u, -1./alpha, m_tmp, m_f[0]);
495}
497
498
499
513template<class ContainerType>
515{
517 using container_type = ContainerType;
519 FilteredExplicitMultistep(){ m_u.resize(1); //this makes the copyable function work
520 }
521
531 const ContainerType& copyable): m_t(tableau)
532 {
533 m_f.assign( m_t.steps(), copyable);
534 m_u.assign( m_t.steps(), copyable);
535 m_counter = 0;
536 }
538 template<class ...Params>
539 void construct( Params&& ...ps)
540 {
541 //construct and swap
542 *this = FilteredExplicitMultistep( std::forward<Params>( ps)...);
543 }
545 const ContainerType& copyable()const{ return m_u[0];}
546
562 template< class ExplicitRHS, class Limiter>
563 void init( const std::tuple<ExplicitRHS, Limiter>& ode, value_type t0, const ContainerType& u0, value_type dt);
564
580 template< class ExplicitRHS, class Limiter>
581 void step( const std::tuple<ExplicitRHS, Limiter>& ode, value_type& t, ContainerType& u);
582
583 private:
585 std::vector<ContainerType> m_u, m_f;
586 value_type m_tu, m_dt;
587 unsigned m_counter; //counts how often step has been called after init
588};
590template< class ContainerType>
591template< class ExplicitRHS, class Limiter>
592void FilteredExplicitMultistep<ContainerType>::init( const std::tuple<ExplicitRHS, Limiter>& ode, value_type t0, const ContainerType& u0, value_type dt)
593{
594 m_tu = t0, m_dt = dt;
595 unsigned s = m_t.steps();
596 dg::blas1::copy( u0, m_u[s-1]);
597 std::get<1>(ode)( m_u[s-1]);
598 std::get<0>(ode)(m_tu, m_u[s-1], m_f[s-1]); //call f on new point
599 m_counter = 0;
600}
601
602template<class ContainerType>
603template<class ExplicitRHS, class Limiter>
604void FilteredExplicitMultistep<ContainerType>::step(const std::tuple<ExplicitRHS, Limiter>& ode, value_type& t, ContainerType& u)
605{
606 unsigned s = m_t.steps();
607 if( m_counter < s-1)
608 {
609 std::map<unsigned, enum tableau_identifier> order2method{
610 {1, SSPRK_2_2},
611 {2, SSPRK_2_2},
612 {3, SSPRK_3_3},
613 {4, SSPRK_5_4},
614 {5, SSPRK_5_4},
615 {6, SSPRK_5_4},
616 {7, SSPRK_5_4}
617 };
618 ShuOsher<ContainerType> rk( order2method.at(m_t.order()), u);
619 rk.step( ode, t, u, t, u, m_dt);
620 m_counter++;
621 m_tu = t;
622 blas1::copy( u, m_u[s-1-m_counter]);
623 std::get<0>(ode)( m_tu, m_u[s-1-m_counter], m_f[s-1-m_counter]);
624 return;
625 }
626 //compute new t,u
627 t = m_tu = m_tu + m_dt;
628 dg::blas1::axpby( m_t.a(0), m_u[0], m_dt*m_t.ex(0), m_f[0], u);
629 for (unsigned i = 1; i < s; i++){
630 dg::blas1::axpbypgz( m_t.a(i), m_u[i], m_dt*m_t.ex(i), m_f[i], 1., u);
631 }
632 //apply limiter
633 std::get<1>(ode)( u);
634 //permute m_f[s-1], m_u[s-1] to be the new m_f[0], m_u[0]
635 std::rotate( m_f.rbegin(), m_f.rbegin()+1, m_f.rend());
636 std::rotate( m_u.rbegin(), m_u.rbegin()+1, m_u.rend());
637 blas1::copy( u, m_u[0]); //store result
638 std::get<0>(ode)(m_tu, m_u[0], m_f[0]); //call f on new point
639}
641//
642
643
661template<class ContainerType>
662struct MultistepTimeloop : public aTimeloop<ContainerType>
663{
664 using container_type = ContainerType;
667 MultistepTimeloop( ) = default;
668 // We cannot reset dt because that would require access to the Stepper to re-init
675 MultistepTimeloop( std::function<void ( value_type&, ContainerType&)>
676 step, value_type dt ) : m_step(step), m_dt(dt){}
696 template<class Stepper, class ODE>
698 Stepper&& stepper, ODE&& ode, value_type t0, const
699 ContainerType& u0, value_type dt )
700 {
701 stepper.init( ode, t0, u0, dt);
702 m_step = [=, cap = std::tuple<Stepper, ODE>(std::forward<Stepper>(stepper),
703 std::forward<ODE>(ode)) ]( auto& t, auto& y) mutable
704 {
705 std::get<0>(cap).step( std::get<1>(cap), t, y);
706 };
707 m_dt = dt;
708 }
709
711 template<class ...Params>
712 void construct( Params&& ...ps)
713 {
714 //construct and swap
715 *this = MultistepTimeloop( std::forward<Params>( ps)...);
716 }
717
718 virtual MultistepTimeloop* clone() const{return new
719 MultistepTimeloop(*this);}
720 private:
721 virtual void do_integrate(value_type& t0, const container_type& u0,
722 value_type t1, container_type& u1, enum to mode) const;
723 std::function<void ( value_type&, ContainerType&)> m_step;
724 virtual value_type do_dt( ) const { return m_dt;}
725 value_type m_dt;
726};
727
729template< class ContainerType>
730void MultistepTimeloop<ContainerType>::do_integrate(
731 value_type& t_begin, const ContainerType&
732 begin, value_type t_end, ContainerType& end,
733 enum to mode ) const
734{
735 bool forward = (t_end - t_begin > 0);
736 if( (m_dt < 0 && forward) || ( m_dt > 0 && !forward) )
737 throw dg::Error( dg::Message(_ping_)<<"Timestep has wrong sign! dt "<<m_dt);
738 if( m_dt == 0)
739 throw dg::Error( dg::Message(_ping_)<<"Timestep may not be zero in MultistepTimeloop!");
740 dg::blas1::copy( begin, end);
741 if( is_divisable( t_end-t_begin, m_dt))
742 {
743 unsigned N = (unsigned)round((t_end - t_begin)/m_dt);
744 for( unsigned i=0; i<N; i++)
745 m_step( t_begin, end);
746 return;
747 }
748 else
749 {
750 if( dg::to::exact == mode)
751 throw dg::Error( dg::Message(_ping_) << "In a multistep integrator dt "
752 <<m_dt<<" has to integer divide the interval "<<t_end-t_begin);
753 unsigned N = (unsigned)floor( (t_end-t_begin)/m_dt);
754 for( unsigned i=0; i<N+1; i++)
755 m_step( t_begin, end);
756 }
757}
759
761
762} //namespace dg
class intended for the use in throw statements
Definition: exceptions.h:83
small class holding a stringstream
Definition: exceptions.h:29
#define _ping_
Definition: exceptions.h:12
void copy(const ContainerTypeIn &source, ContainerTypeOut &target)
Definition: blas1.h:164
void axpbypgz(get_value_type< ContainerType > alpha, const ContainerType1 &x, get_value_type< ContainerType > beta, const ContainerType2 &y, get_value_type< ContainerType > gamma, ContainerType &z)
Definition: blas1.h:265
void axpby(get_value_type< ContainerType > alpha, const ContainerType1 &x, get_value_type< ContainerType > beta, ContainerType &y)
Definition: blas1.h:231
@ forward
forward derivative (cell to the right and current cell)
Definition: enums.h:98
@ y
y direction
bool is_divisable(double a, double b, double eps=1e-15)
Definition: runge_kutta.h:961
to
Switch for the Timeloop integrate function.
Definition: ode.h:17
@ exact
match the ending exactly
@ SSPRK_2_2
SSPRK "Shu-Osher-Form"
Definition: tableau.h:1379
@ SSPRK_3_3
SSPRK "Shu-Osher-Form"
Definition: tableau.h:1381
@ SANCHEZ_6_5
Sanchez-6-5
Definition: tableau.h:1375
@ SSPRK_5_4
SSPRK "Shu-Osher-Form"
Definition: tableau.h:1383
@ IMPLICIT_EULER_1_1
Euler (implicit)
Definition: tableau.h:1356
@ SDIRK_2_1_2
generic 2nd order A and L-stable
Definition: tableau.h:1359
@ SANCHEZ_7_6
Sanchez-7-6
Definition: tableau.h:1377
@ SDIRK_5_3_4
SDIRK-5-3-4
Definition: tableau.h:1371
@ SDIRK_4_2_3
Cameron2002
Definition: tableau.h:1365
typename TensorTraits< std::decay_t< Vector > >::value_type get_value_type
Definition: tensor_traits.h:38
This is the namespace for all functions and classes defined and used by the discontinuous Galerkin li...
An abstract ODE integrator.
Runge-Kutta explicit ODE-integrators.
Convert identifiers to their corresponding dg::MultistepTableau.
Definition: multistep_tableau.h:651
General explicit linear multistep ODE integrator .
Definition: multistep.h:60
ExplicitMultistep()=default
No memory allocation.
void step(ExplicitRHS &rhs, value_type &t, ContainerType &u)
Advance one timestep.
Definition: multistep.h:107
ContainerType container_type
Definition: multistep.h:62
ExplicitMultistep(ConvertsToMultistepTableau< value_type > tableau, const ContainerType &copyable)
Reserve memory for the integration.
Definition: multistep.h:66
void init(ExplicitRHS &rhs, value_type t0, const ContainerType &u0, value_type dt)
Initialize timestepper. Call before using the step function.
Definition: multistep.h:90
void construct(Params &&...ps)
Perfect forward parameters to one of the constructors.
Definition: multistep.h:69
get_value_type< ContainerType > value_type
the value type of the time variable (float or double)
Definition: multistep.h:61
const ContainerType & copyable() const
Return an object of same size as the object used for construction.
Definition: multistep.h:75
EXPERIMENTAL: General explicit linear multistep ODE integrator with Limiter / Filter .
Definition: multistep.h:515
const ContainerType & copyable() const
Return an object of same size as the object used for construction.
Definition: multistep.h:545
void init(const std::tuple< ExplicitRHS, Limiter > &ode, value_type t0, const ContainerType &u0, value_type dt)
Initialize timestepper. Call before using the step function.
FilteredExplicitMultistep(ConvertsToMultistepTableau< value_type > tableau, const ContainerType &copyable)
Reserve memory for the integration.
Definition: multistep.h:530
ContainerType container_type
Definition: multistep.h:517
void construct(Params &&...ps)
Perfect forward parameters to one of the constructors.
Definition: multistep.h:539
void step(const std::tuple< ExplicitRHS, Limiter > &ode, value_type &t, ContainerType &u)
Advance one timestep.
get_value_type< ContainerType > value_type
the value type of the time variable (float or double)
Definition: multistep.h:516
FilteredExplicitMultistep()
No memory allocation.
Definition: multistep.h:519
A filter that does nothing.
Definition: runge_kutta.h:119
Semi-implicit multistep ODE integrator .
Definition: multistep.h:156
void construct(Params &&...ps)
Perfect forward parameters to one of the constructors.
Definition: multistep.h:188
ImExMultistep(ConvertsToMultistepTableau< value_type > tableau, const ContainerType &copyable)
Reserve memory for integration and construct Solver.
Definition: multistep.h:169
const ContainerType & copyable() const
Return an object of same size as the object used for construction.
Definition: multistep.h:194
get_value_type< ContainerType > value_type
the value type of the time variable (float or double)
Definition: multistep.h:157
void step(const std::tuple< ExplicitRHS, ImplicitRHS, Solver > &ode, value_type &t, ContainerType &u)
Advance one timestep.
void init(const std::tuple< ExplicitRHS, ImplicitRHS, Solver > &ode, value_type t0, const ContainerType &u0, value_type dt)
Initialize timestepper. Call before using the step function.
ImExMultistep()=default
No memory allocation.
ContainerType container_type
Definition: multistep.h:158
Implicit multistep ODE integrator .
Definition: multistep.h:346
void construct(Params &&...ps)
Perfect forward parameters to one of the constructors.
Definition: multistep.h:377
const ContainerType & copyable() const
Return an object of same size as the object used for construction.
Definition: multistep.h:383
void step(const std::tuple< ImplicitRHS, Solver > &ode, value_type &t, container_type &u)
Advance one timestep.
ImplicitMultistep(ConvertsToMultistepTableau< value_type > tableau, const ContainerType &copyable)
Reserve memory for integration.
Definition: multistep.h:360
get_value_type< ContainerType > value_type
the value type of the time variable (float or double)
Definition: multistep.h:348
void init(const std::tuple< ImplicitRHS, Solver > &ode, value_type t0, const ContainerType &u0, value_type dt)
Initialize timestepper. Call before using the step function.
ImplicitMultistep()=default
No memory allocation.
ContainerType container_type
Definition: multistep.h:349
unsigned steps() const
The number of stages s.
Definition: multistep_tableau.h:75
real_type im(unsigned i)
Read the implicit (c_i) coefficients.
Definition: multistep_tableau.h:73
Integrate using a for loop and a fixed non-changeable time-step.
Definition: multistep.h:663
MultistepTimeloop(Stepper &&stepper, ODE &&ode, value_type t0, const ContainerType &u0, value_type dt)
Initialize and bind the step function of a Multistep stepper.
Definition: multistep.h:697
ContainerType container_type
Definition: multistep.h:664
MultistepTimeloop(std::function< void(value_type &, ContainerType &)> step, value_type dt)
Construct using a std::function.
Definition: multistep.h:675
virtual MultistepTimeloop * clone() const
Abstract copy method that returns a copy of *this on the heap.
Definition: multistep.h:718
void construct(Params &&...ps)
Perfect forward parameters to one of the constructors.
Definition: multistep.h:712
MultistepTimeloop()=default
no allocation
dg::get_value_type< ContainerType > value_type
Definition: multistep.h:665
Abstract timeloop independent of stepper and ODE.
Definition: ode.h:60