Heidelberg Educational Numerics Library Version 0.27 (from 15 March 2021)
ode.hh
Go to the documentation of this file.
1// -*- tab-width: 4; indent-tabs-mode: nil -*-
2#ifndef HDNUM_ODE_HH
3#define HDNUM_ODE_HH
4
5#include<vector>
6#include "newton.hh"
7
12namespace hdnum {
13
22 template<class M>
23 class EE
24 {
25 public:
27 typedef typename M::size_type size_type;
28
30 typedef typename M::time_type time_type;
31
33 typedef typename M::number_type number_type;
34
36 EE (const M& model_)
37 : model(model_), u(model.size()), f(model.size())
38 {
39 model.initialize(t,u);
40 dt = 0.1;
41 }
42
45 {
46 dt = dt_;
47 }
48
50 void step ()
51 {
52 model.f(t,u,f); // evaluate model
53 u.update(dt,f); // advance state
54 t += dt; // advance time
55 }
56
59 {
60 t = t_;
61 u = u_;
62 }
63
66 {
67 return u;
68 }
69
72 {
73 return t;
74 }
75
78 {
79 return dt;
80 }
81
84 {
85 return 1;
86 }
87
88 private:
89 const M& model;
90 time_type t, dt;
93 };
94
103 template<class M>
105 {
106 public:
108 typedef typename M::size_type size_type;
109
111 typedef typename M::time_type time_type;
112
114 typedef typename M::number_type number_type;
115
118 : model(model_), u(model.size()), w(model.size()), k1(model.size()), k2(model.size())
119 {
120 c2 = 0.5;
121 a21 = 0.5;
122 b2 = 1.0;
123 model.initialize(t,u);
124 dt = 0.1;
125 }
126
129 {
130 dt = dt_;
131 }
132
134 void step ()
135 {
136 // stage 1
137 model.f(t,u,k1);
138
139 // stage 2
140 w = u;
141 w.update(dt*a21,k1);
142 model.f(t+c2*dt,w,k2);
143
144 // final
145 u.update(dt*b2,k2);
146 t += dt;
147 }
148
151 {
152 t = t_;
153 u = u_;
154 }
155
158 {
159 return u;
160 }
161
164 {
165 return t;
166 }
167
170 {
171 return dt;
172 }
173
176 {
177 return 2;
178 }
179
180 private:
181 const M& model;
182 time_type t, dt;
183 time_type c2,a21,b2;
186 };
187
188
197 template<class M>
198 class Heun2
199 {
200 public:
202 typedef typename M::size_type size_type;
203
205 typedef typename M::time_type time_type;
206
208 typedef typename M::number_type number_type;
209
211 Heun2 (const M& model_)
212 : model(model_), u(model.size()), w(model.size()), k1(model.size()), k2(model.size())
213 {
214 c2 = 1.0;
215 a21 = 1.0;
216 b1 = 0.5;
217 b2 = 0.5;
218 model.initialize(t,u);
219 dt = 0.1;
220 }
221
224 {
225 dt = dt_;
226 }
227
229 void step ()
230 {
231 // stage 1
232 model.f(t,u,k1);
233
234 // stage 2
235 w = u;
236 w.update(dt*a21,k1);
237 model.f(t+c2*dt,w,k2);
238
239 // final
240 u.update(dt*b1,k1);
241 u.update(dt*b2,k2);
242 t += dt;
243 }
244
247 {
248 t = t_;
249 u = u_;
250 }
251
254 {
255 return u;
256 }
257
260 {
261 return t;
262 }
263
266 {
267 return dt;
268 }
269
272 {
273 return 2;
274 }
275
276 private:
277 const M& model;
278 time_type t, dt;
279 time_type c2,a21,b1,b2;
282 };
283
284
293 template<class M>
294 class Heun3
295 {
296 public:
298 typedef typename M::size_type size_type;
299
301 typedef typename M::time_type time_type;
302
304 typedef typename M::number_type number_type;
305
307 Heun3 (const M& model_)
308 : model(model_), u(model.size()), w(model.size()), k1(model.size()),
309 k2(model.size()), k3(model.size())
310 {
311 c2 = time_type(1.0)/time_type(3.0);
312 c3 = time_type(2.0)/time_type(3.0);
313 a21 = time_type(1.0)/time_type(3.0);
314 a32 = time_type(2.0)/time_type(3.0);
315 b1 = 0.25;
316 b2 = 0.0;
317 b3 = 0.75;
318 model.initialize(t,u);
319 dt = 0.1;
320 }
321
324 {
325 dt = dt_;
326 }
327
329 void step ()
330 {
331 // stage 1
332 model.f(t,u,k1);
333
334 // stage 2
335 w = u;
336 w.update(dt*a21,k1);
337 model.f(t+c2*dt,w,k2);
338
339 // stage 3
340 w = u;
341 w.update(dt*a32,k2);
342 model.f(t+c3*dt,w,k3);
343
344 // final
345 u.update(dt*b1,k1);
346 u.update(dt*b3,k3);
347 t += dt;
348 }
349
352 {
353 t = t_;
354 u = u_;
355 }
356
359 {
360 return u;
361 }
362
365 {
366 return t;
367 }
368
371 {
372 return dt;
373 }
374
377 {
378 return 3;
379 }
380
381 private:
382 const M& model;
383 time_type t, dt;
384 time_type c2,c3,a21,a31,a32,b1,b2,b3;
386 Vector<number_type> k1,k2,k3;
387 };
388
397 template<class M>
398 class Kutta3
399 {
400 public:
402 typedef typename M::size_type size_type;
403
405 typedef typename M::time_type time_type;
406
408 typedef typename M::number_type number_type;
409
411 Kutta3 (const M& model_)
412 : model(model_), u(model.size()), w(model.size()), k1(model.size()),
413 k2(model.size()), k3(model.size())
414 {
415 c2 = 0.5;
416 c3 = 1.0;
417 a21 = 0.5;
418 a31 = -1.0;
419 a32 = 2.0;
420 b1 = time_type(1.0)/time_type(6.0);
421 b2 = time_type(4.0)/time_type(6.0);
422 b3 = time_type(1.0)/time_type(6.0);
423 model.initialize(t,u);
424 dt = 0.1;
425 }
426
429 {
430 dt = dt_;
431 }
432
434 void step ()
435 {
436 // stage 1
437 model.f(t,u,k1);
438
439 // stage 2
440 w = u;
441 w.update(dt*a21,k1);
442 model.f(t+c2*dt,w,k2);
443
444 // stage 3
445 w = u;
446 w.update(dt*a31,k1);
447 w.update(dt*a32,k2);
448 model.f(t+c3*dt,w,k3);
449
450 // final
451 u.update(dt*b1,k1);
452 u.update(dt*b2,k2);
453 u.update(dt*b3,k3);
454 t += dt;
455 }
456
459 {
460 t = t_;
461 u = u_;
462 }
463
466 {
467 return u;
468 }
469
472 {
473 return t;
474 }
475
478 {
479 return dt;
480 }
481
484 {
485 return 3;
486 }
487
488 private:
489 const M& model;
490 time_type t, dt;
491 time_type c2,c3,a21,a31,a32,b1,b2,b3;
493 Vector<number_type> k1,k2,k3;
494 };
495
504 template<class M>
506 {
507 public:
509 typedef typename M::size_type size_type;
510
512 typedef typename M::time_type time_type;
513
515 typedef typename M::number_type number_type;
516
519 : model(model_), u(model.size()), w(model.size()), k1(model.size()),
520 k2(model.size()), k3(model.size()), k4(model.size())
521 {
522 c2 = 0.5;
523 c3 = 0.5;
524 c4 = 1.0;
525 a21 = 0.5;
526 a32 = 0.5;
527 a43 = 1.0;
528 b1 = time_type(1.0)/time_type(6.0);
529 b2 = time_type(2.0)/time_type(6.0);
530 b3 = time_type(2.0)/time_type(6.0);
531 b4 = time_type(1.0)/time_type(6.0);
532 model.initialize(t,u);
533 dt = 0.1;
534 }
535
538 {
539 dt = dt_;
540 }
541
543 void step ()
544 {
545 // stage 1
546 model.f(t,u,k1);
547
548 // stage 2
549 w = u;
550 w.update(dt*a21,k1);
551 model.f(t+c2*dt,w,k2);
552
553 // stage 3
554 w = u;
555 w.update(dt*a32,k2);
556 model.f(t+c3*dt,w,k3);
557
558 // stage 4
559 w = u;
560 w.update(dt*a43,k3);
561 model.f(t+c4*dt,w,k4);
562
563 // final
564 u.update(dt*b1,k1);
565 u.update(dt*b2,k2);
566 u.update(dt*b3,k3);
567 u.update(dt*b4,k4);
568 t += dt;
569 }
570
573 {
574 t = t_;
575 u = u_;
576 }
577
580 {
581 return u;
582 }
583
586 {
587 return t;
588 }
589
592 {
593 return dt;
594 }
595
598 {
599 return 4;
600 }
601
602 private:
603 const M& model;
604 time_type t, dt;
605 time_type c2,c3,c4,a21,a32,a43,b1,b2,b3,b4;
607 Vector<number_type> k1,k2,k3,k4;
608 };
609
614 template<class M>
615 class RKF45
616 {
617 public:
619 typedef typename M::size_type size_type;
620
622 typedef typename M::time_type time_type;
623
625 typedef typename M::number_type number_type;
626
628 RKF45 (const M& model_)
629 : model(model_), u(model.size()), w(model.size()), ww(model.size()), k1(model.size()),
630 k2(model.size()), k3(model.size()), k4(model.size()), k5(model.size()), k6(model.size()),
631 steps(0), rejected(0)
632 {
633 TOL = time_type(0.0001);
634 rho = time_type(0.8);
635 alpha = time_type(0.25);
636 beta = time_type(4.0);
637 dt_min = 1E-12;
638
639 c2 = time_type(1.0)/time_type(4.0);
640 c3 = time_type(3.0)/time_type(8.0);
641 c4 = time_type(12.0)/time_type(13.0);
642 c5 = time_type(1.0);
643 c6 = time_type(1.0)/time_type(2.0);
644
645 a21 = time_type(1.0)/time_type(4.0);
646
647 a31 = time_type(3.0)/time_type(32.0);
648 a32 = time_type(9.0)/time_type(32.0);
649
650 a41 = time_type(1932.0)/time_type(2197.0);
651 a42 = time_type(-7200.0)/time_type(2197.0);
652 a43 = time_type(7296.0)/time_type(2197.0);
653
654 a51 = time_type(439.0)/time_type(216.0);
655 a52 = time_type(-8.0);
656 a53 = time_type(3680.0)/time_type(513.0);
657 a54 = time_type(-845.0)/time_type(4104.0);
658
659 a61 = time_type(-8.0)/time_type(27.0);
660 a62 = time_type(2.0);
661 a63 = time_type(-3544.0)/time_type(2565.0);
662 a64 = time_type(1859.0)/time_type(4104.0);
663 a65 = time_type(-11.0)/time_type(40.0);
664
665 b1 = time_type(25.0)/time_type(216.0);
666 b2 = time_type(0.0);
667 b3 = time_type(1408.0)/time_type(2565.0);
668 b4 = time_type(2197.0)/time_type(4104.0);
669 b5 = time_type(-1.0)/time_type(5.0);
670
671 bb1 = time_type(16.0)/time_type(135.0);
672 bb2 = time_type(0.0);
673 bb3 = time_type(6656.0)/time_type(12825.0);
674 bb4 = time_type(28561.0)/time_type(56430.0);
675 bb5 = time_type(-9.0)/time_type(50.0);
676 bb6 = time_type(2.0)/time_type(55.0);
677
678 model.initialize(t,u);
679 dt = 0.1;
680 }
681
684 {
685 dt = dt_;
686 }
687
690 {
691 TOL = TOL_;
692 }
693
695 void step ()
696 {
697 steps++;
698
699 // stage 1
700 model.f(t,u,k1);
701
702 // stage 2
703 w = u;
704 w.update(dt*a21,k1);
705 model.f(t+c2*dt,w,k2);
706
707 // stage 3
708 w = u;
709 w.update(dt*a31,k1);
710 w.update(dt*a32,k2);
711 model.f(t+c3*dt,w,k3);
712
713 // stage 4
714 w = u;
715 w.update(dt*a41,k1);
716 w.update(dt*a42,k2);
717 w.update(dt*a43,k3);
718 model.f(t+c4*dt,w,k4);
719
720 // stage 5
721 w = u;
722 w.update(dt*a51,k1);
723 w.update(dt*a52,k2);
724 w.update(dt*a53,k3);
725 w.update(dt*a54,k4);
726 model.f(t+c5*dt,w,k5);
727
728 // stage 6
729 w = u;
730 w.update(dt*a61,k1);
731 w.update(dt*a62,k2);
732 w.update(dt*a63,k3);
733 w.update(dt*a64,k4);
734 w.update(dt*a65,k5);
735 model.f(t+c6*dt,w,k6);
736
737 // compute order 4 approximation
738 w = u;
739 w.update(dt*b1,k1);
740 w.update(dt*b2,k2);
741 w.update(dt*b3,k3);
742 w.update(dt*b4,k4);
743 w.update(dt*b5,k5);
744
745 // compute order 5 approximation
746 ww = u;
747 ww.update(dt*bb1,k1);
748 ww.update(dt*bb2,k2);
749 ww.update(dt*bb3,k3);
750 ww.update(dt*bb4,k4);
751 ww.update(dt*bb5,k5);
752 ww.update(dt*bb6,k6);
753
754 // estimate local error
755 w -= ww;
756 time_type error(norm(w));
757 time_type dt_opt(dt*pow(rho*TOL/error,0.2));
758 dt_opt = std::min(beta*dt,std::max(alpha*dt,dt_opt));
759 //std::cout << "est. error=" << error << " dt_opt=" << dt_opt << std::endl;
760
761 if (error<=TOL)
762 {
763 t += dt;
764 u = ww;
765 dt = dt_opt;
766 }
767 else
768 {
769 rejected++;
770 dt = dt_opt;
771 if (dt>dt_min) step();
772 }
773 }
774
777 {
778 return u;
779 }
780
783 {
784 return t;
785 }
786
789 {
790 return dt;
791 }
792
795 {
796 return 5;
797 }
798
800 void get_info () const
801 {
802 std::cout << "RE: steps=" << steps << " rejected=" << rejected << std::endl;
803 }
804
805 private:
806 const M& model;
807 time_type t, dt;
808 time_type TOL,rho,alpha,beta,dt_min;
809 time_type c2,c3,c4,c5,c6;
810 time_type a21,a31,a32,a41,a42,a43,a51,a52,a53,a54,a61,a62,a63,a64,a65;
811 time_type b1,b2,b3,b4,b5; // 4th order
812 time_type bb1,bb2,bb3,bb4,bb5,bb6; // 5th order
813 Vector<number_type> u,w,ww;
814 Vector<number_type> k1,k2,k3,k4,k5,k6;
815 mutable size_type steps, rejected;
816 };
817
818
824 template<class M, class S>
825 class RE
826 {
827 public:
829 typedef typename M::size_type size_type;
830
832 typedef typename M::time_type time_type;
833
835 typedef typename M::number_type number_type;
836
838 RE (const M& model_, S& solver_)
839 : model(model_), solver(solver_), u(model.size()),
840 wlow(model.size()), whigh(model.size()), ww(model.size()),
841 steps(0), rejected(0)
842 {
843 model.initialize(t,u); // initialize state
844 dt = 0.1; // set initial time step
845 two_power_m = 1.0;
846 for (size_type i=0; i<solver.get_order(); i++)
847 two_power_m *= 2.0;
848 TOL = time_type(0.0001);
849 rho = time_type(0.8);
850 alpha = time_type(0.25);
851 beta = time_type(4.0);
852 dt_min = 1E-12;
853 }
854
857 {
858 dt = dt_;
859 }
860
863 {
864 TOL = TOL_;
865 }
866
868 void step ()
869 {
870 // count steps done
871 steps++;
872
873 // do 1 step with 2*dt
874 time_type H(2.0*dt);
875 solver.set_state(t,u);
876 solver.set_dt(H);
877 solver.step();
878 wlow = solver.get_state();
879
880 // do 2 steps with dt
881 solver.set_state(t,u);
882 solver.set_dt(dt);
883 solver.step();
884 solver.step();
885 whigh = solver.get_state();
886
887 // estimate local error
888 ww = wlow;
889 ww -= whigh;
890 time_type error(norm(ww)/(pow(H,1.0+solver.get_order())*(1.0-1.0/two_power_m)));
891 time_type dt_opt(pow(rho*TOL/error,1.0/((time_type)solver.get_order())));
892 dt_opt = std::min(beta*dt,std::max(alpha*dt,dt_opt));
893 //std::cout << "est. error=" << error << " dt_opt=" << dt_opt << std::endl;
894
895 if (dt<=dt_opt)
896 {
897 t += H;
898 u = whigh;
899 u *= two_power_m;
900 u -= wlow;
901 u /= two_power_m-1.0;
902 dt = dt_opt;
903 }
904 else
905 {
906 rejected++;
907 dt = dt_opt;
908 if (dt>dt_min) step();
909 }
910 }
911
914 {
915 return u;
916 }
917
920 {
921 return t;
922 }
923
926 {
927 return dt;
928 }
929
932 {
933 return solver.get_order()+1;
934 }
935
937 void get_info () const
938 {
939 std::cout << "RE: steps=" << steps << " rejected=" << rejected << std::endl;
940 }
941
942 private:
943 const M& model;
944 S& solver;
945 time_type t, dt;
946 time_type two_power_m;
947 Vector<number_type> u,wlow,whigh,ww;
948 time_type TOL,rho,alpha,beta,dt_min;
949 mutable size_type steps, rejected;
950 };
951
952
962 template<class M, class S>
963 class IE
964 {
966 // h_n f(t_n, y_n) - y_n + y_{n-1} = 0
967 class NonlinearProblem
968 {
969 public:
971 typedef typename M::size_type size_type;
972
974 typedef typename M::number_type number_type;
975
977 NonlinearProblem (const M& model_, const Vector<number_type>& yold_,
978 typename M::time_type tnew_, typename M::time_type dt_)
979 : model(model_), yold(yold_), tnew(tnew_), dt(dt_)
980 {}
981
983 std::size_t size () const
984 {
985 return model.size();
986 }
987
989 void F (const Vector<number_type>& x, Vector<number_type>& result) const
990 {
991 model.f(tnew,x,result);
992 result *= dt;
993 result -= x;
994 result += yold;
995 }
996
998 void F_x (const Vector<number_type>& x, DenseMatrix<number_type>& result) const
999 {
1000 model.f_x(tnew,x,result);
1001 result *= dt;
1002 for (size_type i=0; i<model.size(); i++) result[i][i] -= number_type(1.0);
1003 }
1004
1005 void set_tnew_dt (typename M::time_type tnew_, typename M::time_type dt_)
1006 {
1007 tnew = tnew_;
1008 dt = dt_;
1009 }
1010
1011 private:
1012 const M& model;
1013 const Vector<number_type>& yold;
1014 typename M::time_type tnew;
1015 typename M::time_type dt;
1016 };
1017
1018 public:
1020 typedef typename M::size_type size_type;
1021
1023 typedef typename M::time_type time_type;
1024
1026 typedef typename M::number_type number_type;
1027
1029 IE (const M& model_, const S& newton_)
1030 : verbosity(0), model(model_), newton(newton_), u(model.size()), unew(model.size())
1031 {
1032 model.initialize(t,u);
1033 dt = dtmax = 0.1;
1034 }
1035
1038 {
1039 dt = dtmax = dt_;
1040 }
1041
1044 {
1045 verbosity = verbosity_;
1046 }
1047
1049 void step ()
1050 {
1051 if (verbosity>=2)
1052 std::cout << "IE: step" << " t=" << t << " dt=" << dt << std::endl;
1053 NonlinearProblem nlp(model,u,t+dt,dt);
1054 bool reduced = false;
1055 error = false;
1056 while (1)
1057 {
1058 unew = u;
1059 newton.solve(nlp,unew);
1060 if (newton.has_converged())
1061 {
1062 u = unew;
1063 t += dt;
1064 if (!reduced && dt<dtmax-1e-13)
1065 {
1066 dt = std::min(2.0*dt,dtmax);
1067 if (verbosity>0)
1068 std::cout << "IE: increasing time step to " << dt << std::endl;
1069 }
1070 return;
1071 }
1072 else
1073 {
1074 if (dt<1e-12)
1075 {
1076 HDNUM_ERROR("time step too small in implicit Euler");
1077 error = true;
1078 break;
1079 }
1080 dt *= 0.5;
1081 reduced = true;
1082 nlp.set_tnew_dt(t+dt,dt);
1083 if (verbosity>0) std::cout << "IE: reducing time step to " << dt << std::endl;
1084 }
1085 }
1086 }
1087
1089 bool get_error () const
1090 {
1091 return error;
1092 }
1093
1096 {
1097 t = t_;
1098 u = u_;
1099 }
1100
1103 {
1104 return u;
1105 }
1106
1109 {
1110 return t;
1111 }
1112
1115 {
1116 return dt;
1117 }
1118
1121 {
1122 return 1;
1123 }
1124
1126 void get_info () const
1127 {
1128 }
1129
1130 private:
1131 size_type verbosity;
1132 const M& model;
1133 const S& newton;
1134 time_type t, dt, dtmax;
1135 number_type reduction;
1136 size_type linesearchsteps;
1139 mutable bool error;
1140 };
1141
1152 template<class M, class S>
1153 class DIRK
1154 {
1155 public:
1156
1158 typedef typename M::size_type size_type;
1159
1161 typedef typename M::time_type time_type;
1162
1164 typedef typename M::number_type number_type;
1165
1168
1169 private:
1170
1173 static ButcherTableau initTableau(const std::string method)
1174 {
1175 if(method.find("Implicit Euler") != std::string::npos){
1176 ButcherTableau butcher(2,2,0.0);
1177 butcher[1][1] = 1;
1178 butcher[0][1] = 1;
1179 butcher[0][0] = 1;
1180
1181 return butcher;
1182 }
1183 else if(method.find("Alexander") != std::string::npos){
1184 ButcherTableau butcher(3,3,0.0);
1185 const number_type alpha = 1. - sqrt(2.)/2.;
1186 butcher[0][0] = alpha;
1187 butcher[0][1] = alpha;
1188
1189 butcher[1][0] = 1.;
1190 butcher[1][1] = 1. - alpha;
1191 butcher[1][2] = alpha;
1192
1193 butcher[2][1] = 1. - alpha;
1194 butcher[2][2] = alpha;
1195
1196 return butcher;
1197 }
1198 else if(method.find("Crouzieux") != std::string::npos){
1199 ButcherTableau butcher(3,3,0.0);
1200 const number_type beta = 1./2./sqrt(3);
1201 butcher[0][0] = 0.5 + beta;
1202 butcher[0][1] = 0.5 + beta;
1203
1204 butcher[1][0] = 0.5 - beta;
1205 butcher[1][1] = -1. / sqrt(3);
1206 butcher[1][2] = 0.5 + beta;
1207
1208 butcher[2][1] = 0.5;
1209 butcher[2][2] = 0.5;
1210
1211 return butcher;
1212 }
1213 else if(method.find("Midpoint Rule") != std::string::npos){
1214 ButcherTableau butcher(2,2,0.0);
1215 butcher[0][0] = 0.5;
1216 butcher[0][1] = 0.5;
1217 butcher[1][1] = 1;
1218
1219 return butcher;
1220 }
1221 else if(method.find("Fractional Step Theta") != std::string::npos){
1222 ButcherTableau butcher(5,5,0.0);
1223 const number_type theta = 1 - sqrt(2.)/2.;
1224 const number_type alpha = 2. - sqrt(2.);
1225 const number_type beta = 1. - alpha;
1226 butcher[1][0] = theta;
1227 butcher[1][1] = beta * theta;
1228 butcher[1][2] = alpha * theta;
1229
1230 butcher[2][0] = 1.-theta;
1231 butcher[2][1] = beta * theta;
1232 butcher[2][2] = alpha * (1.-theta);
1233 butcher[2][3] = alpha * theta;
1234
1235 butcher[3][0] = 1.;
1236 butcher[3][1] = beta * theta;
1237 butcher[3][2] = alpha * (1.-theta);
1238 butcher[3][3] = (alpha + beta) * theta;
1239 butcher[3][4] = alpha * theta;
1240
1241 butcher[4][1] = beta * theta;
1242 butcher[4][2] = alpha * (1.-theta);
1243 butcher[4][3] = (alpha + beta) * theta;
1244 butcher[4][4] = alpha * theta;
1245
1246 return butcher;
1247 }
1248 else{
1249 HDNUM_ERROR("Order not available for Runge Kutta solver.");
1250 }
1251 }
1252
1253 static int initOrder(const std::string method)
1254 {
1255 if(method.find("Implicit Euler") != std::string::npos){
1256 return 1;
1257 }
1258 else if(method.find("Alexander") != std::string::npos){
1259 return 2;
1260 }
1261 else if(method.find("Crouzieux") != std::string::npos){
1262 return 3;
1263 }
1264 else if(method.find("Midpoint Rule") != std::string::npos){
1265 return 2;
1266 }
1267 else if(method.find("Fractional Step Theta") != std::string::npos){
1268 return 2;
1269 }
1270 else{
1271 HDNUM_ERROR("Order not available for Runge Kutta solver.");
1272 }
1273 }
1274
1275
1277 // h_n f(t_n, y_n) - y_n + y_{n-1} = 0
1278 class NonlinearProblem
1279 {
1280 public:
1282 typedef typename M::size_type size_type;
1283
1285 typedef typename M::number_type number_type;
1286
1288 NonlinearProblem (const M& model_, const Vector<number_type>& yold_,
1289 typename M::time_type told_, typename M::time_type dt_,
1290 const ButcherTableau & butcher_, const int rk_step_,
1291 const std::vector< Vector<number_type> > & k_)
1292 : model(model_), yold(yold_), told(told_),
1293 dt(dt_), butcher(butcher_), rk_step(rk_step_), k_old(model.size(),0)
1294 {
1295 for(int i=0; i<rk_step; ++i)
1296 k_old.update(butcher[rk_step][1+i] * dt, k_[i]);
1297 }
1298
1300 std::size_t size () const
1301 {
1302 return model.size();
1303 }
1304
1306 void F (const Vector<number_type>& x, Vector<number_type>& result) const
1307 {
1308 result = k_old;
1309
1310 Vector<number_type> current_z(x);
1311 current_z.update(1.,yold);
1312
1313 const number_type tnew = told + butcher[rk_step][0] * dt;
1314
1315 Vector<number_type> current_k(model.size(),0.);
1316 model.f(tnew,current_z,current_k);
1317 result.update(butcher[rk_step][rk_step+1] * dt, current_k);
1318
1319 result.update(-1.,x);
1320 }
1321
1323 void F_x (const Vector<number_type>& x, DenseMatrix<number_type>& result) const
1324 {
1325 const number_type tnew = told + butcher[rk_step][0] * dt;
1326
1327 Vector<number_type> current_z(x);
1328 current_z.update(1.,yold);
1329
1330 model.f_x(tnew,current_z,result);
1331
1332 result *= dt * butcher[rk_step][rk_step+1];
1333
1334 for (size_type i=0; i<model.size(); i++) result[i][i] -= number_type(1.0);
1335 }
1336
1337 void set_told_dt (typename M::time_type told_, typename M::time_type dt_)
1338 {
1339 told = told_;
1340 dt = dt_;
1341 }
1342
1343 private:
1344 const M& model;
1345 const Vector<number_type>& yold;
1346 typename M::time_type told;
1347 typename M::time_type dt;
1348 const ButcherTableau & butcher;
1349 const int rk_step;
1350 Vector<number_type> k_old;
1351 };
1352
1353 public:
1354
1357 DIRK (const M& model_, const S& newton_, const ButcherTableau & butcher_, const int order_)
1358 : verbosity(0), butcher(butcher_), model(model_), newton(newton_),
1359 u(model.size()), order(order_)
1360 {
1361 model.initialize(t,u);
1362 dt = dtmax = 0.1;
1363 }
1364
1367 DIRK (const M& model_, const S& newton_, const std::string method)
1368 : verbosity(0), butcher(initTableau(method)), model(model_), newton(newton_), u(model.size()),
1369 order(initOrder(method))
1370 {
1371 model.initialize(t,u);
1372 dt = dtmax = 0.1;
1373 }
1374
1375
1378 {
1379 dt = dtmax = dt_;
1380 }
1381
1384 {
1385 verbosity = verbosity_;
1386 }
1387
1389 void step ()
1390 {
1391
1392 const size_type R = butcher.colsize()-1;
1393
1394 bool reduced = false;
1395 error = false;
1396 if(verbosity>=2)
1397 std::cout << "DIRK: step to" << " t+dt=" << t+dt << " dt=" << dt << std::endl;
1398
1399 while (1)
1400 {
1401 bool converged = true;
1402
1403 // Perform R Runge-Kutta steps
1404 std::vector< Vector<number_type> > k;
1405 for(size_type i=0; i<R; ++i) {
1406 if (verbosity>=2)
1407 std::cout << "DIRK: step nr "<< i << std::endl;
1408
1409 Vector<number_type> current_z(model.size(),0.0);
1410
1411 // Set starting value of k_i
1412 // model.f(t,u,current_k);
1413
1414 // Solve nonlinear problem
1415 NonlinearProblem nlp(model,u,t,dt,butcher,i,k);
1416
1417 newton.solve(nlp,current_z);
1418
1419 converged = converged && newton.has_converged();
1420 if(!converged)
1421 break;
1422
1423 current_z.update(1., u);
1424 const number_type t_i = t + butcher[i][0] * dt;
1425 Vector<number_type>current_k(model.size(),0.);
1426 model.f(t_i,current_z,current_k);
1427
1428 k.push_back( current_k );
1429 }
1430
1431 if (converged)
1432 {
1433 if(verbosity >= 2)
1434 std::cout << "DIRK finished"<< std::endl;
1435
1436 // Update to new solution
1437 for(size_type i=0; i<R; ++i)
1438 u.update(dt*butcher[R][1+i],k[i]);
1439
1440 t += dt;
1441 if (!reduced && dt<dtmax-1e-13)
1442 {
1443 dt = std::min(2.0*dt,dtmax);
1444 if (verbosity>0)
1445 std::cout << "DIRK: increasing time step to " << dt << std::endl;
1446 }
1447 return;
1448 }
1449 else
1450 {
1451 if (dt<1e-12)
1452 {
1453 HDNUM_ERROR("time step too small in implicit Euler");
1454 error = true;
1455 break;
1456 }
1457 dt *= 0.5;
1458 reduced = true;
1459 if (verbosity>0) std::cout << "DIRK: reducing time step to " << dt << std::endl;
1460 }
1461 }
1462 }
1463
1465 bool get_error () const
1466 {
1467 return error;
1468 }
1469
1472 {
1473 t = t_;
1474 u = u_;
1475 }
1476
1479 {
1480 return u;
1481 }
1482
1485 {
1486 return t;
1487 }
1488
1491 {
1492 return dt;
1493 }
1494
1497 {
1498 return order;
1499 }
1500
1502 void get_info () const
1503 {
1504 }
1505
1506 private:
1507 size_type verbosity;
1508 const DenseMatrix<number_type> butcher;
1509 const M& model;
1510 const S& newton;
1511 time_type t, dt, dtmax;
1512 number_type reduction;
1513 size_type linesearchsteps;
1515 int order;
1516 mutable bool error;
1517 };
1518
1520 template<class T, class N>
1521 inline void gnuplot (const std::string& fname, const std::vector<T> t, const std::vector<Vector<N> > u)
1522 {
1523 std::fstream f(fname.c_str(),std::ios::out);
1524 for (typename std::vector<T>::size_type n=0; n<t.size(); n++)
1525 {
1526 f << std::scientific << std::showpoint
1527 << std::setprecision(16) << t[n];
1528 for (typename Vector<N>::size_type i=0; i<u[n].size(); i++)
1529 f << " " << std::scientific << std::showpoint
1530 << std::setprecision(u[n].precision()) << u[n][i];
1531 f << std::endl;
1532 }
1533 f.close();
1534 }
1535
1537 template<class T, class N>
1538 inline void gnuplot (const std::string& fname, const std::vector<T> t, const std::vector<Vector<N> > u, const std::vector<T> dt)
1539 {
1540 std::fstream f(fname.c_str(),std::ios::out);
1541 for (typename std::vector<T>::size_type n=0; n<t.size(); n++)
1542 {
1543 f << std::scientific << std::showpoint
1544 << std::setprecision(16) << t[n];
1545 for (typename Vector<N>::size_type i=0; i<u[n].size(); i++)
1546 f << " " << std::scientific << std::showpoint
1547 << std::setprecision(u[n].precision()) << u[n][i];
1548 f << " " << std::scientific << std::showpoint
1549 << std::setprecision(16) << dt[n];
1550 f << std::endl;
1551 }
1552 f.close();
1553 }
1554
1555} // namespace hdnum
1556
1557#endif
Implementation of a general Diagonal Implicit Runge-Kutta method.
Definition ode.hh:1154
M::number_type number_type
export number_type
Definition ode.hh:1164
void step()
do one step
Definition ode.hh:1389
void set_dt(time_type dt_)
set time step for subsequent steps
Definition ode.hh:1377
time_type get_time() const
get current time
Definition ode.hh:1484
DIRK(const M &model_, const S &newton_, const ButcherTableau &butcher_, const int order_)
Definition ode.hh:1357
DenseMatrix< number_type > ButcherTableau
the type of a Butcher tableau
Definition ode.hh:1167
void get_info() const
print some information
Definition ode.hh:1502
bool get_error() const
get current state
Definition ode.hh:1465
void set_state(time_type t_, const Vector< number_type > &u_)
set current state
Definition ode.hh:1471
M::size_type size_type
export size_type
Definition ode.hh:1158
M::time_type time_type
export time_type
Definition ode.hh:1161
time_type get_dt() const
get dt used in last step (i.e. to compute current state)
Definition ode.hh:1490
void set_verbosity(size_type verbosity_)
set verbosity level
Definition ode.hh:1383
DIRK(const M &model_, const S &newton_, const std::string method)
Definition ode.hh:1367
size_type get_order() const
return consistency order of the method
Definition ode.hh:1496
const Vector< number_type > & get_state() const
get current state
Definition ode.hh:1478
Class with mathematical matrix operations.
Definition densematrix.hh:33
void update(const REAL s, const DenseMatrix &B)
Scaled update of a Matrix.
Definition densematrix.hh:489
size_t colsize() const
get number of columns of the matrix
Definition densematrix.hh:153
Explicit Euler method as an example for an ODE solver.
Definition ode.hh:24
time_type get_time() const
get current time
Definition ode.hh:71
EE(const M &model_)
constructor stores reference to the model
Definition ode.hh:36
M::number_type number_type
export number_type
Definition ode.hh:33
M::size_type size_type
export size_type
Definition ode.hh:27
void step()
do one step
Definition ode.hh:50
M::time_type time_type
export time_type
Definition ode.hh:30
void set_state(time_type t_, const Vector< number_type > &u_)
set current state
Definition ode.hh:58
void set_dt(time_type dt_)
set time step for subsequent steps
Definition ode.hh:44
const Vector< number_type > & get_state() const
get current state
Definition ode.hh:65
size_type get_order() const
return consistency order of the method
Definition ode.hh:83
time_type get_dt() const
get dt used in last step (i.e. to compute current state)
Definition ode.hh:77
Heun method (order 2 with 2 stages)
Definition ode.hh:199
M::size_type size_type
export size_type
Definition ode.hh:202
void set_dt(time_type dt_)
set time step for subsequent steps
Definition ode.hh:223
const Vector< number_type > & get_state() const
get current state
Definition ode.hh:253
size_type get_order() const
return consistency order of the method
Definition ode.hh:271
time_type get_dt() const
get dt used in last step (i.e. to compute current state)
Definition ode.hh:265
void step()
do one step
Definition ode.hh:229
M::time_type time_type
export time_type
Definition ode.hh:205
void set_state(time_type t_, const Vector< number_type > &u_)
set current state
Definition ode.hh:246
time_type get_time() const
get current time
Definition ode.hh:259
Heun2(const M &model_)
constructor stores reference to the model
Definition ode.hh:211
M::number_type number_type
export number_type
Definition ode.hh:208
Heun method (order 3 with 3 stages)
Definition ode.hh:295
const Vector< number_type > & get_state() const
get current state
Definition ode.hh:358
void set_dt(time_type dt_)
set time step for subsequent steps
Definition ode.hh:323
M::time_type time_type
export time_type
Definition ode.hh:301
M::number_type number_type
export number_type
Definition ode.hh:304
time_type get_dt() const
get dt used in last step (i.e. to compute current state)
Definition ode.hh:370
void set_state(time_type t_, const Vector< number_type > &u_)
set current state
Definition ode.hh:351
size_type get_order() const
return consistency order of the method
Definition ode.hh:376
Heun3(const M &model_)
constructor stores reference to the model
Definition ode.hh:307
M::size_type size_type
export size_type
Definition ode.hh:298
time_type get_time() const
get current time
Definition ode.hh:364
void step()
do one step
Definition ode.hh:329
Implicit Euler using Newton's method to solve nonlinear system.
Definition ode.hh:964
M::number_type number_type
export number_type
Definition ode.hh:1026
IE(const M &model_, const S &newton_)
constructor stores reference to the model
Definition ode.hh:1029
void set_dt(time_type dt_)
set time step for subsequent steps
Definition ode.hh:1037
time_type get_dt() const
get dt used in last step (i.e. to compute current state)
Definition ode.hh:1114
void set_verbosity(size_type verbosity_)
set verbosity level
Definition ode.hh:1043
M::time_type time_type
export time_type
Definition ode.hh:1023
bool get_error() const
get current state
Definition ode.hh:1089
const Vector< number_type > & get_state() const
get current state
Definition ode.hh:1102
void get_info() const
print some information
Definition ode.hh:1126
void step()
do one step
Definition ode.hh:1049
void set_state(time_type t_, const Vector< number_type > &u_)
set current state
Definition ode.hh:1095
size_type get_order() const
return consistency order of the method
Definition ode.hh:1120
time_type get_time() const
get current time
Definition ode.hh:1108
M::size_type size_type
export size_type
Definition ode.hh:1020
Kutta method (order 3 with 3 stages)
Definition ode.hh:399
M::time_type time_type
export time_type
Definition ode.hh:405
M::number_type number_type
export number_type
Definition ode.hh:408
const Vector< number_type > & get_state() const
get current state
Definition ode.hh:465
void set_state(time_type t_, const Vector< number_type > &u_)
set current state
Definition ode.hh:458
time_type get_dt() const
get dt used in last step (i.e. to compute current state)
Definition ode.hh:477
void step()
do one step
Definition ode.hh:434
size_type get_order() const
return consistency order of the method
Definition ode.hh:483
M::size_type size_type
export size_type
Definition ode.hh:402
time_type get_time() const
get current time
Definition ode.hh:471
void set_dt(time_type dt_)
set time step for subsequent steps
Definition ode.hh:428
Kutta3(const M &model_)
constructor stores reference to the model
Definition ode.hh:411
Modified Euler method (order 2 with 2 stages)
Definition ode.hh:105
void step()
do one step
Definition ode.hh:134
M::time_type time_type
export time_type
Definition ode.hh:111
size_type get_order() const
return consistency order of the method
Definition ode.hh:175
void set_state(time_type t_, const Vector< number_type > &u_)
set current state
Definition ode.hh:150
const Vector< number_type > & get_state() const
get current state
Definition ode.hh:157
time_type get_dt() const
get dt used in last step (i.e. to compute current state)
Definition ode.hh:169
M::size_type size_type
export size_type
Definition ode.hh:108
M::number_type number_type
export number_type
Definition ode.hh:114
ModifiedEuler(const M &model_)
constructor stores reference to the model
Definition ode.hh:117
void set_dt(time_type dt_)
set time step for subsequent steps
Definition ode.hh:128
time_type get_time() const
get current time
Definition ode.hh:163
Adaptive one-step method using Richardson extrapolation.
Definition ode.hh:826
M::number_type number_type
export number_type
Definition ode.hh:835
void get_info() const
print some information
Definition ode.hh:937
RE(const M &model_, S &solver_)
constructor stores reference to the model
Definition ode.hh:838
const Vector< number_type > & get_state() const
get current state
Definition ode.hh:913
void step()
do one step
Definition ode.hh:868
time_type get_dt() const
get dt used in last step (i.e. to compute current state)
Definition ode.hh:925
void set_TOL(time_type TOL_)
set tolerance for adaptive computation
Definition ode.hh:862
size_type get_order() const
return consistency order of the method
Definition ode.hh:931
void set_dt(time_type dt_)
set time step for subsequent steps
Definition ode.hh:856
time_type get_time() const
get current time
Definition ode.hh:919
M::size_type size_type
export size_type
Definition ode.hh:829
M::time_type time_type
export time_type
Definition ode.hh:832
Adaptive Runge-Kutta-Fehlberg method.
Definition ode.hh:616
size_type get_order() const
return consistency order of the method
Definition ode.hh:794
M::time_type time_type
export time_type
Definition ode.hh:622
const Vector< number_type > & get_state() const
get current state
Definition ode.hh:776
time_type get_time() const
get current time
Definition ode.hh:782
time_type get_dt() const
get dt used in last step (i.e. to compute current state)
Definition ode.hh:788
void get_info() const
print some information
Definition ode.hh:800
RKF45(const M &model_)
constructor stores reference to the model
Definition ode.hh:628
M::size_type size_type
export size_type
Definition ode.hh:619
void set_dt(time_type dt_)
set time step for subsequent steps
Definition ode.hh:683
void step()
do one step
Definition ode.hh:695
void set_TOL(time_type TOL_)
set tolerance for adaptive computation
Definition ode.hh:689
M::number_type number_type
export number_type
Definition ode.hh:625
classical Runge-Kutta method (order 4 with 4 stages)
Definition ode.hh:506
void set_dt(time_type dt_)
set time step for subsequent steps
Definition ode.hh:537
void set_state(time_type t_, const Vector< number_type > &u_)
set current state
Definition ode.hh:572
size_type get_order() const
return consistency order of the method
Definition ode.hh:597
void step()
do one step
Definition ode.hh:543
M::size_type size_type
export size_type
Definition ode.hh:509
RungeKutta4(const M &model_)
constructor stores reference to the model
Definition ode.hh:518
time_type get_dt() const
get dt used in last step (i.e. to compute current state)
Definition ode.hh:591
const Vector< number_type > & get_state() const
get current state
Definition ode.hh:579
M::number_type number_type
export number_type
Definition ode.hh:515
M::time_type time_type
export time_type
Definition ode.hh:512
time_type get_time() const
get current time
Definition ode.hh:585
std::size_t size_type
Type used for array indices.
Definition vector.hh:34
Vector & update(const REAL alpha, const Vector &y)
Update vector by addition of a scaled vector (x += a y )
Definition vector.hh:201
Newton's method with line search.