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.