00001 /***************************************************************************
00002 integrator.h - description
00003 -------------------
00004 begin : Tue Aug 12 2000
00005 copyright : (C) 2000 by Michael Peeters
00006 email : Michael.Peeters@vub.ac.be
00007 ***************************************************************************/
00008
00009 /***************************************************************************
00010 * *
00011 * This program is free software; you can redistribute it and/or modify *
00012 * it under the terms of the GNU General Public License as published by *
00013 * the Free Software Foundation; either version 2 of the License, or *
00014 * (at your option) any later version. *
00015 * *
00016 ***************************************************************************/
00017
00018 #ifndef INTEGRATOR_H
00019 #define INTEGRATOR_H
00020
00021 #include "numerictypes.h"
00022 #include "numerictraits.h"
00023 #include "vectorfunction.h"
00024 // #include "odesystem.h"
00025 #include "random.h"
00026 #include "jacobian.h"
00027
00028 namespace MODEL {
00029
00030 // predef
00031 template<integer dims, typename nelem, class NT>
00032 class ODESystem;
00033
00035 enum Integration {Euler, RungeKutta, Milshtein,Heun};
00036
00038 template<integer dims, typename nelem=number, class NT = NumericTraits<nelem,dims> >
00039 class Integrator
00040 {
00041 friend class ODESystem<dims,nelem,NT>;
00042
00043 public:
00044 typedef typename NT::number numT;
00045 typedef typename NT::vect vect;
00046 typedef typename NT::vf vf;
00047 typedef typename NT::matrix matrix;
00048
00058 Integrator(vf& d, vf& s)
00059 : deter(&d), stoch(&s){}
00060
00061 virtual ~Integrator(){};
00062
00070 virtual vect& step(vect& current, time& dt)=0;
00071
00073 vect& currentpoint(void) {return current;}
00074
00075 private:
00077 vf* get_deterministic(void)
00078 {
00079 return deter;
00080 }
00081
00082 vf* get_stochastic(void)
00083 {
00084 return stoch;
00085 }
00086
00087 protected:
00089 vf* deter;
00091 vf* stoch;
00092
00093 };
00094 //------------------------------------------------------------
00095
00100 template<integer dims, typename nelem=number, class NT = NumericTraits<nelem,dims> >
00101 class IEuler : public Integrator<dims,nelem,NT>
00102 {
00103 public:
00105 IEuler(vf& d, vf& s)
00106 : Integrator<dims,nelem,NT>(d,s) {}
00107
00109 virtual vect& step(vect& current, time& dt)
00110 {
00111 vect noise;
00112 for(counter i=0;i<dims;i++) noise[i]=rnd();
00113 vect g=(*stoch)(current);
00114 for(counter i=0;i<dims;i++) g[i]*=noise[i];
00115
00116 return current+=dt*(*deter)(current)+sqrt(dt)*g;
00117 }
00118
00119 private:
00121 Normal rnd; // will be seeded with time()
00122
00123 };
00124
00125
00126 //-------------------------------------------------------------------------
00130 template<integer dims, typename nelem=number, class NT = NumericTraits<nelem,dims> >
00131 class IRungeKutta : public Integrator<dims,nelem,NT>
00132 {
00133 public:
00134 IRungeKutta(vf& d, vf& s)
00135 : Integrator<dims,nelem,NT>(d,s) {}
00136
00137 virtual vect& step(vect& current, time& dt)
00138 {
00139 // Runge-Kutta needs 4 evaluations:
00140 // 1) at the current point
00141 // 2) at a halfway point, using the values of 1)
00142 // 3) at a halfway point, using the values of 2)
00143 // 4) at the end point, using the values of 3)
00144
00145 vect k1,k2,k3,k4;
00146 number dt2=dt/2.;
00147
00148 // Step 1)
00149
00150 k1=(*deter)(current);
00151 k1*=dt2;
00152
00153 // Step 2)
00154 // halfway in t
00155
00156 vect pos(k1);
00157 pos+=current; //halfway in u
00158
00159 k2=(*deter)(pos);
00160 k2*=dt2;
00161
00162 // Step 3)
00163 pos=k2;
00164 pos+=current;
00165
00166 k3=(*deter)(pos);
00167 k3*=dt2;
00168 // Step 4)
00169 //another half step
00170
00171 pos=k3; pos+=current; // BUG FIX: Forgot to add current point
00172 k4=(*deter)(pos);
00173 k4*=dt2;
00174
00175 // Now calculate next point. Caveat
00176 // emptor, this is very slow (compared to what it could be).
00177 return current+=(k1+2.*k2+2.*k3+k4)/3.;
00178 }
00179
00180 };
00181
00182 //----------------------------------------------------------------------
00186 template<integer dims, typename nelem=number, class NT = NumericTraits<nelem,dims> >
00187 class IMilshtein : public Integrator<dims,nelem,NT>
00188 {
00189 public:
00190 IMilshtein(vf& d, vf& s)
00191 : Integrator<dims,nelem,NT>(d,s){}
00192
00193 virtual vect& step(vect& current, time& dt)
00194 {
00195 // The Milshtein method is the basic algo for noisy problems
00196 // => Needs a random number generator !
00197
00198 vect oldcurrent(current);
00199
00200 // Deterministix q
00201 vect q=(*deter)(oldcurrent);
00202 current+=dt*q;
00203
00204 // Stochastix g
00205 // Generate numbers: noise is _NOT_ correlated between modes.
00206 vect noise;
00207 for(counter i=0;i<dims;i++) noise[i]=rnd();
00208
00209 // Additive component (Euler)
00210 number sqdt=sqrt(dt);
00211 vect g=(*stoch)(oldcurrent);
00212
00213 // Multiply each component with its noise
00214 vect ng(g);
00215 for(counter i=0;i<dims;i++) ng[i]*=noise[i];
00216
00217 // Result
00218 current+=sqdt*ng;
00219
00220 // Extra Millstein
00221 Jacobian<dims,NT> J(*stoch);
00222 matrix dgdy=J.calculate(oldcurrent,g);
00223
00224 vect dgs(0.);
00225 for(counter i=0;i<dims;i++)
00226 for (counter j=0;j<dims;j++)
00227 dgs[i]+=0.5*dgdy[i][j]*g[j]*noise[i]*noise[j];
00228
00229 current+=dt*dgs;
00230 return current;
00231 }
00232
00233 private:
00235 Normal rnd; // will be seeded with time()
00236 };
00237
00238 template<integer dims, typename nelem=number, class NT = NumericTraits<nelem,dims> >
00239 class IHeun : public Integrator<dims,nelem,NT>
00240 {
00241 public:
00242 IHeun(vf& d, vf& s)
00243 : Integrator<dims,nelem,NT>(d,s){}
00244
00245 virtual vect& step(vect& current, time& dt)
00246 {
00247 // The Heun method is the best easy algo for noisy problems
00248 // => Needs a random number generator !
00249
00250 // u is N(0,1)
00251
00252 // k=h.q(t,x)
00253 // l=sqrth.u.g(t,x)
00254 //
00255 // qavg = (1/2)*( q(t,x) + q(t+h,x+k+l) )
00256 // gavg = (1/2)*( g(t,x) + g(t+h,x+k+l) )
00257 //
00258 // Watch out: we might have to take a step for the modulators
00259 //
00260 // xnew = x + h*qavg + sqrth*u*gavg
00261
00262 vect oldcurrent(current);
00263
00264 // Some to be optimized out temps
00265 const number h=dt;
00266 const number sh=sqrt(dt);
00267
00268 vect q = (*deter)(oldcurrent);
00269 vect g = (*stoch)(oldcurrent);
00270
00271 // Generate numbers: noise is _NOT_ correlated between modes.
00272 vect u;
00273 for(counter i=0;i<dims;i++) u[i]=rnd();
00274
00279 // uneff: vect k=h*q;
00280 // uneff: vect l=sh*g;
00281
00282 // generate next point
00283 for(counter i=0;i<dims;i++)
00284 {
00285 oldcurrent[i]+=h*q[i]+sh*g[i]*u[i];
00286 // The stochastic part should be sqrt(2D) when the autocorrelation
00287 // is given by <F,F>=2D.delta; 2D is the variance (in fact)
00288 }
00289
00290 // uneff: l[i]*=u[i];
00291
00292 // uneff: oldcurrent+=k;
00293 // uneff: oldcurrent+=l;
00294
00295 // vect qavg=0.5* h * ( q + (*deter)(oldcurrent) );
00296 // vect gavg=0.5* sh * ( g + (*stoch)(oldcurrent) );
00297
00298 vect qn=(*deter)(oldcurrent);
00299 vect gn=(*stoch)(oldcurrent);
00300
00301 for(counter i=0;i<dims;i++)
00302 {
00303 current[i]+=0.5*( h*( q[i] + qn[i]) + sh*u[i]*(g[i]+gn[i]));
00304
00305 // uneff: gavg[i]*=u[i];
00306 }
00307
00308 // uneff: current += qavg;
00309 // uneff: current += gavg;
00310
00311 return current;
00312 }
00313
00314 private:
00316 Normal rnd; // will be seeded with time()
00317 };
00318
00321 template<integer dims, typename nelem=number, class NT = NumericTraits<nelem,dims> >
00322 class IHeunSimpleCorr : public Integrator<dims,nelem,NT>
00323 {
00324 public:
00325 IHeunSimpleCorr(vf& d, vf& s, vf& transform)
00326 : Integrator<dims,nelem,NT>(d,s), trans(&transform){}
00327
00328 virtual vect& step(vect& current, time& dt)
00329 {
00330 // The Heun method is the best easy algo for noisy problems
00331 // => Needs a random number generator !
00332
00333 // u is N(0,1)
00334
00335 // k=h.q(t,x)
00336 // l=sqrth.u.g(t,x)
00337 //
00338 // qavg = (1/2)*( q(t,x) + q(t+h,x+k+l) )
00339 // gavg = (1/2)*( g(t,x) + g(t+h,x+k+l) )
00340 //
00341 // Watch out: we might have to take a step for the modulators
00342 //
00343 // xnew = x + h*qavg + sqrth*u*gavg
00344
00345 vect oldcurrent(current);
00346
00347 // Some to be optimized out temps
00348 const number h=dt;
00349 const number sh=sqrt(dt);
00350
00351 vect q = (*deter)(oldcurrent);
00352 vect g = (*stoch)(oldcurrent);
00353
00354 // Generate numbers: noise is _NOT_ correlated between modes.
00355 vect u,u0;
00356 for(counter i=0;i<dims;i++) u0[i]=rnd();
00357
00358 // Do transform for eventual correlation
00359 trans->function(u,u0);
00360
00361 // uneff: vect k=h*q;
00362 // uneff: vect l=sh*g;
00363
00364 // generate next point
00365 for(counter i=0;i<dims;i++)
00366 {
00367 oldcurrent[i]+=h*q[i]+sh*g[i]*u[i];
00368 }
00369
00370 // uneff: l[i]*=u[i];
00371
00372 // uneff: oldcurrent+=k;
00373 // uneff: oldcurrent+=l;
00374
00375 // vect qavg=0.5* h * ( q + (*deter)(oldcurrent) );
00376 // vect gavg=0.5* sh * ( g + (*stoch)(oldcurrent) );
00377
00378 vect qn=(*deter)(oldcurrent);
00379 vect gn=(*stoch)(oldcurrent);
00380
00381 for(counter i=0;i<dims;i++)
00382 {
00383 current[i]+=0.5*( h*( q[i] + qn[i]) + sh*u[i]*(g[i]+gn[i]));
00384
00385 // uneff: gavg[i]*=u[i];
00386 }
00387
00388 // uneff: current += qavg;
00389 // uneff: current += gavg;
00390
00391 return current;
00392 }
00393
00394 private:
00396 Normal rnd; // will be seeded with time()
00397
00399 vf* trans;
00400 };
00401
00402 } // end namespace
00403 #endif
00404
00405 /*********************************************************************
00406 $Id: integrator.h,v 1.1.2.1 2002/06/19 13:15:47 mpeeters Exp $
00407 **********************************************************************
00408
00409 $Log: integrator.h,v $
00410 Revision 1.1.2.1 2002/06/19 13:15:47 mpeeters
00411 New integrator manipulators, Euler-Maryuama, transforms.
00412
00413 Revision 1.1 2001/05/22 10:54:55 mpeeters
00414 Moved sources and headers for libModel to model/ subdirectory, in an attempt to rationalize the source tree. This should make things "netter".
00415
00416 Revision 1.4 2001/05/21 11:53:16 mpeeters
00417 Removed Makefile.in, which is automatically generated anyway.
00418
00419 Revision 1.3 2000/09/22 08:50:03 mpeeters
00420 Changed dependencies causing trouble.
00421
00422 Revision 1.2 2000/09/15 10:26:31 mpeeters
00423 Cleaned out header and added CVS tails to files, removed superfuous
00424 @author comments, inserted dates
00425
00426 *********************************************************************/
More Info? Michael Peeters. Also, check our research website: www.alna.vub.ac.be
Last update: June 2002.