/* Steven Andrews, 1/28/97 */ /* modified 11/99 */ /* Added code called '2004 version' during 6/04. It is separate from rest of code. */ /* See documentation called dynsys doc */ /* Copyright 2003 by Steven Andrews. Permission is granted for non-commercial use of and modifications to the code. */ #include "dynsys.h" #include "Plot.h" #include "Utility.h" #include "Rn.h" #include "DiskIO.h" #include #include #include #include #include #define Pmax 10 int ODEeuler(void (*eqm)(float *,float *,float *),float *k,int p,float *u,float tf,float dt,int (*trackfn)(float,int,float *)) { float dudt[Pmax],t; int i,z=0; for(t=0;tdiff)?err:diff; } if(!eps) eps=err; if(err<=eps) { t+=dt; for(i=0;itf) dt=tf-t; if(trackfn) if((z=trackfn(t,p,u))!=0) break; (*eqm)(u,k,k1); } else dt=safe*dt*pow(eps/err,0.2); } return z; } /* k value is omega^2 (=k/m) */ void EQMsho(float *u,float *k,float *dudt) { dudt[0]=u[1]; dudt[1]=-k[0]*u[0]; } /* k values are: sigma, r, b. Suggested values: 10, 28, 8/3 */ void EQMlorenz(float *u,float *k,float *dudt) { dudt[0]=k[0]*(u[1]-u[0]); dudt[1]=k[1]*u[0]-u[1]-u[0]*u[2]; dudt[2]=u[0]*u[1]-k[2]*u[2]; } phptr phptalloc(int sp,int fp,int fs) { phptr u; int ok; ok=1; u=(phptr) malloc(sizeof(struct phpt)); ok=ok&&u; if(!ok) return 0; u->sp=sp; u->fp=fp; u->fs=fs; u->sa=u->fa=NULL; if(sp) {u->sa=allocV(sp);ok=ok&&u->sa;} if(fp&&fs) {u->fa=allocM(fs,fp);ok=ok&&u->fa;} if(ok) return u; else {phptfree(u);return 0; }} void phptfree(phptr u) { if(!u) return; if(u->sa) freeV(u->sa); if(u->fa) freeM(u->fa); free(u); } int phptsave(phptr u,char *fnames,char *fnamef) { int ok; ok=1; if(u->sp) ok=ok&&SaveData(u->sa,u->sp,1,fnames,0); if(u->fp&&u->fs) ok=ok&&SaveData(u->fa,u->fs,u->fp,fnamef,0); return ok; } phptr phptload(char *fnames,char *fnamef) { phptr u; int m,n; float *a; u=phptalloc(0,0,0); if(!u) return NULL; if(LoadData2(&a,&m,&n,fnames,0)) { u->sp=m; u->sa=a; } if(LoadData2(&a,&m,&n,fnamef,0)) { u->fs=m; u->fp=n; u->fa=a; } return u; } int ODEFeuler(void (*eqm)(phptr,void *,phptr),void *k,phptr u,float *Dt,float intpar[],int (*trackfn)(float,phptr,void *),void *trackptr) { phptr dudt; float *s,*f,*dsdt,*dfdt; float t,tf,dt; unsigned int sp,fp,fs; int i,j,z=0; sp=u->sp; fp=u->fp; fs=u->fs; s=u->sa; f=u->fa; dudt=phptalloc(sp,fp,fs); if(!dudt) return 1; dsdt=dudt->sa; dfdt=dudt->fa; dt=intpar[0]; tf=*Dt; if(trackfn) trackfn(0,u,trackptr); for(t=0;tsp; fp=u->fp; fs=u->fs; s=u->sa; f=u->fa; ut=phptalloc(sp,fp,fs); k1=phptalloc(sp,fp,fs); k2=phptalloc(sp,fp,fs); k3=phptalloc(sp,fp,fs); k4=phptalloc(sp,fp,fs); if(!(ut&&k1&&k2&&k3&&k4)) return 1; st=ut->sa; ft=ut->fa; sk1=k1->sa; fk1=k1->fa; sk2=k2->sa; fk2=k2->fa; sk3=k3->sa; fk3=k3->fa; sk4=k4->sa; fk4=k4->fa; dt=intpar[0]; dt2=dt/2.0; dt3=dt/3.0; dt6=dt/6.0; tf=*Dt; if(trackfn) trackfn(0,u,trackptr); for(t=0;tsp; fp=u->fp; fs=u->fs; s=u->sa; f=u->fa; ut=phptalloc(sp,fp,fs); k1=phptalloc(sp,fp,fs); k2=phptalloc(sp,fp,fs); k3=phptalloc(sp,fp,fs); k4=phptalloc(sp,fp,fs); k5=phptalloc(sp,fp,fs); ubig=phptalloc(sp,fp,fs); usmall=phptalloc(sp,fp,fs); uscal=phptalloc(sp,fp,fs); if(!(ut&&k1&&k2&&k3&&k4&&k5&&ubig&&usmall&&uscal)) return 1; st=ut->sa; ft=ut->fa; sk1=k1->sa; fk1=k1->fa; sk2=k2->sa; fk2=k2->fa; sk3=k3->sa; fk3=k3->fa; sk4=k4->sa; fk4=k4->fa; sk5=k5->sa; fk5=k5->fa; sbig=ubig->sa; fbig=ubig->fa; ssmall=usmall->sa; fsmall=usmall->fa; sscal=uscal->sa; fscal=uscal->fa; tf=*Dt; dt=intpar[0]; (*eqm)(u,k,k1); /* define scaling vector */ for(i=0;idiff)?err:diff; } for(j=0;jdiff)?err:diff; } if(!eps) eps=err; if(err<=eps) { t+=dt; for(i=0;itf) dt=tf-t; if(trackfn) if((z=trackfn(t,u,trackptr))!=0) break; (*eqm)(u,k,k1); } else dt=safe*dt*pow(eps/err,0.2); } *Dt=t; phptfree(ut); phptfree(k1); phptfree(k2); phptfree(k3); phptfree(k4); phptfree(k5); phptfree(ubig); phptfree(usmall); phptfree(uscal); return z; } // all derivatives are 0 void EQMFzero(phptr u,void *k,phptr dudt) { int i,j,fp; k=NULL; // to avoid warning fp=u->fp; for(i=0;isp;i++) dudt->sa[i]=0; for(j=0;jfp;j++) for(i=0;ifs;i++) dudt->fa[fp*i+j]=0; return; } // k[0] is w^2; sa[0] is position, sa[1] is velocity void EQMFsho(phptr u,void *k,phptr dudt) { dudt->sa[0]=u->sa[1]; dudt->sa[1]=-((float *)k)[0]*u->sa[0]; return; } // diffusion equation; k[0] is diffusion constant; u[row,0]=concentration; u->fp=1 void EQMFdiff(phptr u,void *k,phptr dudt) { int i,m; float alpha2; alpha2=((float *)k)[0]; m=u->fs; dudt->fa[0]=alpha2*(u->fa[1]-u->fa[0]); for(i=1;ifa[i]=alpha2*(u->fa[i+1]+u->fa[i-1]-2*u->fa[i]); dudt->fa[m-1]=alpha2*(u->fa[m-2]-u->fa[m-1]); return; } // wave equation on periodic string // k[0]=c^2; u[row,0]=position, u[row,1]=velocity; u->fp=2 void EQMFwave(phptr u,void *k,phptr dudt) { int i,m; float c2; c2=((float *)k)[0]; m=u->fs; dudt->fa[0]=u->fa[1]; dudt->fa[1]=c2*(u->fa[2]+u->fa[2*(m-1)]-2*u->fa[0]); for(i=1;ifa[2*i]=u->fa[2*i+1]; dudt->fa[2*i+1]=c2*(u->fa[2*(i+1)]+u->fa[2*(i-1)]-2*u->fa[2*i]); } dudt->fa[2*(m-1)]=u->fa[2*(m-1)+1]; dudt->fa[2*(m-1)+1]=c2*(u->fa[0]+u->fa[2*(m-2)]-2*u->fa[2*(m-1)]); return; } /* displays first two scalers */ int TKFticker(float t,phptr u,void *tkptr) { tkptr=NULL; // to avoid warning printf("%f\t%f\t%f\n",t,u->sa[0],u->sa[1]); return inkey(); } /* plots first scaler */ int TKFtimeplot(float t,phptr u,void *tkptr) { tkptr=NULL; // to avoid warning PlotPt(t,u->sa[0]); return inkey(); } /* plots first field */ /* tkptr is float[], [0]=xmin, [1]=xmax, [2]=ymin, [3]=ymax */ int TKFshowfield(float t,phptr u,void *tkptr) { int i,fp; float xmin,xmax,ymin,ymax,dx; t=0; // to avoid warning fp=u->fp; xmin=((float *)tkptr)[0]; xmax=((float *)tkptr)[1]; ymin=((float *)tkptr)[2]; ymax=((float *)tkptr)[3]; dx=(xmax-xmin)/u->fs; SetScales(xmin,xmax,ymin,ymax); PlotClear(); DrawAxes(); PlotPt(xmin,u->fa[0]); for(i=1;ifs;i++) PlotLine(xmin+i*dx,u->fa[fp*i]); return inkey(); } /******************** Start of 2004 version *****************************/ odeptr allocodestruct(int dim,int order,float *dtptr,void *systemptr,int (*eqm)(void *)) { int i; odeptr ode; if(!(order==1||order==2||order==4||order==5)) return NULL; ode=(odeptr) malloc(sizeof(struct odestruct)); if(!ode) return NULL; ode->dim=dim; ode->order=order; ode->dtptr=dtptr; ode->dtsugg=0; ode->dtmax=0; ode->eps=0; ode->systemptr=systemptr; ode->eqm=eqm; ode->state0=ode->state1=NULL; ode->scale=NULL; ode->k1=ode->k2=ode->k3=ode->k4=NULL; ode->state0=(float**) calloc(dim,sizeof(float*)); ode->state1=(float**) calloc(dim,sizeof(float*)); if(!ode->state0||!ode->state1) {freeodestruct(ode);return NULL;} for(i=0;istate0[i]=ode->state1[i]=NULL; if(order>=2) { ode->k1=(float *) calloc(dim,sizeof(float)); if(!ode->k1) {freeodestruct(ode);return NULL;} for(i=0;ik1[i]=0; } if(order>=4) { ode->k2=(float *) calloc(dim,sizeof(float)); if(!ode->k2) {freeodestruct(ode);return NULL;} for(i=0;ik2[i]=0; } if(order>=5) { ode->scale=(float*) calloc(dim,sizeof(float)); if(!ode->scale) {freeodestruct(ode);return NULL;} for(i=0;iscale[i]=1.0; ode->k3=(float *) calloc(dim,sizeof(float)); if(!ode->k3) {freeodestruct(ode);return NULL;} ode->k4=(float *) calloc(dim,sizeof(float)); if(!ode->k4) {freeodestruct(ode);return NULL;} for(i=0;ik3[i]=ode->k4[i]=0; } return ode; } void freeodestruct(odeptr ode) { if(!ode) return; if(ode->state0) free(ode->state0); if(ode->state1) free(ode->state1); if(ode->scale) free(ode->scale); if(ode->k1) free(ode->k1); if(ode->k2) free(ode->k2); free(ode); return; } int runodestruct(odeptr ode) { int dim,order,i,er; static int redoctr=0; float **s0,**s1,dt,dt2,dt3,dt4,dt6,dt12; float *k1,*k2,*k3,*k4; float diff,diffmax,*scale; void *systemptr; dim=ode->dim; order=ode->order; systemptr=ode->systemptr; s0=ode->state0; s1=ode->state1; if(order==1) { // *** ORDER 1 *** dt=*ode->dtptr; for(i=0;ieqm)(systemptr))) return er; for(i=0;idtptr; k1=ode->k1; dt2=dt/2.0; for(i=0;ieqm)(systemptr))) return er; for(i=0;ieqm)(systemptr))) return er; for(i=0;idtptr; k1=ode->k1; k2=ode->k2; dt2=dt/2.0; dt3=dt/3.0; dt6=dt/6.0; for(i=0;ieqm)(systemptr))) return er; for(i=0;ieqm)(systemptr))) return er; for(i=0;ieqm)(systemptr))) return er; for(i=0;ieqm)(systemptr))) return er; for(i=0;idtsugg>0?ode->dtsugg:*ode->dtptr; if(ode->dtmax&&dt>ode->dtmax) dt=ode->dtmax; scale=ode->scale; k1=ode->k1; k2=ode->k2; k3=ode->k3; k4=ode->k4; dt2=dt/2.0; dt3=dt/3.0; dt4=dt/4.0; dt6=dt/6.0; dt12=dt/12.0; for(i=0;ieqm)(systemptr))) return er; // *** start of dt step for(i=0;ieqm)(systemptr))) return er; for(i=0;ieqm)(systemptr))) return er; for(i=0;ieqm)(systemptr))) return er; for(i=0;ieqm)(systemptr))) return er; for(i=0;ieqm)(systemptr))) return er; for(i=0;ieqm)(systemptr))) return er; for(i=0;ieqm)(systemptr))) return er; // start of second dt2 step for(i=0;ieqm)(systemptr))) return er; for(i=0;ieqm)(systemptr))) return er; for(i=0;ieqm)(systemptr))) return er; for(i=0;idtptr=dt; diffmax=0; for(i=0;idiff)) break; if(diff>diffmax) diffmax=diff; } if(!(diff+1.0>diff)) { ode->dtsugg=dt*0.5; for(i=0;idtsugg=dt*1.1; else if(!ode->eps) ode->eps=diffmax; else if(diffmax<=ode->eps) ode->dtsugg=dt*0.95*pow(ode->eps/diffmax,0.25); else { ode->dtsugg=dt*0.95*pow(ode->eps/diffmax,0.2); for(i=0;idtmax&&ode->dtsugg>ode->dtmax) ode->dtsugg=ode->dtmax; redoctr=0; return 0; } /* Example program for 2004 routines */ typedef struct shostate { float position[2]; float velocity[2]; float omega2; float gamma; float time; } *shostateptr; int odestructsho(void *system); int odestructsho(void *system) { shostateptr sys; sys=(shostateptr) system; sys->position[0]=sys->velocity[1]; sys->velocity[0]=-sys->omega2*sys->position[1]-2.0*sys->gamma*sys->velocity[1]; return 0; } int odestructexample(void) { odeptr ode; float dt; shostateptr sys; int er,order; order=5; dt=0.2; sys=(shostateptr)malloc(sizeof(struct shostate)); if(!sys) return 0; sys->position[0]=sys->position[1]=1.0; sys->velocity[0]=sys->velocity[1]=-0.1; sys->omega2=0.5; sys->gamma=0.1; sys->time=0; ode=allocodestruct(2,order,&dt,(void*)sys,&odestructsho); if(!ode) return 0; ode->state0[0]=&sys->position[0]; ode->state1[0]=&sys->position[1]; ode->state0[1]=&sys->velocity[0]; ode->state1[1]=&sys->velocity[1]; if(order==5) ode->dtmax=1.0/sqrt(sys->omega2); // this keeps amplitude and phase good to at least t=500 for(;sys->time<500;sys->time+=dt) { printf("t,x,v: %f %e %e\n",sys->time,sys->position[0],sys->velocity[0]); er=runodestruct(ode); if(er) break; } freeodestruct(ode); return 0; }