#include #include #include #include #include "xpplim.h" #include "getvar.h" #define MY_DBL_EPS 5e-16 /* this is a new (Summer 1995) addition to XPP that allows one to do things like delta functions and other discontinuous stuff. The conditions are set up as part of the "ODE" file: global sign condition {event1;....;eventn} global sign {condition} {event1;....;eventn} the {} and ; are required for the events condition is anything that when it evaluates to 0 means the flag should be set. The sign is like in Poincare maps, thus let C(t1) and C(t2) be the value of the condition at t1 and t2. sign = 0 ==> just find when C(t)=0 sign = 1 ==> C(t1)<0 C(t2)>0 sign = -1==> C(t1)>0 C(t2)<0 To get the time of the event, we use linear interpolation: t* = t1 + (t2-t1) ------- (0-C(t1)) C(t2)-C(t1) This yields the variables, etc at that time Now what are the events: They are of the form: name = expression the variable is replaced by the value of Note that there may be several "conditions" defined and that these must also be checked to see if they have been switched and in what order. This is particularly true for "delta" function type things. Here is a simple example -- the kicked cycle: dx/dt = y dy/dy = -x -c y if y=0 and y goes from pos to neg then x=x+b here is how it would work: global -1 y {x=x+b} Here is Tysons model: global -1 u-.2 {m=.5*m} */ /* type =0 variable type =1 parameter type =2 output type =3 halt */ #define MAX_EVENTS 20 /* this is the maximum number of events per flag */ #define MAXFLAG 500 extern char upar_names[MAXPAR][11]; typedef struct { double f0,f1; double tstar; int lhs[MAX_EVENTS]; double vrhs[MAX_EVENTS]; char lhsname[MAX_EVENTS][11]; char *rhs[MAX_EVENTS]; int *comrhs[MAX_EVENTS]; char *cond; int *comcond; int sign,nevents; int hit,type[MAX_EVENTS]; int anypars; } FLAG; #define IC 2 #define PARAM 1 /* #define Set_ivar(a,b) variables[(a)]=(b) */ FLAG flag[MAXFLAG]; int NFlags=0; double STOL=1.e-10; extern double variables[]; extern int NVAR; double evaluate(); add_global(cond,sign,rest) char *cond; int sign; char *rest; { char temp[256]; int nevents,ii,index,k,l,lt,j=NFlags; char ch; if(NFlags>=MAXFLAG){ printf("Too many global conditions\n"); return(1); } l=strlen(cond); flag[j].cond=(char *) malloc(l+1); strcpy(flag[j].cond,cond); nevents=0; flag[j].lhsname[0][0]=0; k=0; l=strlen(rest); for(ii=0;ii is not a valid variable/parameter name \n", flag[j].lhsname[i]); return(1); } } } else{ flag[j].lhs[i]=index; flag[j].type[i]=1; flag[j].anypars=1; } } else { flag[j].lhs[i]=index; flag[j].type[i]=0; } if(add_expr(flag[j].rhs[i],command,&nc)){ printf("Illegal event %s for global %s\n", flag[j].rhs[i],flag[j].cond); return(1); } flag[j].comrhs[i]=(int *)malloc(sizeof(int)*(nc+1)); for(k=0;k<=nc;k++) flag[j].comrhs[i][k]=command[k]; } } return(0); } /* here is the shell code for a loop around integration step */ one_flag_step(yold,ynew,istart,told,tnew,neq,s ) double *yold,*ynew,*tnew,*s,told; int *istart,neq; { double temp,dt=*tnew-told; double f0,f1,tol,tolmin=1e-10; double smin=2; int sign,i,j,in,ncycle=0,newhit,nevents; if(NFlags==0)return(0); for(i=0;i=0.0))||((f0<=0.0)&&(f1>0.0)))&&tol>tolmin){ flag[i].hit=ncycle+1; flag[i].tstar=f0/(f0-f1); /* printf(" tstar=%g \n",flag[i].tstar); */ } break; case -1: if(f0>0.0&&f1<=0.0&&tol>tolmin){ flag[i].hit=ncycle+1; flag[i].tstar=f0/(f0-f1); } break; case 0: /* if(f1==0.0){ */ if(fabs(f1)tolmin){ flag[i].hit=ncycle+1; flag[i].tstar=f0/(f0-f1); } */ break; } if(smin>flag[i].tstar)smin=flag[i].tstar; } /* printf("smin = %g \n",smin); */ if(smin1.0)return(0); *tnew=told+dt*smin; SETVAR(0,*tnew); for(i=0;i0))send_output(ynew,*tnew); if((flag[i].type[j]==3)&&(flag[i].vrhs[j]>0))send_halt(ynew,*tnew); } } /* printf(" increment it ... \n"); */ } if(flag[i].anypars){ evaluate_derived(); redraw_params(); } } } /* printf(" %g %g %g \n",*tnew,ynew[0],ynew[1]); */ for(i=0;i0)continue; /* already hit so dont do anything */ f1=flag[i].f1; sign=flag[i].sign; f0=flag[i].f0; tol=fabs(f1-f0); /* printf(" call2 flag=%d %g %g -- %g \n",i,f0,f1,smin); */ switch(sign){ case 1: if(f0<=0.0&&f1>=0.0&&tol>tolmin){ flag[i].tstar=smin; flag[i].hit=ncycle+1; newhit=1; } break; case -1: if(f0>=0.0&&f1<=0.0&&tol>tolmin){ flag[i].tstar=smin; flag[i].hit=ncycle+1; newhit=1; } break; case 0: if(f0*f1<=0&&(f1!=0||f0!=0)&&tol>tolmin){ flag[i].tstar=smin; flag[i].hit=ncycle+1; newhit=1; } } } if(newhit==0)break; } *s=smin; return(1); } /* here are the ODE drivers */ one_flag_step_symp(y,dt,work,neq,tim,istart) double dt,*tim; double *y,*work; int neq,*istart; { double yold[MAXODE],told; int i,hit; double s,dtt=dt; int nstep=0; while(1){ for(i=0;i(NFlags+2)){ printf(" Working too hard?? "); printf("smin=%g\n",s); break; } } } one_flag_step_euler(y,dt,work,neq,tim,istart) double dt,*tim; double *y,*work; int neq,*istart; { double yold[MAXODE],told; int i,hit; double s,dtt=dt; int nstep=0; while(1){ for(i=0;i(NFlags+2)){ printf(" Working too hard?? "); printf("smin=%g\n",s); break; } } } one_flag_step_discrete(y,dt,work,neq,tim,istart) double dt,*tim; double *y,*work; int neq,*istart; { double yold[MAXODE],told; int i,hit; double s,dtt=dt; int nstep=0; while(1){ for(i=0;i(NFlags+2)){ printf(" Working too hard?? "); printf("smin=%g\n",s); break; } } } one_flag_step_heun(y,dt,yval,neq,tim,istart) double dt,*tim,*yval[2]; double *y; int neq,*istart; { double yold[MAXODE],told; int i,hit; double s,dtt=dt; int nstep=0; while(1){ for(i=0;i(NFlags+2)){ printf(" Working too hard? "); printf(" smin=%g\n",s); break; } } } one_flag_step_rk4(y,dt,yval,neq,tim,istart) double dt,*tim; double *y,*yval[3]; int neq,*istart; { double yold[MAXODE],told; int i,hit; double s,dtt=dt; int nstep=0; while(1){ for(i=0;i(NFlags+2)){ printf(" Working too hard?"); printf("smin=%g\n",s); /* printflaginfo(); */ break; } } } printflaginfo() { int i; for(i=0;i(NFlags+2)){ printf(" Working too hard? "); printf("smin=%g\n",s); break; } } return 0; } one_flag_step_rosen(double *y,double *tstart,double tfinal, int *istart,int n,double *work,int *ierr) { double yold[MAXODE],told; int i,ok,hit,jj; double s; int nstep=0; while(1){ for(i=0;i(NFlags+2)){ printf(" Working too hard? "); printf("smin=%g\n",s); *ierr=-2; return 1; break; } } return 0; } one_flag_step_dp(istart,y,t,n,tout,tol,atol,flag,kflag) double *y,*t,tout,*tol,*atol; int flag,*istart,*kflag; { double yold[MAXODE],told; int i,hit,jj; double s; int nstep=0; while(1){ for(i=0;i(NFlags+2)){ printf(" Working too hard? "); printf("smin=%g\n",s); return 1; break; } } return 0; } #ifdef CVODE_YES one_flag_step_cvode(command,y,t,n,tout,kflag,atol,rtol) /* command =0 continue, 1 is start 2 finish */ int *command,*kflag; double *y,*atol,*rtol; double *t; double tout; int n; { double yold[MAXODE],told; int i,hit,jj,neq=n; double s; int nstep=0; while(1){ for(i=0;i(NFlags+2)){ printf(" Working too hard? "); printf("smin=%g\n",s); return 1; } } return 0; } #endif one_flag_step_adap(y,neq,t,tout,eps,hguess,hmin,work,ier,epjac,iflag,jstart) double *y,*t,tout,eps,*hguess,hmin,*work,epjac; int neq,*ier,iflag,*jstart; { double yold[MAXODE],told; int i,hit,jj; double s; int nstep=0; while(1){ for(i=0;i(NFlags+2)){ printf(" Working too hard? "); printf("smin=%g\n",s); break; } } return 0; } one_flag_step_backeul(y,t,dt,neq,yg,yp,yp2,ytemp,errvec,jac,istart) double *y,*t,dt,*yg,*yp,*yp2,*ytemp,*errvec,*jac; int neq,*istart; { double yold[MAXODE],told; int i,hit,j; double s,dtt=dt; int nstep=0; while(1){ for(i=0;i(NFlags+2)){ printf(" Working too hard?"); printf("smin=%g\n",s); break; } } return 0; }