void praxis( int n, double *x, int *data, double (*funct)(double *, void *data), double *in, double *out) { int illc,i,j,k,k2,nl,maxf,nf,kl,kt,ktm,emergency; double s,sl,dn,dmin,fx,f1,lds,ldt,sf,df,qf1,qd0,qd1,qa,qb,qc,m2,m4, small,vsmall,large,vlarge,scbd,ldfac,t2,macheps,reltol, abstol,h,**v,*d,*y,*z,*q0,*q1,**a,em[8],l; /* * Seed random number generator */ #ifdef MSWIN srand(34084320); #else srand48(34084320); #endif // for (i=0; i<8; ++i) x[i+1] = (double)data->x[i]; d=allocate_real_vector(1,n); y=allocate_real_vector(1,n); z=allocate_real_vector(1,n); q0=allocate_real_vector(1,n); q1=allocate_real_vector(1,n); v=allocate_real_matrix(1,n,1,n); a=allocate_real_matrix(1,n,1,n); // heuristic numbers: // // If the axes may be badly scaled (which is to be avoided if // possible), then set scbd = 10. otherwise set scbd=1. // // If the problem is known to be ill-conditioned, set ILLC = true. // // KTM is the number of iterations without improvement before the // algorithm terminates. KTM = 4 is very cautious; usually KTM = 1 // is satisfactory. // macheps=in[0]; reltol=in[1]; abstol=in[2]; maxf=in[5]; h=in[6]; scbd=in[7]; ktm=in[8]; illc = in[9] < 0.0; small=macheps*macheps; vsmall=small*small; large=1.0/small; vlarge=1.0/vsmall; m2=reltol; m4=sqrt(m2); srand(1); ldfac = (illc ? 0.1 : 0.01); kt=nl=0; nf=1; out[3]=qf1=fx=(*funct)(x, data); abstol=t2=small+fabs(abstol); dmin=small; if (h < abstol*100.0) h=abstol*100; ldt=h; inimat(1,n,1,n,v,0.0); for (i=1; i<=n; i++) v[i][i]=1.0; d[1]=qd0=qd1=0.0; dupvec(1,n,0,q1,x); inivec(1,n,q0,0.0); emergency=0; while (1) { sf=d[1]; d[1]=s=0.0; praxismin(1,2,&(d[1]),&s,&fx,0, n,x,v,&qa,&qb,&qc,qd0,qd1,q0,q1,&nf, &nl,&fx,m2,m4,dmin,ldt,reltol,abstol,small,h,funct, data); if (s <= 0.0) mulcol(1,n,1,1,v,v,-1.0); if (sf <= 0.9*d[1] || 0.9*sf >= d[1]) inivec(2,n,d,0.0); for (k=2; k<=n; k++) { dupvec(1,n,0,y,x); sf=fx; illc = (illc || kt > 0); while (1) { kl=k; df=0.0; if (illc) { /* random stop to get off resulting valley */ for (i=1; i<=n; i++) { s=z[i]=(0.1*ldt+t2*pow(10.0,kt))* #ifdef MSWIN ((double)(rand())/RAND_MAX-0.5); #else (drand48()-0.5); #endif elmveccol(1,n,i,x,v,s); } fx=(*funct)(x, data); nf++; } for (k2=k; k2<=n; k2++) { sl=fx; s=0.0; praxismin(k2,2,&(d[k2]),&s,&fx,0, n,x,v,&qa,&qb,&qc,qd0,qd1,q0,q1,&nf, &nl,&fx,m2,m4,dmin,ldt,reltol,abstol,small,h,funct, data); s = illc ? d[k2]*(s+z[k2])*(s+z[k2]) : sl-fx; if (df < s) { df=s; kl=k2; } } if (!illc && df < fabs(100.0*macheps*fx)) illc=1; else break; } for (k2=1; k2<=k-1; k2++) { s=0.0; praxismin(k2,2,&(d[k2]),&s,&fx,0, n,x,v,&qa,&qb,&qc,qd0,qd1,q0,q1,&nf, &nl,&fx,m2,m4,dmin,ldt,reltol,abstol,small,h,funct, data); } f1=fx; fx=sf; lds=0.0; for (i=1; i<=n; i++) { sl=x[i]; x[i]=y[i]; y[i] = sl -= y[i]; lds += sl*sl; } lds=sqrt(lds); if (lds > small) { for (i=kl-1; i>=k; i--) { for (j=1; j<=n; j++) v[j][i+1]=v[j][i]; d[i+1]=d[i]; } d[k]=0.0; dupcolvec(1,n,k,v,y); mulcol(1,n,k,k,v,v,1.0/lds); praxismin(k,4,&(d[k]),&lds,&f1,1, n,x,v,&qa,&qb,&qc,qd0,qd1,q0,q1,&nf, &nl,&fx,m2,m4,dmin,ldt,reltol,abstol,small,h,funct, data); if (lds <= 0.0) { lds = -lds; mulcol(1,n,k,k,v,v,-1.0); } } ldt *= ldfac; if (ldt < lds) ldt=lds; t2=m2*sqrt(vecvec(1,n,0,x,x))+abstol; kt = (ldt > 0.5*t2) ? 0 : kt+1; if (kt > ktm) { out[1]=0.0; emergency=1; } } if (emergency) break; /* quad */ s=fx; fx=qf1; qf1=s; qd1=0.0; for (i=1; i<=n; i++) { s=x[i]; x[i]=l=q1[i]; q1[i]=s; qd1 += (s-l)*(s-l); } l=qd1=sqrt(qd1); s=0.0; if ((qd0*qd1 > DBL_MIN) && (nl >=3*n*n)) { praxismin(0,2,&s,&l,&qf1,1, n,x,v,&qa,&qb,&qc,qd0,qd1,q0,q1,&nf, &nl,&fx,m2,m4,dmin,ldt,reltol,abstol,small,h,funct, data); qa=l*(l-qd1)/(qd0*(qd0+qd1)); qb=(l+qd0)*(qd1-l)/(qd0*qd1); qc=l*(l+qd0)/(qd1*(qd0+qd1)); } else { fx=qf1; qa=qb=0.0; qc=1.0; } qd0=qd1; for (i=1; i<=n; i++) { s=q0[i]; q0[i]=x[i]; x[i]=qa*s+qb*x[i]+qc*q1[i]; } /* end of quad */ dn=0.0; for (i=1; i<=n; i++) { d[i]=1.0/sqrt(d[i]); if (dn < d[i]) dn=d[i]; } for (j=1; j<=n; j++) { s=d[j]/dn; mulcol(1,n,j,j,v,v,s); } if (scbd > 1.0) { s=vlarge; for (i=1; i<=n; i++) { sl=z[i]=sqrt(mattam(1,n,i,i,v,v)); if (sl < m4) z[i]=m4; if (s > sl) s=sl; } for (i=1; i<=n; i++) { sl=s/z[i]; z[i]=1.0/sl; if (z[i] > scbd) { sl=1.0/scbd; z[i]=scbd; } mulrow(1,n,i,i,v,v,sl); } } for (i=1; i<=n; i++) ichrowcol(i+1,n,i,i,v); em[0]=em[2]=macheps; em[4]=10*n; em[6]=vsmall; dupmat(1,n,1,n,a,v); if (qrisngvaldec(a,n,n,d,v,em) != 0) { out[1]=2.0; emergency=1; } if (emergency) break; if (scbd > 1.0) { for (i=1; i<=n; i++) mulrow(1,n,i,i,v,v,z[i]); for (i=1; i<=n; i++) { s=sqrt(tammat(1,n,i,i,v,v)); d[i] *= s; s=1.0/s; mulcol(1,n,i,i,v,v,s); } } for (i=1; i<=n; i++) { s=dn*d[i]; d[i] = (s > large) ? vsmall : ((s < small) ? vlarge : 1.0/(s*s)); } /* sort */ for (i=1; i<=n-1; i++) { k=i; s=d[i]; for (j=i+1; j<=n; j++) if (d[j] > s) { k=j; s=d[j]; } if (k > i) { d[k]=d[i]; d[i]=s; for (j=1; j<=n; j++) { s=v[j][i]; v[j][i]=v[j][k]; v[j][k]=s; } } } /* end of sort */ dmin=d[n]; if (dmin < small) dmin=small; illc = (m2*d[1]) > dmin; if (nf >= maxf) { out[1]=1.0; break; } } out[2]=fx; out[4]=nf; out[5]=nl; out[6]=ldt; free_real_vector(d,1); free_real_vector(y,1); free_real_vector(z,1); free_real_vector(q0,1); free_real_vector(q1,1); free_real_matrix(v,1,n,1); free_real_matrix(a,1,n,1); // for (i=0; i<40; ++i) data->x[i] = (double)x[i+1]; }
real_t flemin(int n, real_t x[], real_t g[], real_t h[], real_t (*funct)(int, real_t[], real_t[]), real_t in[], real_t out[]) { real_t *allocate_real_vector(int, int); void free_real_vector(real_t *, int); real_t vecvec(int, int, int, real_t [], real_t []); void elmvec(int, int, int, real_t [], real_t [], real_t); real_t symmatvec(int, int, int, real_t [], real_t []); void inivec(int, int, real_t [], real_t); void inisymd(int, int, int, real_t [], real_t); void mulvec(int, int, int, real_t [], real_t [], real_t); void dupvec(int, int, int, real_t [], real_t []); void linemin(int, real_t [], real_t [], real_t, real_t *, real_t [], real_t (*)(int, real_t[], real_t[]), real_t, real_t *, real_t, real_t *, int *, int, real_t []); void davupd(real_t [], int, real_t [], real_t [], real_t, real_t); void fleupd(real_t [], int, real_t [], real_t [], real_t, real_t); int i,it,cntl,evl,evlmax; real_t f,f0,fmin,mu,dg,dg0,nrmdelta,alfa,reltol,abstol,eps,tolg, aid,*v,*delta,*s; v=allocate_real_vector(1,n); delta=allocate_real_vector(1,n); s=allocate_real_vector(1,n); reltol=in[1]; abstol=in[2]; mu=in[3]; tolg=in[4]; fmin=in[5]; alfa=in[6]; evlmax=in[7]; out[4]=0.0; it=0; f=(*funct)(n,x,g); evl=1; cntl=0; if (alfa > 0.0) { inivec(1,(n*(n+1))/2,h,0.0); inisymd(1,n,0,h,alfa); } for (i=1; i<=n; i++) delta[i] = -symmatvec(1,n,i,h,g); dg=sqrt(vecvec(1,n,0,g,g)); nrmdelta=sqrt(vecvec(1,n,0,delta,delta)); eps=sqrt(vecvec(1,n,0,x,x))*reltol+abstol; dg0=vecvec(1,n,0,delta,g); it++; while ((nrmdelta > eps || dg > tolg) && (evl < evlmax)) { dupvec(1,n,0,s,x); dupvec(1,n,0,v,g); if (it >= n) alfa=1.0; else { if (it != 1) alfa /= nrmdelta; else { alfa=2.0*(fmin-f)/dg0; if (alfa > 1.0) alfa=1.0; } } elmvec(1,n,0,x,delta,alfa); f0=f; f=(*funct)(n,x,g); evl++; dg=vecvec(1,n,0,delta,g); if (it == 1 || f0-f < -mu*dg0*alfa) { /* line minimization */ i=evlmax-evl; cntl++; linemin(n,s,delta,nrmdelta,&alfa,g,funct,f0,&f, dg0,&dg,&i,0,in); evl += i; dupvec(1,n,0,x,s); } if (alfa != 1.0) mulvec(1,n,0,delta,delta,alfa); mulvec(1,n,0,v,v,-1.0); elmvec(1,n,0,v,g,1.0); for (i=1; i<=n; i++) s[i]=symmatvec(1,n,i,h,v); aid=vecvec(1,n,0,v,s); dg=(dg-dg0)*alfa; if (dg > 0.0) if (dg >= aid) fleupd(h,n,delta,s,1.0/dg,(1.0+aid/dg)/dg); else davupd(h,n,delta,s,1.0/dg,1.0/aid); for (i=1; i<=n; i++) delta[i] = -symmatvec(1,n,i,h,g); alfa *= nrmdelta; nrmdelta=sqrt(vecvec(1,n,0,delta,delta)); eps=sqrt(vecvec(1,n,0,x,x))*reltol+abstol; dg=sqrt(vecvec(1,n,0,g,g)); dg0=vecvec(1,n,0,delta,g); if (dg0 > 0.0) { out[4] = -1.0; break; } it++; } out[0]=nrmdelta; out[1]=dg; out[2]=evl; out[3]=cntl; free_real_vector(v,1); free_real_vector(delta,1); free_real_vector(s,1); return f; }
int peidefunct(int nrow, int ncol, real_t par[], real_t res[], int n, int m, int nobs, int *nbp, int first, int *sec, int *max, int *nis, real_t eps1, int weight, int bp[], real_t save[], real_t ymax[], real_t y[], real_t **yp, real_t **fy, real_t **fp, int cobs[], real_t tobs[], real_t obs[], real_t in[], real_t aux[], int clean, int (*deriv)(int,int,real_t [],real_t [],real_t,real_t []), int (*jacdfdy)(int,int,real_t [],real_t [],real_t,real_t **), int (*jacdfdp)(int,int,real_t [],real_t [],real_t,real_t **), void (*callystart)(int,int,real_t [],real_t [],real_t[]), void (*monitor)(int,int,int,real_t [],real_t [],int,int)) { /* this function is internally used by PEIDE */ void peidereset(int, int, real_t, real_t, real_t, real_t, real_t [], real_t [], real_t *, real_t *, real_t *, int *); void peideorder(int, int, real_t, real_t [], real_t [], real_t *, real_t *, real_t *, real_t *, real_t *, int *); void peidestep(int, int, int, real_t, real_t, real_t, real_t, real_t [], real_t [], real_t [], real_t [], int *, real_t *); real_t peideinterpol(int, int, int, real_t, real_t []); int l,k,knew,fails,same,kpold,n6,nnpar,j5n,cobsii,*p,evaluate, evaluated,decompose,conv,extra,npar,i,j,jj,ii; real_t xold,hold,a0,tolup,tol,toldwn,tolconv,h,ch,chnew,error, dfi,tobsdif,a[6],*delta,*lastdelta,*df,*y0,**jacob,xend, hmax,hmin,eps,s,aa,x,t,c; p=allocate_integer_vector(1,n); delta=allocate_real_vector(1,n); lastdelta=allocate_real_vector(1,n); df=allocate_real_vector(1,n); y0=allocate_real_vector(1,n); jacob=allocate_real_matrix(1,n,1,n); if (*sec) { *sec=0; goto Finish; } xend=tobs[nobs]; eps=in[2]; npar=m; extra=(*nis)=0; ii=1; jj = (*nbp == 0) ? 0 : 1; n6=n*6; inivec(-3,-1,save,0.0); inivec(n6+1,(6+m)*n,y,0.0); inimat(1,nobs+(*nbp),1,m+(*nbp),yp,0.0); t=tobs[1]; x=tobs[0]; (*callystart)(n,m,par,y,ymax); hmax=tobs[1]-tobs[0]; hmin=hmax*in[1]; /* evaluate jacobian */ evaluate=0; decompose=evaluated=1; if (!(*jacdfdy)(n,m,par,y,x,fy)) { save[-3]=4.0; goto Finish; } nnpar=n*npar; Newstart: k=1; kpold=0; same=2; peideorder(n,k,eps,a,save,&tol,&tolup,&toldwn,&tolconv, &a0,&decompose); if (!(*deriv)(n,m,par,y,x,df)) { save[-3]=3.0; goto Finish; } s=FLT_MIN; for (i=1; i<=n; i++) { aa=matvec(1,n,i,fy,df)/ymax[i]; s += aa*aa; } h=sqrt(2.0*eps/sqrt(s)); if (h > hmax) h=hmax; else if (h < hmin) h=hmin; xold=x; hold=h; ch=1.0; for (i=1; i<=n; i++) { save[i]=y[i]; save[n+i]=y[n+i]=df[i]*h; } fails=0; while (x < xend) { if (x+h <= xend) x += h; else { h=xend-x; x=xend; ch=h/hold; c=1.0; for (j=n; j<=k*n; j += n) { c *= ch; for (i=j+1; i<=j+n; i++) y[i] *= c; } same = (same < 3) ? 3 : same+1; } /* prediction */ for (l=1; l<=n; l++) { for (i=l; i<=(k-1)*n+l; i += n) for (j=(k-1)*n+l; j>=i; j -= n) y[j] += y[j+n]; delta[l]=0.0; } evaluated=0; /* correction and estimation local error */ for (l=1; l<=3; l++) { if (!(*deriv)(n,m,par,y,x,df)) { save[-3]=3; goto Finish; } for (i=1; i<=n; i++) df[i]=df[i]*h-y[n+i]; if (evaluate) { /* evaluate jacobian */ evaluate=0; decompose=evaluated=1; if (!(*jacdfdy)(n,m,par,y,x,fy)) { save[-3]=4.0; goto Finish; } } if (decompose) { /* decompose jacobian */ decompose=0; c = -a0*h; for (j=1; j<=n; j++) { for (i=1; i<=n; i++) jacob[i][j]=fy[i][j]*c; jacob[j][j] += 1.0; } dec(jacob,n,aux,p); } sol(jacob,n,p,df); conv=1; for (i=1; i<=n; i++) { dfi=df[i]; y[i] += a0*dfi; y[n+i] += dfi; delta[i] += dfi; conv=(conv && (fabs(dfi) < tolconv*ymax[i])); } if (conv) { s=FLT_MIN; for (i=1; i<=n; i++) { aa=delta[i]/ymax[i]; s += aa*aa; } error=s; break; } } /* acceptance or rejection */ if (!conv) { if (!evaluated) evaluate=1; else { ch /= 4.0; if (h < 4.0*hmin) { save[-1] += 10.0; hmin /= 10.0; if (save[-1] > 40.0) goto Finish; } } peidereset(n,k,hmin,hmax,hold,xold,y,save,&ch,&x, &h,&decompose); } else if (error > tol) { fails++; if (h > 1.1*hmin) { if (fails > 2) { peidereset(n,k,hmin,hmax,hold,xold,y,save,&ch,&x, &h,&decompose); goto Newstart; } else { /* calculate step and order */ peidestep(n,k,fails,tolup,toldwn,tol,error,delta, lastdelta,y,ymax,&knew,&chnew); if (knew != k) { k=knew; peideorder(n,k,eps,a,save,&tol,&tolup, &toldwn,&tolconv,&a0,&decompose); } ch *= chnew; peidereset(n,k,hmin,hmax,hold,xold,y,save,&ch,&x, &h,&decompose); } } else { if (k == 1) { /* violate eps criterion */ save[-2] += 1.0; same=4; goto Errortestok; } k=1; peidereset(n,k,hmin,hmax,hold,xold,y,save,&ch,&x, &h,&decompose); peideorder(n,k,eps,a,save,&tol,&tolup, &toldwn,&tolconv,&a0,&decompose); same=2; } } else { Errortestok: fails=0; for (i=1; i<=n; i++) { c=delta[i]; for (l=2; l<=k; l++) y[l*n+i] += a[l]*c; if (fabs(y[i]) > ymax[i]) ymax[i]=fabs(y[i]); } same--; if (same == 1) dupvec(1,n,0,lastdelta,delta); else if (same == 0) { /* calculate step and order */ peidestep(n,k,fails,tolup,toldwn,tol,error,delta, lastdelta,y,ymax,&knew,&chnew); if (chnew > 1.1) { if (k != knew) { if (knew > k) mulvec(knew*n+1,knew*n+n,-knew*n,y,delta, a[k]/knew); k=knew; peideorder(n,k,eps,a,save,&tol,&tolup, &toldwn,&tolconv,&a0,&decompose); } same=k+1; if (chnew*h > hmax) chnew=hmax/h; h *= chnew; c=1.0; for (j=n; j<=k*n; j += n) { c *= chnew; mulvec(j+1,j+n,0,y,y,c); } decompose=1; } else same=10; } (*nis)++; /* start of an integration step of yp */ if (clean) { hold=h; xold=x; kpold=k; ch=1.0; dupvec(1,k*n+n,0,save,y); } else { if (h != hold) { ch=h/hold; c=1.0; for (j=n6+nnpar; j<=kpold*nnpar+n6; j += nnpar) { c *= ch; for (i=j+1; i<=j+nnpar; i++) y[i] *= c; } hold=h; } if (k > kpold) inivec(n6+k*nnpar+1,n6+k*nnpar+nnpar,y,0.0); xold=x; kpold=k; ch=1.0; dupvec(1,k*n+n,0,save,y); /* evaluate jacobian */ evaluate=0; decompose=evaluated=1; if (!(*jacdfdy)(n,m,par,y,x,fy)) { save[-3]=4.0; goto Finish; } /* decompose jacobian */ decompose=0; c = -a0*h; for (j=1; j<=n; j++) { for (i=1; i<=n; i++) jacob[i][j]=fy[i][j]*c; jacob[j][j] += 1.0; } dec(jacob,n,aux,p); if (!(*jacdfdp)(n,m,par,y,x,fp)) { save[-3]=5.0; goto Finish; } if (npar > m) inimat(1,n,m+1,npar,fp,0.0); /* prediction */ for (l=0; l<=k-1; l++) for (j=k-1; j>=l; j--) elmvec(j*nnpar+n6+1,j*nnpar+n6+nnpar,nnpar, y,y,1.0); /* correction */ for (j=1; j<=npar; j++) { j5n=(j+5)*n; dupvec(1,n,j5n,y0,y); for (i=1; i<=n; i++) df[i]=h*(fp[i][j]+matvec(1,n,i,fy,y0))- y[nnpar+j5n+i]; sol(jacob,n,p,df); for (l=0; l<=k; l++) { i=l*nnpar+j5n; elmvec(i+1,i+n,-i,y,df,a[l]); } } } while (x >= t) { /* calculate a row of the jacobian matrix and an element of the residual vector */ tobsdif=(tobs[ii]-x)/h; cobsii=cobs[ii]; res[ii]=peideinterpol(cobsii,n,k,tobsdif,y)-obs[ii]; if (!clean) { for (i=1; i<=npar; i++) yp[ii][i]=peideinterpol(cobsii+(i+5)*n,nnpar,k, tobsdif,y); /* introducing break-points */ if (bp[jj] != ii) { } else if (first && fabs(res[ii]) < eps1) { (*nbp)--; for (i=jj; i<=(*nbp); i++) bp[i]=bp[i+1]; bp[*nbp+1]=0; } else { extra++; if (first) par[m+jj]=obs[ii]; /* introducing a jacobian row and a residual vector element for continuity requirements */ yp[nobs+jj][m+jj] = -weight; mulrow(1,npar,nobs+jj,ii,yp,yp,weight); res[nobs+jj]=weight*(res[ii]+obs[ii]-par[m+jj]); } } if (ii == nobs) goto Finish; else { t=tobs[ii+1]; if (bp[jj] == ii && jj < *nbp) jj++; hmax=t-tobs[ii]; hmin=hmax*in[1]; ii++; } } /* break-points introduce new initial values for y & yp */ if (extra > 0) { for (i=1; i<=n; i++) { y[i]=peideinterpol(i,n,k,tobsdif,y); for (j=1; j<=npar; j++) y[i+(j+5)*n]=peideinterpol(i+(j+5)*n,nnpar, k,tobsdif,y); } for (l=1; l<=extra; l++) { cobsii=cobs[bp[npar-m+l]]; y[cobsii]=par[npar+l]; for (i=1; i<=npar+extra; i++) y[cobsii+(5+i)*n]=0.0; inivec(1+nnpar+(l+5)*n,nnpar+(l+6)*n,y,0.0); y[cobsii+(5+npar+l)*n]=1.0; } npar += extra; extra=0; x=tobs[ii-1]; /* evaluate jacobian */ evaluate=0; decompose=evaluated=1; if (!(*jacdfdy)(n,m,par,y,x,fy)) { save[-3]=4.0; goto Finish; } nnpar=n*npar; goto Newstart; } } } Finish: if (save[-2] > *max) *max=save[-2]; if (!first) (*monitor)(1,ncol,nrow,par,res,weight,*nis); free_integer_vector(p,1); free_real_vector(delta,1); free_real_vector(lastdelta,1); free_real_vector(df,1); free_real_vector(y0,1); free_real_matrix(jacob,1,n,1); return (save[-1] <= 40.0 && save[-3] == 0.0); }
void ark(real_t *t, real_t *te, int *m0, int *m, real_t u[], void (*derivative)(int *, int *, real_t *, real_t[]), real_t data[], void (*out)(int *, int *, real_t *, real_t *, real_t [], real_t [])) { real_t *allocate_real_vector(int, int); real_t **allocate_real_matrix(int, int, int, int); void free_real_vector(real_t *, int); void free_real_matrix(real_t **, int, int, int); void inivec(int, int, real_t [], real_t); void mulvec(int, int, int, real_t [], real_t [], real_t); void dupvec(int, int, int, real_t [], real_t []); real_t vecvec(int, int, int, real_t [], real_t []); void elmvec(int, int, int, real_t [], real_t [], real_t); void decsol(real_t **, int, real_t [], real_t []); real_t arkmui(int, int, int, real_t []); real_t arklabda(int, int, int, int, real_t []); static real_t th1[8] = {1.0, 0.5, 1.0/6.0, 1.0/3.0, 1.0/24.0, 1.0/12.0, 0.125, 0.25}; static real_t ec0,ec1,ec2,tau0,tau1,tau2,taus,t2; int p,n,q,start,step1,last,i,j,k,l,n1,m00; real_t thetanm1,tau,betan,qinv,eta,*mu,*lambda,*thetha,*ro,*r, **alfa,th[9],aux[4],s,ss,theta0,tauacc,taustab, aa,bb,cc,ec,mt,lt; n=data[1]; m00=(*m0); mu=allocate_real_vector(1,n); lambda=allocate_real_vector(1,n); thetha=allocate_real_vector(0,n); ro=allocate_real_vector(m00,*m); r=allocate_real_vector(m00,*m); alfa=allocate_real_matrix(1,8,1,n+1); p=data[2]; ec1=ec2=0.0; betan=data[3]; thetanm1 = (p == 3) ? 0.75 : 1.0; theta0=1.0-thetanm1; s=1.0; for (j=n-1; j>=1; j--) { s = -s*theta0+data[n+10-j]; mu[j]=data[n+11-j]/s; lambda[j]=mu[j]-theta0; } for (i=1; i<=8; i++) for (j=0; j<=n; j++) if (i == 1) alfa[i][j+1]=1.0; else if (j == 0) alfa[i][j+1]=0.0; else if (i == 2 || i == 4 || i == 8) alfa[i][j+1]=pow(arkmui(j,n,p,lambda),(i+2)/3); else if ((i == 3 || i == 6) && j > 1) { s=0.0; for (l=1; l<=j-1; l++) s += arklabda(j,l,n,p,lambda)* pow(arkmui(l,n,p,lambda),i/3); alfa[i][j+1]=s; } else if (i == 5 && j > 2) { s=0.0; for (l=2; l<=j-1; l++) { ss=0.0; for (k=1; k<=l-1; k++) ss += arklabda(l,k,n,p,lambda)* arkmui(k,n,p,lambda); s += arklabda(j,l,n,p,lambda)*ss; } alfa[i][j+1]=s; } else if (i == 7 && j > 1) { s=0.0; for (l=1; l<=j-1; l++) s += arklabda(j,l,n,p,lambda)*arkmui(l,n,p,lambda); alfa[i][j+1]=s*arkmui(j,n,p,lambda); } else alfa[i][j+1]=0.0; n1 = ((n < 4) ? n+1 : ((n < 7) ? 4 : 8)); for (i=1; i<=8; i++) th[i]=th1[i-1]; if (p == 3 && n < 7) th[1]=th[2]=0.0; aux[2]=FLT_EPSILON; decsol(alfa,n1,aux,th); inivec(0,n,thetha,0.0); dupvec(0,n1-1,1,thetha,th); if (!(p == 3 && n < 7)) { thetha[0] -= theta0; thetha[n-1] -= thetanm1; q=p+1; } else q=3; qinv=1.0/q; start=(data[8] == 0.0); data[10]=0.0; last=0; dupvec(*m0,*m,0,r,u); (*derivative)(m0,m,t,r); do { /* stepsize */ eta=sqrt(vecvec(*m0,*m,0,u,u))*data[7]+data[6]; if (eta > 0.0) { if (start) { if (data[8] == 0) { tauacc=data[5]; step1=1; } else if (step1) { tauacc=pow(eta/ec2,qinv); if (tauacc > 10.0*tau2) tauacc=10.0*tau2; else step1=0; } else { bb=(ec2-ec1)/tau1; cc = -bb*t2+ec2; ec=bb*(*t)+cc; tauacc = (ec < 0.0) ? tau2 : pow(eta/ec,qinv); start=0; } } else { aa=((ec0-ec1)/tau0+(ec2-ec1)/tau1)/(tau1+tau0); bb=(ec2-ec1)/tau1-(2.0*t2-tau1)*aa; cc = -(aa*t2+bb)*t2+ec2; ec=(aa*(*t)+bb)*(*t)+cc; tauacc = ((ec < 0.0) ? taus : pow(eta/ec,qinv)); if (tauacc > 2.0*taus) tauacc=2.0*taus; if (tauacc < taus/2.0) tauacc=taus/2.0; } } else tauacc=data[5]; if (tauacc < data[5]) tauacc=data[5]; taustab=betan/data[4]; if (taustab < data[5]) { data[10]=1.0; break; } tau = ((tauacc > taustab) ? taustab : tauacc); taus=tau; if (tau >= (*te)-(*t)) { tau=(*te)-(*t); last=1; } tau0=tau1; tau1=tau2; tau2=tau; /* difference scheme */ mulvec(*m0,*m,0,ro,r,thetha[0]); if (p == 3) elmvec(*m0,*m,0,u,r,0.25*tau); for (i=1; i<=n-1; i++) { mt=mu[i]*tau; lt=lambda[i]*tau; for (j=(*m0); j<=(*m); j++) r[j]=lt*r[j]+u[j]; s=(*t)+mt; (*derivative)(m0,m,&s,r); if (thetha[i] != 0.0) elmvec(*m0,*m,0,ro,r,thetha[i]); if (i == n) { data[9]=sqrt(vecvec(*m0,*m,0,ro,ro))*tau; ec0=ec1; ec1=ec2; ec2=data[9]/pow(tau,q); } } elmvec(*m0,*m,0,u,r,thetanm1*tau); dupvec(*m0,*m,0,r,u); s=(*t)+tau; (*derivative)(m0,m,&s,r); if (thetha[n] != 0.0) elmvec(*m0,*m,0,ro,r,thetha[n]); data[9]=sqrt(vecvec(*m0,*m,0,ro,ro))*tau; ec0=ec1; ec1=ec2; ec2=data[9]/pow(tau,q); t2=(*t); if (last) { last=0; (*t)=(*te); } else (*t) += tau; data[8] += 1.0; (*out)(m0,m,t,te,u,data); } while ((*t) != (*te)); free_real_vector(mu,1); free_real_vector(lambda,1); free_real_vector(thetha,0); free_real_vector(ro,m00); free_real_vector(r,m00); free_real_matrix(alfa,1,8,1); }