diff --git a/Makefile b/Makefile index 6dde9cf72e8a8006f2f80b1885d1c923dc98b3bd..7bdc4a4672c81648abeb04a7709273a332431c4f 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ PROJNAME = miscmaths USRINCFLAGS = -I${INC_NEWMAT} -I${INC_PROB} -I${INC_ZLIB} USRLDFLAGS = -L${LIB_NEWMAT} -L${LIB_PROB} -L${LIB_ZLIB} -OBJS = miscmaths.o optimise.o miscprob.o kernel.o histogram.o base2z.o t2z.o f2z.o volume.o volumeseries.o minimize.o cspline.o sparse_matrix.o sparsefn.o +OBJS = miscmaths.o optimise.o miscprob.o kernel.o histogram.o base2z.o t2z.o f2z.o volume.o volumeseries.o minimize.o cspline.o sparse_matrix.o sparsefn.o rungekutta.o #OBJS = miscmaths.o optimise.o miscprob.o kernel.o histogram.o base2z.o t2z.o f2z.o volume.o volumeseries.o minimize.o cspline.o LIBS = -lutils -lnewmat -lprob -lm diff --git a/rungekutta.cc b/rungekutta.cc new file mode 100644 index 0000000000000000000000000000000000000000..8a14621bec93f6b6805b21dea6e0dff9cda3d5c2 --- /dev/null +++ b/rungekutta.cc @@ -0,0 +1,167 @@ +/* rungekutta.cc + + Mark Woolrich, FMRIB Image Analysis Group + + Copyright (C) 2002 University of Oxford */ + +/* CCOPYRIGHT */ + +#include "rungekutta.h" + +namespace MISCMATHS { + + +void rk(ColumnVector& ret, const ColumnVector& y, const ColumnVector& dy, float x, float h, const Derivative& deriv,const ColumnVector& paramvalues) +{ + Tracer tr("rk"); + + float hh=h*0.5; + float xh=x+hh; + + //first step + ColumnVector yt=y+hh*dy; + + //second step + ColumnVector dyt = deriv.evaluate(xh,yt,paramvalues); + yt=y+hh*dyt; + + //third step + ColumnVector dym = deriv.evaluate(xh,yt,paramvalues); + yt=y+h*dym; + dym=dym+dyt; + + //fourth step + dyt = deriv.evaluate(x+h,yt,paramvalues); + + //addup + ret = y+h*(dy+dyt+2*dym)/6; +} + +void rkqc(ColumnVector& y, float& x, float& hnext, ColumnVector& dy, float htry, float eps, const Derivative& deriv,const ColumnVector& paramvalues) +{ + Tracer tr("rkqc"); + + float xsav = x; + ColumnVector dysav = dy; + ColumnVector ysav = y; + float h = htry; + float hdid; + ColumnVector ytemp; + + while(true) + { + // take 2 1/2 step sizes + + // first 1/2 step + float hh=h*0.5; + + rk(ytemp,ysav,dysav,xsav,hh,deriv,paramvalues); + + // second 1/2 step + x=xsav+hh; + dy = deriv.evaluate(x,ytemp,paramvalues); + rk(y,ytemp,dysav,xsav,hh,deriv,paramvalues); + x=xsav+h; + if(x==xsav) cerr << "step size too small" << endl; + + // take large step size + rk(ytemp,ysav,dysav,xsav,h,deriv,paramvalues); + + // eval accuracy + float errmax = 0.0; + for(int i=1; i<=y.Nrows(); i++) + { + //errmax=max(abs((y-ytemp)./y)); + + float tmp = fabs((y(i)-ytemp(i))/y(i)); + if(tmp > errmax) errmax = tmp; + } + + errmax=errmax/eps; + + if(errmax <=1.0) + { + // step OK, compute step size for next step + hdid=h; + + if(errmax>6e-4) + hnext=h*std::exp(-0.2*std::log(errmax)); + else + hnext=4*h; + + break; + } + else + { + // step too large, + h=h*std::exp(-0.25*std::log(errmax)); + } + } + + y = y+(y-ytemp)/15; +} + +void runge_kutta(Matrix& yp, ColumnVector& xp, ColumnVector& hp, const ColumnVector& ystart, float x1, float x2, float eps, float hmin, const Derivative& deriv,const ColumnVector& paramvalues) +{ + Tracer tr("runge_kutta"); + + int MAXSTEP=1000; + + ColumnVector y = ystart; + + float x=x1; + xp.ReSize(MAXSTEP,1); + xp = 0; + xp(1) =x1; + + float h=hp(1); + hp.ReSize(MAXSTEP,1); + hp = 0; + + yp.ReSize(MAXSTEP,y.Nrows()); + yp = 0; + + int kout=1; + + ColumnVector dy; + + for(int k=1; k <= MAXSTEP; k++) + { + dy = deriv.evaluate(x,y,paramvalues); + + // store results: + xp(kout)=x; + yp.Row(kout)=y; + hp(kout)=h; + + kout=kout+1; + + // stop overshoot of step past x2: + if((x+h-x2)*(x+h-x1)>0) h=x2-x; + + float hnext = 0.0; + rkqc(y,x,hnext,dy,h,eps,deriv,paramvalues); + + if((x-x2)*(x2-x1) >= 0.0) + { + xp(kout)=x; + yp.Row(kout)=y; + hp(kout)=h; + //kout=kout+1; + + xp = xp.Rows(1,kout); + yp = yp.Rows(1,kout); + + return; + } + else + { + if(hnext<=hmin) cerr << "step size too small" << endl; + h=hnext; + } + + } + cerr << "too many steps" << endl; +} + +} diff --git a/rungekutta.h b/rungekutta.h new file mode 100644 index 0000000000000000000000000000000000000000..2f57123e8dabbd19029781768185ce879aff1747 --- /dev/null +++ b/rungekutta.h @@ -0,0 +1,48 @@ +/* rungekutta.h + + Mark Woolrich - FMRIB Image Analysis Group + + Copyright (C) 2002 University of Oxford */ + +/* COPYRIGHT */ + +#if !defined(rungekutta_h) +#define rungekutta_h + +#include <iostream> +#include <fstream> +#include <string> +#include <vector> + +#include "newimage/newimageall.h" + +using namespace NEWIMAGE; + +namespace MISCMATHS { + +class Derivative +{ +public: + Derivative(int pny) : ny(pny), dy(pny) {} + + // x is time point to evaluate at + // y is state variables + // paramvalues are "constants" in the diff eqn + virtual const ColumnVector& evaluate(float x,const ColumnVector& y,const ColumnVector& paramvalues) const = 0; + + virtual ~Derivative(){}; + +protected: + int ny; + mutable ColumnVector dy; +}; + +void rk(ColumnVector& ret, const ColumnVector& y, const ColumnVector& dy, float x, float h, const Derivative& deriv,const ColumnVector& paramvalues); + +void rkqc(ColumnVector& y, float& x, float& hnext, ColumnVector& dy, float htry, float eps, const Derivative& deriv,const ColumnVector& paramvalues); + +void runge_kutta(Matrix& yp, ColumnVector& xp, ColumnVector& hp, const ColumnVector& ystart, float x1, float x2, float eps, float hmin, const Derivative& deriv,const ColumnVector& paramvalues); + +} + +#endif