Discontinuous Galerkin Library
#include "dg/algorithm.h"
runge_kutta.h
Go to the documentation of this file.
1#ifndef _DG_RK_
2#define _DG_RK_
3
4#include <cassert>
5#include <array>
6#include <tuple>
7
8#include "ode.h"
10#include "tableau.h"
11#include "blas1.h"
12#include "implicit.h"
13
18namespace dg{
20namespace detail{
21// this is a dense matrix-matrix multiplication
22// a generalization of the corresponding blas2::gemv DenseMatrix algorithm
23template<class ContainerType>
24void gemm(
25 const std::array<double,2>& alpha,
26 const DenseMatrix<ContainerType>& m,
27 const std::array<const std::vector<double>*,2> x,
28 const std::array<double,2>& beta,
29 std::array<ContainerType*,2>&& y)
30{
31 const unsigned size = m.num_cols();
32 unsigned i=0;
33 if( size >= 8)
34 for( i=0; i<size/8; i++)
36 *y[0], *y[1], i==0 ? beta[0] : 1., i==0 ? beta[1] : 1.,
37 alpha[0]*(*x[0])[i*8+0], alpha[1]*(*x[1])[i*8+0], *m.get()[i*8+0],
38 alpha[0]*(*x[0])[i*8+1], alpha[1]*(*x[1])[i*8+1], *m.get()[i*8+1],
39 alpha[0]*(*x[0])[i*8+2], alpha[1]*(*x[1])[i*8+2], *m.get()[i*8+2],
40 alpha[0]*(*x[0])[i*8+3], alpha[1]*(*x[1])[i*8+3], *m.get()[i*8+3],
41 alpha[0]*(*x[0])[i*8+4], alpha[1]*(*x[1])[i*8+4], *m.get()[i*8+4],
42 alpha[0]*(*x[0])[i*8+5], alpha[1]*(*x[1])[i*8+5], *m.get()[i*8+5],
43 alpha[0]*(*x[0])[i*8+6], alpha[1]*(*x[1])[i*8+6], *m.get()[i*8+6],
44 alpha[0]*(*x[0])[i*8+7], alpha[1]*(*x[1])[i*8+7], *m.get()[i*8+7]);
45 unsigned l=0;
46 if( size%8 >= 4)
47 for( l=0; l<(size%8)/4; l++)
49 *y[0], *y[1], size < 8 ? beta[0] : 1., size < 8 ? beta[1] : 1.,
50 alpha[0]*(*x[0])[i*8+l*4+0], alpha[1]*(*x[1])[i*8+l*4+0], *m.get()[i*8+l*4+0],
51 alpha[0]*(*x[0])[i*8+l*4+1], alpha[1]*(*x[1])[i*8+l*4+1], *m.get()[i*8+l*4+1],
52 alpha[0]*(*x[0])[i*8+l*4+2], alpha[1]*(*x[1])[i*8+l*4+2], *m.get()[i*8+l*4+2],
53 alpha[0]*(*x[0])[i*8+l*4+3], alpha[1]*(*x[1])[i*8+l*4+3], *m.get()[i*8+l*4+3]);
54 unsigned k=0;
55 if( (size%8)%4 >= 2)
56 for( k=0; k<((size%8)%4)/2; k++)
58 *y[0], *y[1], size < 4 ? beta[0] : 1., size < 4 ? beta[1] : 1.,
59 alpha[0]*(*x[0])[i*8+l*4+k*2+0], alpha[1]*(*x[1])[i*8+l*4+k*2+0], *m.get()[i*8+l*4+k*2+0],
60 alpha[0]*(*x[0])[i*8+l*4+k*2+1], alpha[1]*(*x[1])[i*8+l*4+k*2+1], *m.get()[i*8+l*4+k*2+1]);
61 if( ((size%8)%4)%2 == 1)
63 *y[0], *y[1], size < 2 ? beta[0] : 1., size < 2 ? beta[1] : 1.,
64 alpha[0]*(*x[0])[i*8+l*4+k*2], alpha[1]*(*x[1])[i*8+l*4+k*2], *m.get()[i*8+l*4+k*2]);
65
66}
67} // namespace detail
69
119{
126 template<class ContainerType1>
127 void operator()( ContainerType1& inout) const{ }
128};
130template<class ContainerType>
131struct FilteredERKStep;
133//Should we try if filters inside RHS are equally usable?
134
137
138
161template< class ContainerType>
163{
165 using container_type = ContainerType;
167 ERKStep() = default;
176 ERKStep( ConvertsToButcherTableau<value_type> tableau, const ContainerType&
177 copyable): m_ferk(tableau, copyable)
178 {
179 }
180
182 template<class ...Params>
183 void construct( Params&& ...ps)
184 {
185 //construct and swap
186 *this = ERKStep( std::forward<Params>( ps)...);
187 }
189 const ContainerType& copyable()const{ return m_ferk.copyable();}
190
192 void ignore_fsal(){ m_ferk.ignore_fsal();}
194 void enable_fsal(){ m_ferk.enable_fsal();}
195
199 template<class ExplicitRHS>
200 void step( ExplicitRHS& rhs, value_type t0, const ContainerType& u0, value_type& t1, ContainerType& u1, value_type dt, ContainerType& delta)
201 {
203 m_ferk.step( std::tie( rhs, id), t0, u0, t1, u1, dt, delta);
204 }
231 template<class ExplicitRHS>
232 void step( ExplicitRHS& rhs, value_type t0, const ContainerType& u0, value_type&
233 t1, ContainerType& u1, value_type dt)
234 {
236 m_ferk.step( std::tie( rhs, id), t0, u0, t1, u1, dt);
237 }
239 unsigned order() const {
240 return m_ferk.order();
241 }
243 unsigned embedded_order() const {
244 return m_ferk.embedded_order();
245 }
247 unsigned num_stages() const{
248 return m_ferk.num_stages();
249 }
250 private:
252};
253
275template< class ContainerType>
277{
279 using container_type = ContainerType;
281 FilteredERKStep() { m_k.resize(1); }
284 ContainerType& copyable): m_rk(tableau), m_k(m_rk.num_stages(),
285 copyable)
286 {
287 m_rkb.resize(m_k.size()), m_rkd.resize( m_k.size());
288 for( unsigned i=0; i<m_k.size(); i++)
289 {
290 m_rkb[i] = m_rk.b(i);
291 m_rkd[i] = m_rk.d(i);
292 }
293 }
294
296 template<class ...Params>
297 void construct( Params&& ...ps)
298 {
299 //construct and swap
300 *this = FilteredERKStep( std::forward<Params>( ps)...);
301 }
303 const ContainerType& copyable()const{ return m_k[0];}
304
306 void ignore_fsal(){ m_ignore_fsal = true;}
308 void enable_fsal(){ m_ignore_fsal = false;}
309
314 template<class ExplicitRHS, class Limiter>
315 void step( const std::tuple<ExplicitRHS,Limiter>& rhs, value_type t0, const ContainerType& u0, value_type& t1, ContainerType& u1, value_type dt, ContainerType& delta)
316 {
317 step ( rhs, t0, u0, t1, u1, dt, delta, true);
318 }
321 template<class ExplicitRHS, class Limiter>
322 void step( const std::tuple<ExplicitRHS, Limiter>& rhs, value_type t0, const ContainerType& u0, value_type&
323 t1, ContainerType& u1, value_type dt)
324 {
325 if( !m_tmp_allocated)
326 {
327 dg::assign( m_k[0], m_tmp);
328 m_tmp_allocated = true;
329 }
330 step ( rhs, t0, u0, t1, u1, dt, m_tmp, false);
331 }
333 unsigned order() const {
334 return m_rk.order();
335 }
337 unsigned embedded_order() const {
338 return m_rk.embedded_order();
339 }
341 unsigned num_stages() const{
342 return m_rk.num_stages();
343 }
344 private:
345 template<class ExplicitRHS, class Limiter>
346 void step( const std::tuple<ExplicitRHS, Limiter>& rhs, value_type t0, const ContainerType& u0, value_type& t1, ContainerType& u1, value_type dt, ContainerType& delta, bool);
348 std::vector<value_type> m_rkb, m_rkd;
349 std::vector<ContainerType> m_k;
350 value_type m_t1 = 1e300;//remember the last timestep at which ERK is called
351 bool m_ignore_fsal = false;
352 ContainerType m_tmp; // only conditionally allocated
353 bool m_tmp_allocated = false;
354};
355
357
358template< class ContainerType>
359template<class ExplicitRHS, class Limiter>
360void FilteredERKStep<ContainerType>::step( const std::tuple<ExplicitRHS, Limiter>& ode, value_type t0, const ContainerType& u0, value_type& t1, ContainerType& u1, value_type dt, ContainerType& delta, bool compute_delta)
361{
362 unsigned s = m_rk.num_stages();
363 std::vector<const ContainerType*> k_ptrs = dg::asPointers( m_k);
364 //0 stage: probe
365 value_type tu = t0;
366 if( t0 != m_t1 || m_ignore_fsal)
367 std::get<0>(ode)(t0, u0, m_k[0]); //freshly compute k_0
368 //else take from last call
369 for ( unsigned i=1; i<s; i++)
370 {
371 std::vector<value_type> rka( i);
372 for( unsigned l=0; l<i; l++)
373 rka[l] = m_rk.a(i,l);
374
375 tu = DG_FMA( dt,m_rk.c(i),t0); //l=0
376 dg::blas1::copy( u0, delta); // can't use u1 here cause u0 can alias
377 dg::blas2::gemv( dt, dg::asDenseMatrix( k_ptrs, i), rka, 1., delta);
378
379 std::get<1>(ode)( delta);
380 std::get<0>(ode)( tu, delta, m_k[i]);
381 }
382 //Now add everything up to get solution and error estimate
383 dg::blas1::copy( u0, u1);
384 if( compute_delta)
385 detail::gemm( {dt,dt}, dg::asDenseMatrix(k_ptrs), {&m_rkb, &m_rkd},
386 {1.,0.}, {&u1, &delta});
387 else
388 blas2::gemv( dt, dg::asDenseMatrix(k_ptrs), m_rkb, 1., u1);
389 std::get<1>(ode)( u1);
390 //make sure (t1,u1) is the last call to f
391 m_t1 = t1 = t0 + dt;
392 if(!m_rk.isFsal() )
393 std::get<0>(ode)( t1, u1, m_k[0]);
394 else
395 {
396 using std::swap;
397 swap( m_k[0], m_k[s-1]); //enable free swap functions
398 }
399}
401
402
427template<class ContainerType>
429{
431 using container_type = ContainerType;
433 ARKStep(){ m_kI.resize(1); }
440 ARKStep( std::string name, const ContainerType& copyable)
441 {
442 std::string exp_name = name+" (explicit)";
443 std::string imp_name = name+" (implicit)";
444 *this = ARKStep( exp_name, imp_name, copyable);
445 }
462 const ContainerType& copyable
463 ):
464 m_rkE(ex_tableau),
465 m_rkI(im_tableau),
466 m_kE(m_rkE.num_stages(), copyable),
467 m_kI(m_rkI.num_stages(), copyable)
468 {
469 assert( m_rkE.num_stages() == m_rkI.num_stages());
470 // check fsal
471 assert( m_rkI.a(0,0) == 0);
472 assert( m_rkI.c(m_rkI.num_stages()-1) == 1);
473 check_implicit_fsal();
474 assign_coeffs();
475 }
477 template<class ...Params>
478 void construct( Params&& ...ps)
479 {
480 //construct and swap
481 *this = ARKStep( std::forward<Params>( ps)...);
482 }
484 const ContainerType& copyable()const{ return m_kI[0];}
485
508 template< class ExplicitRHS, class ImplicitRHS, class Solver>
509 void step( const std::tuple<ExplicitRHS, ImplicitRHS, Solver>& ode, value_type t0, const ContainerType& u0, value_type& t1, ContainerType& u1, value_type dt, ContainerType& delta);
511 unsigned order() const {
512 return m_rkE.order();
513 }
515 unsigned embedded_order() const {
516 return m_rkE.order();
517 }
519 unsigned num_stages() const{
520 return m_rkE.num_stages();
521 }
522 private:
523 ButcherTableau<value_type> m_rkE, m_rkI;
524 std::vector<ContainerType> m_kE, m_kI;
525 std::vector<value_type> m_rkb, m_rkd;
526 value_type m_t1 = 1e300;
527 bool m_implicit_fsal = false;
528 void check_implicit_fsal(){
529 m_implicit_fsal = true;
530 for( unsigned i=0; i<m_rkI.num_stages(); i++)
531 if( m_rkI.a(i,0) != 0)
532 m_implicit_fsal = false;
533 }
534 void assign_coeffs()
535 {
536 m_rkb.resize( 2*m_rkI.num_stages());
537 m_rkd.resize( 2*m_rkI.num_stages());
538 for( unsigned i=0; i<m_rkI.num_stages(); i++)
539 {
540 m_rkb[2*i] = m_rkE.b(i);
541 m_rkb[2*i+1] = m_rkI.b(i);
542 m_rkd[2*i] = m_rkE.d(i);
543 m_rkd[2*i+1] = m_rkI.d(i);
544 }
545 }
546};
547
549template<class ContainerType>
550template< class Explicit, class Implicit, class Solver>
551void ARKStep<ContainerType>::step( const std::tuple<Explicit,Implicit,Solver>& ode, value_type t0, const ContainerType& u0, value_type& t1, ContainerType& u1, value_type dt, ContainerType& delta)
552{
553 unsigned s = m_rkE.num_stages();
554 value_type tu = t0;
555 //0 stage
557 if( t0 != m_t1)
558 std::get<0>(ode)(t0, u0, m_kE[0]); //freshly compute k_0
559 if( !m_implicit_fsal) // all a(i,0) == 0
560 std::get<1>(ode)(t0, u0, m_kI[0]);
561 // DO NOT HOLD POINTERS AS PRVIATE MEMBERS
562 std::vector<const ContainerType*> k_ptrs( 2*m_rkI.num_stages());
563 for( unsigned i=0; i<m_rkI.num_stages(); i++)
564 {
565 k_ptrs[2*i ] = &m_kE[i];
566 k_ptrs[2*i+1] = &m_kI[i];
567 }
568
569 for( unsigned i=1; i<s; i++)
570 {
571 std::vector<value_type> rka( 2*i);
572 for(unsigned l=0; l<i; l++)
573 {
574 rka[2*l] = m_rkE.a(i,l);
575 rka[2*l+1] = m_rkI.a(i,l);
576 }
577 tu = DG_FMA( m_rkI.c(i),dt, t0);
578 dg::blas1::copy( u0, m_kI[i]);
579 dg::blas2::gemv( dt, dg::asDenseMatrix( k_ptrs, 2*i), rka, 1., m_kI[i]);
580 value_type alpha = dt*m_rkI.a(i,i);
581 std::get<2>(ode)( alpha, tu, delta, m_kI[i]);
582 dg::blas1::axpby( 1./alpha, delta, -1./alpha, m_kI[i]);
583 std::get<0>(ode)(tu, delta, m_kE[i]);
584 }
585 m_t1 = t1 = tu;
586 //Now compute result and error estimate
587
588 dg::blas1::copy( u0, u1);
589 detail::gemm( {dt,dt}, dg::asDenseMatrix(k_ptrs), {&m_rkb, &m_rkd},
590 {1.,0.}, {&u1, &delta});
591 //make sure (t1,u1) is the last call to ex
592 std::get<0>(ode)(t1,u1,m_kE[0]);
593}
595
613template<class ContainerType>
615{
616 //MW Dirk methods cannot have stage order greater than 1
618 using container_type = ContainerType;
620 DIRKStep(){ m_kI.resize(1); }
621
633 const ContainerType& copyable):
634 m_rkI(im_tableau),
635 m_kI(m_rkI.num_stages(), copyable)
636 {
637 m_rkIb.resize(m_kI.size()), m_rkId.resize(m_kI.size());
638 for( unsigned i=0; i<m_kI.size(); i++)
639 {
640 m_rkIb[i] = m_rkI.b(i);
641 m_rkId[i] = m_rkI.d(i);
642 }
643 }
644
646 template<class ...Params>
647 void construct( Params&& ...ps)
648 {
649 //construct and swap
650 *this = DIRKStep( std::forward<Params>( ps)...);
651 }
653 const ContainerType& copyable()const{ return m_kI[0];}
654
661 template< class ImplicitRHS, class Solver>
662 void step( const std::tuple<ImplicitRHS,Solver>& ode, value_type t0, const
663 ContainerType& u0, value_type& t1, ContainerType& u1, value_type dt,
664 ContainerType& delta)
665 {
666 step( ode, t0, u0, t1, u1, dt, delta, true);
667 }
684 template< class ImplicitRHS, class Solver>
685 void step( const std::tuple<ImplicitRHS, Solver>& ode, value_type t0, const
686 ContainerType& u0, value_type& t1, ContainerType& u1, value_type dt)
687 {
688 if( !m_allocated)
689 {
690 dg::assign( m_kI[0], m_tmp);
691 m_allocated = true;
692 }
693 step( ode, t0, u0, t1, u1, dt, m_tmp, false);
694 }
696 unsigned order() const {
697 return m_rkI.order();
698 }
700 unsigned embedded_order() const {
701 return m_rkI.order();
702 }
704 unsigned num_stages() const{
705 return m_rkI.num_stages();
706 }
707
708 private:
709 template< class ImplicitRHS, class Solver>
710 void step( const std::tuple<ImplicitRHS, Solver>& ode, value_type t0, const
711 ContainerType& u0, value_type& t1, ContainerType& u1, value_type
712 dt, ContainerType& delta, bool compute_delta);
714 std::vector<ContainerType> m_kI;
715 ContainerType m_tmp;
716 std::vector<value_type> m_rkIb, m_rkId;
717 bool m_allocated = false;
718};
719
721template<class ContainerType>
722template< class ImplicitRHS, class Solver>
723void DIRKStep<ContainerType>::step( const std::tuple<ImplicitRHS,Solver>& ode, value_type t0, const ContainerType& u0, value_type& t1, ContainerType& u1, value_type dt, ContainerType& delta, bool compute_delta)
724{
725 unsigned s = m_rkI.num_stages();
726 value_type tu = t0;
727 //0 stage
728 //rhs = u0
729 tu = DG_FMA( m_rkI.c(0),dt, t0);
730 value_type alpha;
731 if( m_rkI.a(0,0) !=0 )
732 {
733 alpha = dt*m_rkI.a(0,0);
734 std::get<1>(ode)( alpha, tu, delta, u0);
735 dg::blas1::axpby( 1./alpha, delta, -1./alpha, u0, m_kI[0]);
736 }
737 else
738 std::get<0>(ode)(tu, u0, m_kI[0]);
739 std::vector<const ContainerType*> kIptr = dg::asPointers( m_kI);
740
741 for( unsigned i=1; i<s; i++)
742 {
743 tu = DG_FMA( m_rkI.c(i),dt, t0);
744 dg::blas1::copy( u0, m_kI[i]);
745 std::vector<value_type> rkIa( i);
746 for( unsigned l=0; l<i; l++)
747 rkIa[l] = m_rkI.a(i,l);
748 dg::blas2::gemv( dt, dg::asDenseMatrix(kIptr,i), rkIa, 1., m_kI[i]);
749 if( m_rkI.a(i,i) !=0 )
750 {
751 alpha = dt*m_rkI.a(i,i);
752 std::get<1>(ode)( alpha, tu, delta, m_kI[i]);
753 dg::blas1::axpby( 1./alpha, delta, -1./alpha, m_kI[i]);
754 }
755 else
756 std::get<0>(ode)(tu, delta, m_kI[i]);
757 }
758 t1 = t0 + dt;
759 //Now compute result and error estimate
760 dg::blas1::copy( u0, u1);
761 if( compute_delta)
762 detail::gemm( {dt,dt}, dg::asDenseMatrix(kIptr), {&m_rkIb, &m_rkId},
763 {1.,0.}, {&u1, &delta});
764 else
765 blas2::gemv( dt, dg::asDenseMatrix(kIptr), m_rkIb, 1., u1);
766}
768
793template<class ContainerType>
795
806template<class ContainerType>
808
841template<class ContainerType>
843{
845 using container_type = ContainerType;
847 ShuOsher(){m_u.resize(1);}
856 ShuOsher( dg::ConvertsToShuOsherTableau<value_type> tableau, const ContainerType& copyable): m_t( tableau), m_u( m_t.num_stages(), copyable), m_k(m_u)
857 { }
859 template<class ...Params>
860 void construct( Params&& ...ps)
861 {
862 //construct and swap
863 *this = ShuOsher( std::forward<Params>( ps)...);
864 }
866 const ContainerType& copyable()const{ return m_u[0];}
867
882 template<class ExplicitRHS, class Limiter>
883 void step( const std::tuple<ExplicitRHS, Limiter>& ode, value_type t0, const ContainerType& u0, value_type& t1, ContainerType& u1, value_type dt){
884 unsigned s = m_t.num_stages();
885 std::vector<value_type> ts( m_t.num_stages()+1);
886 ts[0] = t0;
887 dg::blas1::copy(u0, m_u[0]);
888 if( t0 != m_t1 ) //this is the first time we call step
889 std::get<0>(ode)(ts[0], m_u[0], m_k[0]); //freshly compute k_0
890 for( unsigned i=1; i<=s; i++)
891 {
892 dg::blas1::axpbypgz( m_t.alpha(i-1,0), m_u[0], dt*m_t.beta(i-1,0), m_k[0], 0., i==s ? u1 : m_u[i]);
893 ts[i] = m_t.alpha(i-1,0)*ts[0] + dt*m_t.beta(i-1,0);
894 for( unsigned j=1; j<i; j++)
895 {
896 //about the i-1: it is unclear to me how the ShuOsher tableau makes implicit schemes
897 dg::blas1::axpbypgz( m_t.alpha(i-1,j), m_u[j], dt*m_t.beta(i-1,j), m_k[j], 1., i==s ? u1 : m_u[i]);
898 ts[i] += m_t.alpha(i-1,j)*ts[j] + dt*m_t.beta(i-1,j);
899
900 }
901 std::get<1>(ode)( i==s ? u1 : m_u[i]);
902 if(i!=s)
903 std::get<0>(ode)(ts[i], m_u[i], m_k[i]);
904 else
905 //make sure (t1,u1) is the last call to f
906 std::get<0>(ode)(ts[i], u1, m_k[0]);
907 }
908 m_t1 = t1 = ts[s];
909 }
911 unsigned order() const {
912 return m_t.order();
913 }
915 unsigned num_stages() const{
916 return m_t.num_stages();
917 }
918 private:
920 std::vector<ContainerType> m_u, m_k;
921 value_type m_t1 = 1e300;
922};
942template<class ContainerType>
944
945
948inline bool is_same( double x, double y, double eps = 1e-15)
949{
950 return fabs(x - y) < std::max(1.0, std::max( fabs(x), fabs(y)));
951}
954inline bool is_same( float x, float y, float eps = 1e-6)
955{
956 return fabsf(x - y) < eps * std::max(1.0f, std::max( fabsf(x), fabsf(y)));
957}
961inline bool is_divisable( double a, double b, double eps = 1e-15)
962{
963 return is_same( round(a/b)*b, a);
964}
968inline bool is_divisable( float a, float b, float eps = 1e-6)
969{
970 return is_same( (float)round(a/b)*b, (float)a);
971}
972
988template<class ContainerType>
989struct SinglestepTimeloop : public aTimeloop<ContainerType>
990{
991 using container_type = ContainerType;
994 SinglestepTimeloop( ) = default;
995
1002 SinglestepTimeloop( std::function<void ( value_type, const ContainerType&,
1003 value_type&, ContainerType&, value_type)> step, value_type dt = 0 )
1004 : m_step(step), m_dt(dt){}
1005
1020 template<class Stepper, class ODE>
1021 SinglestepTimeloop( Stepper&& stepper, ODE&& ode, value_type dt = 0)
1022 {
1023 // Open/Close Principle (OCP) Software entities should be open for extension but closed for modification
1024 m_step = [=, cap = std::tuple<Stepper, ODE>(std::forward<Stepper>(stepper),
1025 std::forward<ODE>(ode)) ]( auto t0, auto y0, auto& t1, auto& y1,
1026 auto dtt) mutable
1027 {
1028 std::get<0>(cap).step( std::get<1>(cap), t0, y0, t1, y1, dtt);
1029 };
1030 m_dt = dt;
1031 }
1032
1034 template<class ...Params>
1035 void construct( Params&& ...ps)
1036 {
1037 //construct and swap
1038 *this = SinglestepTimeloop( std::forward<Params>( ps)...);
1039 }
1040
1046 void set_dt( value_type dt){ m_dt = dt;}
1047
1063 container_type& u1, unsigned steps)
1064 {
1065 set_dt( (t1-t0)/(value_type)steps );
1066 this->integrate( t0, u0, t1, u1);
1067 }
1068
1069 virtual SinglestepTimeloop* clone() const{ return new
1070 SinglestepTimeloop(*this);}
1071 private:
1072 virtual void do_integrate(value_type& t0, const container_type& u0, value_type t1, container_type& u1, enum to mode) const;
1073 std::function<void ( value_type, ContainerType, value_type&,
1074 ContainerType&, value_type)> m_step;
1075 virtual value_type do_dt( ) const { return m_dt;}
1076 value_type m_dt;
1077};
1078
1080template< class ContainerType>
1081void SinglestepTimeloop<ContainerType>::do_integrate(
1082 value_type& t_begin, const ContainerType&
1083 begin, value_type t_end, ContainerType& end,
1084 enum to mode ) const
1085{
1086 bool forward = (t_end - t_begin > 0);
1087 if( (m_dt < 0 && forward) || ( m_dt > 0 && !forward) )
1088 throw dg::Error( dg::Message(_ping_)<<"Timestep has wrong sign! dt "<<m_dt);
1089 dg::blas1::copy( begin, end);
1090 if( m_dt == 0)
1091 throw dg::Error( dg::Message(_ping_)<<"Timestep may not be zero in SinglestepTimeloop!");
1092 if( is_divisable( t_end-t_begin, m_dt))
1093 {
1094 unsigned N = (unsigned)round((t_end - t_begin)/m_dt);
1095 for( unsigned i=0; i<N; i++)
1096 m_step( t_begin, end, t_begin, end, m_dt);
1097 }
1098 else
1099 {
1100 unsigned N = (unsigned)floor( (t_end-t_begin)/m_dt);
1101 for( unsigned i=0; i<N; i++)
1102 m_step( t_begin, end, t_begin, end, m_dt);
1103 if( dg::to::exact == mode)
1104 {
1105 value_type dt_final = t_end - t_begin;
1106 m_step( t_begin, end, t_begin, end, dt_final);
1107 }
1108 else
1109 m_step( t_begin, end, t_begin, end, m_dt);
1110 }
1111 return;
1112}
1114
1116
1117} //namespace dg
1118
1119#endif //_DG_RK_
class intended for the use in throw statements
Definition: exceptions.h:83
small class holding a stringstream
Definition: exceptions.h:29
Error classes or the dg library.
#define _ping_
Definition: exceptions.h:12
void assign(const from_ContainerType &from, ContainerType &to, Params &&... ps)
Generic way to assign the contents of a from_ContainerType object to a ContainerType object optionall...
Definition: blas1.h:665
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
void subroutine(Subroutine f, ContainerType &&x, ContainerTypes &&... xs)
; Customizable and generic blas1 function
Definition: blas1.h:618
void gemv(get_value_type< ContainerType1 > alpha, MatrixType &&M, const ContainerType1 &x, get_value_type< ContainerType1 > beta, ContainerType2 &y)
; (alias for symv)
Definition: blas2.h:299
@ forward
forward derivative (cell to the right and current cell)
Definition: enums.h:98
@ y
y direction
@ x
x direction
std::vector< const ContainerType * > asPointers(const std::vector< ContainerType > &in)
Convert a vector of vectors to a vector of pointers.
Definition: densematrix.h:100
auto asDenseMatrix(const std::vector< const ContainerType * > &in)
Lightweight DenseMatrix for dg::blas2::gemv.
Definition: densematrix.h:70
Operator< real_type > delta(unsigned n)
Create the unit matrix.
Definition: operator.h:514
bool is_divisable(double a, double b, double eps=1e-15)
Definition: runge_kutta.h:961
bool is_same(double x, double y, double eps=1e-15)
Definition: runge_kutta.h:948
to
Switch for the Timeloop integrate function.
Definition: ode.h:17
@ exact
match the ending exactly
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.
Additive Runge Kutta (semi-implicit) time-step with error estimate following The ARKode library
Definition: runge_kutta.h:429
ContainerType container_type
Definition: runge_kutta.h:431
void step(const std::tuple< ExplicitRHS, ImplicitRHS, Solver > &ode, value_type t0, const ContainerType &u0, value_type &t1, ContainerType &u1, value_type dt, ContainerType &delta)
Advance one step.
get_value_type< ContainerType > value_type
the value type of the time variable (float or double)
Definition: runge_kutta.h:430
ARKStep()
No memory allocation.
Definition: runge_kutta.h:433
unsigned order() const
global order of the method given by the current Butcher Tableau
Definition: runge_kutta.h:511
ARKStep(ConvertsToButcherTableau< value_type > ex_tableau, ConvertsToButcherTableau< value_type > im_tableau, const ContainerType &copyable)
Construct with two Butcher Tableaus.
Definition: runge_kutta.h:460
void construct(Params &&...ps)
Perfect forward parameters to one of the constructors.
Definition: runge_kutta.h:478
const ContainerType & copyable() const
Return an object of same size as the object used for construction.
Definition: runge_kutta.h:484
ARKStep(std::string name, const ContainerType &copyable)
Construct with given name.
Definition: runge_kutta.h:440
unsigned embedded_order() const
global order of the embedding given by the current Butcher Tableau
Definition: runge_kutta.h:515
unsigned num_stages() const
number of stages of the method given by the current Butcher Tableau
Definition: runge_kutta.h:519
unsigned order() const
global order of accuracy for the method represented by b
Definition: tableau.h:132
real_type c(unsigned i) const
Read the c_i coefficients.
Definition: tableau.h:99
unsigned embedded_order() const
global order of accuracy for the embedded method represented by bt
Definition: tableau.h:136
real_type a(unsigned i, unsigned j) const
Read the a_ij coefficients.
Definition: tableau.h:91
real_type d(unsigned j) const
Return the coefficients for the error estimate Equivalent to b(j)-bt(j)
Definition: tableau.h:124
real_type b(unsigned j) const
Read the b_j coefficients.
Definition: tableau.h:107
unsigned num_stages() const
The number of stages s.
Definition: tableau.h:128
Convert identifiers to their corresponding dg::ButcherTableau.
Definition: tableau.h:1704
Convert identifiers to their corresponding dg::ShuOsherTableau.
Definition: tableau.h:1752
Embedded diagonally implicit Runge Kutta time-step with error estimate .
Definition: runge_kutta.h:615
DIRKStep(ConvertsToButcherTableau< value_type > im_tableau, const ContainerType &copyable)
Construct with a diagonally implicit Butcher Tableau.
Definition: runge_kutta.h:632
unsigned order() const
global order of the method given by the current Butcher Tableau
Definition: runge_kutta.h:696
void step(const std::tuple< ImplicitRHS, Solver > &ode, value_type t0, const ContainerType &u0, value_type &t1, ContainerType &u1, value_type dt, ContainerType &delta)
Advance one step with error estimate.
Definition: runge_kutta.h:662
get_value_type< ContainerType > value_type
the value type of the time variable (float or double)
Definition: runge_kutta.h:617
unsigned embedded_order() const
global order of the embedding given by the current Butcher Tableau
Definition: runge_kutta.h:700
ContainerType container_type
Definition: runge_kutta.h:618
DIRKStep()
No memory allocation.
Definition: runge_kutta.h:620
void step(const std::tuple< ImplicitRHS, Solver > &ode, value_type t0, const ContainerType &u0, value_type &t1, ContainerType &u1, value_type dt)
Advance one step ignoring error estimate and embedded method.
Definition: runge_kutta.h:685
void construct(Params &&...ps)
Perfect forward parameters to one of the constructors.
Definition: runge_kutta.h:647
unsigned num_stages() const
number of stages of the method given by the current Butcher Tableau
Definition: runge_kutta.h:704
const ContainerType & copyable() const
Return an object of same size as the object used for construction.
Definition: runge_kutta.h:653
Embedded Runge Kutta explicit time-step with error estimate .
Definition: runge_kutta.h:163
unsigned num_stages() const
number of stages of the method given by the current Butcher Tableau
Definition: runge_kutta.h:247
void step(ExplicitRHS &rhs, value_type t0, const ContainerType &u0, value_type &t1, ContainerType &u1, value_type dt, ContainerType &delta)
Advance one step with error estimate.
Definition: runge_kutta.h:200
void enable_fsal()
All subsequent calls to step method will enable the check for the first same as last property.
Definition: runge_kutta.h:194
const ContainerType & copyable() const
Return an object of same size as the object used for construction.
Definition: runge_kutta.h:189
ContainerType container_type
Definition: runge_kutta.h:165
void construct(Params &&...ps)
Perfect forward parameters to one of the constructors.
Definition: runge_kutta.h:183
ERKStep()=default
No memory allocation.
void ignore_fsal()
All subsequent calls to step method will ignore the first same as last property (useful if you want t...
Definition: runge_kutta.h:192
ERKStep(ConvertsToButcherTableau< value_type > tableau, const ContainerType &copyable)
Reserve internal workspace for the integration.
Definition: runge_kutta.h:176
get_value_type< ContainerType > value_type
the value type of the time variable (float or double)
Definition: runge_kutta.h:164
void step(ExplicitRHS &rhs, value_type t0, const ContainerType &u0, value_type &t1, ContainerType &u1, value_type dt)
Advance one step ignoring error estimate and embedded method.
Definition: runge_kutta.h:232
unsigned embedded_order() const
global order of the embedding given by the current Butcher Tableau
Definition: runge_kutta.h:243
unsigned order() const
global order of the method given by the current Butcher Tableau
Definition: runge_kutta.h:239
Definition: subroutines.h:164
EXPERIMENTAL: Filtered Embedded Runge Kutta explicit time-step with error estimate .
Definition: runge_kutta.h:277
get_value_type< ContainerType > value_type
the value type of the time variable (float or double)
Definition: runge_kutta.h:278
unsigned order() const
global order of the method given by the current Butcher Tableau
Definition: runge_kutta.h:333
FilteredERKStep()
No memory allocation.
Definition: runge_kutta.h:281
void step(const std::tuple< ExplicitRHS, Limiter > &rhs, value_type t0, const ContainerType &u0, value_type &t1, ContainerType &u1, value_type dt)
Advance one step ignoring error estimate and embedded method.
Definition: runge_kutta.h:322
void step(const std::tuple< ExplicitRHS, Limiter > &rhs, value_type t0, const ContainerType &u0, value_type &t1, ContainerType &u1, value_type dt, ContainerType &delta)
Advance one step with error estimate.
Definition: runge_kutta.h:315
void ignore_fsal()
All subsequent calls to step method will ignore the first same as last property (useful if you want t...
Definition: runge_kutta.h:306
void enable_fsal()
All subsequent calls to step method will enable the check for the first same as last property.
Definition: runge_kutta.h:308
void construct(Params &&...ps)
Perfect forward parameters to one of the constructors.
Definition: runge_kutta.h:297
unsigned embedded_order() const
global order of the embedding given by the current Butcher Tableau
Definition: runge_kutta.h:337
ContainerType container_type
Definition: runge_kutta.h:279
unsigned num_stages() const
number of stages of the method given by the current Butcher Tableau
Definition: runge_kutta.h:341
const ContainerType & copyable() const
Return an object of same size as the object used for construction.
Definition: runge_kutta.h:303
FilteredERKStep(ConvertsToButcherTableau< value_type > tableau, const ContainerType &copyable)
Reserve internal workspace for the integration.
Definition: runge_kutta.h:283
A filter that does nothing.
Definition: runge_kutta.h:119
void operator()(ContainerType1 &inout) const
Do nothing.
Definition: runge_kutta.h:127
Shu-Osher fixed-step explicit ODE integrator with Slope Limiter / Filter .
Definition: runge_kutta.h:843
ContainerType container_type
Definition: runge_kutta.h:845
void step(const std::tuple< ExplicitRHS, Limiter > &ode, value_type t0, const ContainerType &u0, value_type &t1, ContainerType &u1, value_type dt)
Advance one step.
Definition: runge_kutta.h:883
const ContainerType & copyable() const
Return an object of same size as the object used for construction.
Definition: runge_kutta.h:866
ShuOsher()
No memory allocation.
Definition: runge_kutta.h:847
ShuOsher(dg::ConvertsToShuOsherTableau< value_type > tableau, const ContainerType &copyable)
Reserve internal workspace for the integration.
Definition: runge_kutta.h:856
unsigned order() const
global order of the method given by the current Butcher Tableau
Definition: runge_kutta.h:911
get_value_type< ContainerType > value_type
the value type of the time variable (float or double)
Definition: runge_kutta.h:844
void construct(Params &&...ps)
Perfect forward parameters to one of the constructors.
Definition: runge_kutta.h:860
unsigned num_stages() const
number of stages of the method given by the current Butcher Tableau
Definition: runge_kutta.h:915
real_type beta(unsigned i, unsigned j)
Read the beta_ij coefficients.
Definition: tableau.h:257
unsigned num_stages() const
The number of stages s.
Definition: tableau.h:259
unsigned order() const
global order of accuracy for the method
Definition: tableau.h:263
real_type alpha(unsigned i, unsigned j)
Read the alpha_ij coefficients.
Definition: tableau.h:250
Integrate using a for loop and a fixed time-step.
Definition: runge_kutta.h:990
SinglestepTimeloop(Stepper &&stepper, ODE &&ode, value_type dt=0)
Bind the step function of a single step stepper.
Definition: runge_kutta.h:1021
void construct(Params &&...ps)
Perfect forward parameters to one of the constructors.
Definition: runge_kutta.h:1035
SinglestepTimeloop(std::function< void(value_type, const ContainerType &, value_type &, ContainerType &, value_type)> step, value_type dt=0)
Construct using a std::function.
Definition: runge_kutta.h:1002
virtual SinglestepTimeloop * clone() const
Abstract copy method that returns a copy of *this on the heap.
Definition: runge_kutta.h:1069
void integrate_steps(value_type t0, const container_type &u0, value_type t1, container_type &u1, unsigned steps)
Integrate differential equation with a fixed number of steps.
Definition: runge_kutta.h:1062
ContainerType container_type
Definition: runge_kutta.h:991
void set_dt(value_type dt)
Set the constant timestep to be used in the integrate functions.
Definition: runge_kutta.h:1046
dg::get_value_type< ContainerType > value_type
Definition: runge_kutta.h:992
SinglestepTimeloop()=default
no allocation
Abstract timeloop independent of stepper and ODE.
Definition: ode.h:60
void integrate(value_type t0, const ContainerType &u0, value_type t1, ContainerType &u1)
Integrate a differential equation between given bounds.
Definition: ode.h:83
ContainerType container_type
Definition: ode.h:62