template struct StepperSie : StepperBase { typedef D Dtype; static const Int KMAXX=12,IMAXX=KMAXX+1; Int k_targ; VecInt nseq; VecDoub cost; MatDoub table; MatDoub dfdy; VecDoub dfdx; Doub jac_redo; bool calcjac; Doub theta; MatDoub a; Int kright; MatDoub coeff; MatDoub fsave; VecDoub dens; VecDoub factrl; StepperSie(VecDoub_IO &yy, VecDoub_IO &dydxx, Doub &xx, const Doub atol, const Doub rtol, bool dens); void step(const Doub htry,D &derivs); bool dy(VecDoub_I &y, const Doub htot, const Int k, VecDoub_O ¥d, Int &ipt,VecDoub_I &scale,D &derivs); void polyextr(const Int k, MatDoub_IO &table, VecDoub_IO &last); void prepare_dense(const Doub h,VecDoub_I &ysav,VecDoub_I &scale, const Int k, Doub &error); Doub dense_out(const Int i,const Doub x,const Doub h); void dense_interp(const Int n, VecDoub_IO &y, const Int imit); }; template StepperSie::StepperSie(VecDoub_IO &yy, VecDoub_IO &dydxx, Doub &xx, const Doub atoll,const Doub rtoll, bool dens) : StepperBase(yy,dydxx,xx,atoll,rtoll,dens),nseq(IMAXX),cost(IMAXX), table(KMAXX,n),dfdy(n,n),dfdx(n),calcjac(false), a(n,n),coeff(IMAXX,IMAXX), fsave((IMAXX-1)*(IMAXX+1)/2+2,n),dens((IMAXX+2)*n),factrl(IMAXX) { static const Doub costfunc=1.0,costjac=5.0,costlu=1.0,costsolve=1.0; EPS=numeric_limits::epsilon(); jac_redo=MIN(1.0e-4,rtol); theta=2.0*jac_redo; nseq[0]=2; nseq[1]=3; for (Int i=2;i void StepperSie::step(const Doub htry,D &derivs) { const Doub STEPFAC1=0.6,STEPFAC2=0.93,STEPFAC3=0.1,STEPFAC4=4.0, STEPFAC5=0.5,KFAC1=0.7,KFAC2=0.9; static bool first_step=true,last_step=false; static bool forward,reject=false,prev_reject=false; static Doub errold; Int i,k; Doub fac,h,hnew,err; bool firstk; VecDoub hopt(IMAXX),work(IMAXX); VecDoub ysav(n),yseq(n); VecDoub ymid(n),scale(n); work[0]=1.e30; h=htry; forward = h>0 ? true : false; for (i=0;i jac_redo && !calcjac) { derivs.jacobian(x,y,dfdx,dfdy); calcjac=true; } while (firstk || reject) { h = forward ? hnew : -hnew; firstk=false; reject=false; if (abs(h) <= abs(x)*EPS) throw("step size underflow in StepperSie"); Int ipt=-1; for (k=0; k<=k_targ+1;k++) { bool success=dy(ysav,h,k,yseq,ipt,scale,derivs); if (!success) { reject=true; hnew=abs(h)*STEPFAC5; break; } if (k == 0) y=yseq; else for (i=0;i 1.0/EPS || (k > 1 && err >= errold)) { reject=true; hnew=abs(h)*STEPFAC5; break; } errold=max(4.0*err,1.0); Doub expo=1.0/(k+1); Doub facmin=pow(STEPFAC3,expo); if (err == 0.0) fac=1.0/facmin; else { fac=STEPFAC2/pow(err/STEPFAC1,expo); fac=MAX(facmin/STEPFAC4,MIN(1.0/facmin,fac)); } hopt[k]=abs(h*fac); work[k]=cost[k]/hopt[k]; if ((first_step || last_step) && err <= 1.0) break; if (k == k_targ-1 && !prev_reject && !first_step && !last_step) { if (err <= 1.0) break; else if (err>nseq[k_targ]*nseq[k_targ+1]*4.0) { reject=true; k_targ=k; if (k_targ>1 && work[k-1]nseq[k+1]*2.0) { reject=true; if (k_targ>1 && work[k-1] 1.0) { reject=true; if (k_targ>1 && work[k_targ-1] 2 && work[k-2] < KFAC1*work[k-1]) kopt=k-2; if (work[k] < KFAC2*work[kopt]) kopt=MIN(k,KMAXX-1); } if (prev_reject) { k_targ=MIN(kopt,k); hnew=MIN(abs(h),hopt[k_targ]); prev_reject=false; } else { if (kopt <= k) hnew=hopt[kopt]; else { if (k bool StepperSie::dy(VecDoub_I &y,const Doub htot,const Int k,VecDoub_O ¥d, Int &ipt,VecDoub_I &scale,D &derivs) { VecDoub del(n),ytemp(n),dytemp(n); Int nstep=nseq[k]; Doub h=htot/nstep; for (Int i=0;i 1.0) return false; } alu.solve(yend,del); if (dense && nn >= nstep-k-1) { ipt++; for (Int i=0;i void StepperSie::polyextr(const Int k,MatDoub_IO &table,VecDoub_IO &last) { Int l=last.size(); for (Int j=k-1; j>0; j--) for (Int i=0; i void StepperSie::prepare_dense(const Doub h,VecDoub_I &ysav,VecDoub_I &scale, const Int k,Doub &error) { kright=k; for (Int i=0; i= 1) { for (Int kk=klr; kk<=k; kk++) { Int lbeg=((kk+3)*kk)/2; Int lend=lbeg-kk+1; for (Int l=lbeg; l>=lend; l--) for (Int i=0; i=klr+1; l--) { Doub factor=dblenj/nseq[l-1]-1.0; for (Int i=0; i Doub StepperSie::dense_out(const Int i,const Doub x,const Doub h) { Doub theta=(x-xold)/h; Int k=kright; Doub yinterp=dens[(k+1)*n+i]; for (Int j=1; j<=k; j++) yinterp=dens[(k+1-j)*n+i]+yinterp*(theta-1.0); return dens[i]+yinterp*theta; }