-
Notifications
You must be signed in to change notification settings - Fork 105
/
Copy pathodeint.h
executable file
·128 lines (126 loc) · 3.21 KB
/
odeint.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
struct Output {
Int kmax;
Int nvar;
Int nsave;
bool dense;
Int count;
Doub x1,x2,xout,dxout;
VecDoub xsave;
MatDoub ysave;
Output() : kmax(-1),dense(false),count(0) {}
Output(const Int nsavee) : kmax(500),nsave(nsavee),count(0),xsave(kmax) {
dense = nsave > 0 ? true : false;
}
void init(const Int neqn, const Doub xlo, const Doub xhi) {
nvar=neqn;
if (kmax == -1) return;
ysave.resize(nvar,kmax);
if (dense) {
x1=xlo;
x2=xhi;
xout=x1;
dxout=(x2-x1)/nsave;
}
}
void resize() {
Int kold=kmax;
kmax *= 2;
VecDoub tempvec(xsave);
xsave.resize(kmax);
for (Int k=0; k<kold; k++)
xsave[k]=tempvec[k];
MatDoub tempmat(ysave);
ysave.resize(nvar,kmax);
for (Int i=0; i<nvar; i++)
for (Int k=0; k<kold; k++)
ysave[i][k]=tempmat[i][k];
}
template <class Stepper>
void save_dense(Stepper &s, const Doub xout, const Doub h) {
if (count == kmax) resize();
for (Int i=0;i<nvar;i++)
ysave[i][count]=s.dense_out(i,xout,h);
xsave[count++]=xout;
}
void save(const Doub x, VecDoub_I &y) {
if (kmax <= 0) return;
if (count == kmax) resize();
for (Int i=0;i<nvar;i++)
ysave[i][count]=y[i];
xsave[count++]=x;
}
template <class Stepper>
void out(const Int nstp,const Doub x,VecDoub_I &y,Stepper &s,const Doub h) {
if (!dense)
throw("dense output not set in Output!");
if (nstp == -1) {
save(x,y);
xout += dxout;
} else {
while ((x-xout)*(x2-x1) > 0.0) {
save_dense(s,xout,h);
xout += dxout;
}
}
}
};
template<class Stepper>
struct Odeint {
static const Int MAXSTP=50000;
Doub EPS;
Int nok;
Int nbad;
Int nvar;
Doub x1,x2,hmin;
bool dense;
VecDoub y,dydx;
VecDoub &ystart;
Output &out;
typename Stepper::Dtype &derivs;
Stepper s;
Int nstp;
Doub x,h;
Odeint(VecDoub_IO &ystartt,const Doub xx1,const Doub xx2,
const Doub atol,const Doub rtol,const Doub h1,
const Doub hminn,Output &outt,typename Stepper::Dtype &derivss);
void integrate();
};
template<class Stepper>
Odeint<Stepper>::Odeint(VecDoub_IO &ystartt, const Doub xx1, const Doub xx2,
const Doub atol, const Doub rtol, const Doub h1, const Doub hminn,
Output &outt,typename Stepper::Dtype &derivss) : nvar(ystartt.size()),
y(nvar),dydx(nvar),ystart(ystartt),x(xx1),nok(0),nbad(0),
x1(xx1),x2(xx2),hmin(hminn),dense(outt.dense),out(outt),derivs(derivss),
s(y,dydx,x,atol,rtol,dense) {
EPS=numeric_limits<Doub>::epsilon();
h=SIGN(h1,x2-x1);
for (Int i=0;i<nvar;i++) y[i]=ystart[i];
out.init(s.neqn,x1,x2);
}
template<class Stepper>
void Odeint<Stepper>::integrate() {
derivs(x,y,dydx);
if (dense)
out.out(-1,x,y,s,h);
else
out.save(x,y);
for (nstp=0;nstp<MAXSTP;nstp++) {
if ((x+h*1.0001-x2)*(x2-x1) > 0.0)
h=x2-x;
s.step(h,derivs);
if (s.hdid == h) ++nok; else ++nbad;
if (dense)
out.out(nstp,x,y,s,s.hdid);
else
out.save(x,y);
if ((x-x2)*(x2-x1) >= 0.0) {
for (Int i=0;i<nvar;i++) ystart[i]=y[i];
if (out.kmax > 0 && abs(out.xsave[out.count-1]-x2) > 100.0*abs(x2)*EPS)
out.save(x,y);
return;
}
if (abs(s.hnext) <= hmin) throw("Step size too small in Odeint");
h=s.hnext;
}
throw("Too many steps in routine Odeint");
}