#include #include #include #include #include "nicmos.h" /* This file contains various Numerical Recipies routines that are ** used by the "pedvmr" program. It includes numerical fitting ** routines, as well as utilities for allocating and freeing arrays. ** The only modification from the standard versions is the use of ** the n_error routine for broadcasting error messages, instead of ** the standard Num. Rec. routine nrerror. ** ** It contains the following routines: ** ** amoeba ** amotry ** brent ** fpoly ** gaussj ** lfit ** nrselect ** piksrt ** pythag ** rtbis ** shell ** sort ** svdfit ** svbksb ** svdcmp ** vector ** free_vector ** matrix ** free_matrix */ float *vector(int nl, int nh); void free_vector(float *v, int nl, int nh); int *ivector(int nl, int nh); void free_ivector(int *v, int nl, int nh); float **matrix(int nrl, int nrh, int ncl, int nch); void free_matrix(float **m, int nrl, int nrh, int ncl, int nch); static float amotry(float **p, float y[], float psum[], int ndim, float (*funk)(float []), int ihi, float fac); static void svbksb(float **u, float *w, float **v, int m, int n, float b[], float x[]); static void svdcmp(float **a, int m, int n, float *w, float **v); static void gaussj(float **a, int n, float **b, int m); static float pythag(float a, float b); #define SIGN(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a)) #define SWAP(a,b) {float swap=(a);(a)=(b);(b)=swap;} #define NMAX 5000 #define GET_PSUM \ for (j=1;j<=ndim;j++) {\ for (sum=0.0,i=1;i<=mpts;i++) sum += p[i][j];\ psum[j]=sum;} void amoeba (float **p, float y[], int ndim, float ftol, float (*funk)(float []), int *nfunk) { /* Local variables */ int i,ihi,ilo,inhi,j,mpts=ndim+1; float rtol,sum,ysave,ytry,*psum; psum=vector(1,ndim); *nfunk=0; GET_PSUM for (;;) { ilo=1; ihi = y[1]>y[2] ? (inhi=2,1) : (inhi=1,2); for (i=1;i<=mpts;i++) { if (y[i] <= y[ilo]) ilo=i; if (y[i] > y[ihi]) { inhi=ihi; ihi=i; } else if (y[i] > y[inhi] && i != ihi) inhi=i; } rtol=2.0*fabs(y[ihi]-y[ilo])/(fabs(y[ihi])+fabs(y[ilo])); if (rtol < ftol) { SWAP(y[1],y[ilo]) for (i=1;i<=ndim;i++) SWAP(p[1][i],p[ilo][i]) break; } if (*nfunk >= NMAX) { sprintf (MsgText, "NMAX exceeded in amoeba"); n_error (MsgText); } *nfunk += 2; ytry=amotry(p,y,psum,ndim,funk,ihi,-1.0); if (ytry <= y[ilo]) ytry=amotry(p,y,psum,ndim,funk,ihi,2.0); else if (ytry >= y[inhi]) { ysave=y[ihi]; ytry=amotry(p,y,psum,ndim,funk,ihi,0.5); if (ytry >= ysave) { for (i=1;i<=mpts;i++) { if (i != ilo) { for (j=1;j<=ndim;j++) p[i][j]=psum[j]=0.5*(p[i][j]+p[ilo][j]); y[i]=(*funk)(psum); } } *nfunk += ndim; GET_PSUM } } else --(*nfunk); } free_vector(psum,1,ndim); } #undef GET_PSUM #undef NMAX static float amotry (float **p, float y[], float psum[], int ndim, float (*funk)(float []), int ihi, float fac) { int j; float fac1,fac2,ytry,*ptry; ptry=vector(1,ndim); fac1=(1.0-fac)/ndim; fac2=fac1-fac; for (j=1;j<=ndim;j++) ptry[j]=psum[j]*fac1-p[ihi][j]*fac2; ytry=(*funk)(ptry); if (ytry < y[ihi]) { y[ihi]=ytry; for (j=1;j<=ndim;j++) { psum[j] += ptry[j]-p[ihi][j]; p[ihi][j]=ptry[j]; } } free_vector(ptry,1,ndim); return ytry; } #define ITMAX 100 #define CGOLD 0.3819660 #define ZEPS 1.0e-10 #define SHFT(a,b,c,d) (a)=(b);(b)=(c);(c)=(d); float brent(float ax, float bx, float cx, float (*f)(float), float tol, float *xmin) { /* Local variables */ int iter; float a,b,d,etemp,fu,fv,fw,fx,p,q,r,tol1,tol2,u,v,w,x,xm; float e=0.0; a=(ax < cx ? ax : cx); b=(ax > cx ? ax : cx); x=w=v=bx; fw=fv=fx=(*f)(x); for (iter=1;iter<=ITMAX;iter++) { xm=0.5*(a+b); tol2=2.0*(tol1=tol*fabs(x)+ZEPS); if (fabs(x-xm) <= (tol2-0.5*(b-a))) { *xmin=x; return fx; } if (fabs(e) > tol1) { r=(x-w)*(fx-fv); q=(x-v)*(fx-fw); p=(x-v)*q-(x-w)*r; q=2.0*(q-r); if (q > 0.0) p = -p; q=fabs(q); etemp=e; e=d; if (fabs(p) >= fabs(0.5*q*etemp) || p <= q*(a-x) || p >= q*(b-x)) d=CGOLD*(e=(x >= xm ? a-x : b-x)); else { d=p/q; u=x+d; if (u-a < tol2 || b-u < tol2) d=SIGN(tol1,xm-x); } } else { d=CGOLD*(e=(x >= xm ? a-x : b-x)); } u=(fabs(d) >= tol1 ? x+d : x+SIGN(tol1,d)); fu=(*f)(u); if (fu <= fx) { if (u >= x) a=x; else b=x; SHFT(v,w,x,u) SHFT(fv,fw,fx,fu) } else { if (u < x) a=u; else b=u; if (fu <= fw || w == x) { v=w; w=u; fv=fw; fw=fu; } else if (fu <= fv || v == x || v == w) { v=u; fv=fu; } } } sprintf (MsgText, "Too many iterations in brent"); n_error (MsgText); } #undef ITMAX #undef CGOLD #undef ZEPS #undef SHFT float nrselect (int k, int n, float arr[]) { /* Local variables */ int i,ir,j,l,mid; float a; l=1; ir=n; for (;;) { if (ir <= l+1) { if (ir == l+1 && arr[ir] < arr[l]) { SWAP(arr[l],arr[ir]) } return arr[k]; } else { mid=(l+ir) >> 1; SWAP(arr[mid],arr[l+1]) if (arr[l] > arr[ir]) { SWAP(arr[l],arr[ir]) } if (arr[l+1] > arr[ir]) { SWAP(arr[l+1],arr[ir]) } if (arr[l] > arr[l+1]) { SWAP(arr[l],arr[l+1]) } i=l+1; j=ir; a=arr[l+1]; for (;;) { do i++; while (arr[i] < a); do j--; while (arr[j] > a); if (j < i) break; SWAP(arr[i],arr[j]) } arr[l+1]=arr[j]; arr[j]=a; if (j >= k) ir=j-1; if (j <= k) l=i; } } } #define TOL 1.0e-5 static float maxarg1,maxarg2; #define FMAX(a,b) (maxarg1=(a),maxarg2=(b),(maxarg1) > (maxarg2) ?\ (maxarg1) : (maxarg2)) static int iminarg1,iminarg2; #define IMIN(a,b) (iminarg1=(a),iminarg2=(b),(iminarg1) < (iminarg2) ?\ (iminarg1) : (iminarg2)) static float sqrarg; #define SQR(a) ((sqrarg=(a)) == 0.0 ? 0.0 : sqrarg*sqrarg) void svdfit(float x[], float y[], float sig[], int ndata, float a[], int ma, float **u, float **v, float *w, float *chisq, void (*funcs)(float, float [], int)) { int j,i; float wmax,tmp,thresh,sum,*b,*afunc; b=vector(1,ndata); afunc=vector(1,ma); for (i=1;i<=ndata;i++) { (*funcs)(x[i],afunc,ma); tmp=1.0/sig[i]; for (j=1;j<=ma;j++) u[i][j]=afunc[j]*tmp; b[i]=y[i]*tmp; } svdcmp(u,ndata,ma,w,v); wmax=0.0; for (j=1;j<=ma;j++) if (w[j] > wmax) wmax=w[j]; thresh=TOL*wmax; for (j=1;j<=ma;j++) if (w[j] < thresh) w[j]=0.0; svbksb(u,w,v,ndata,ma,b,a); *chisq=0.0; for (i=1;i<=ndata;i++) { (*funcs)(x[i],afunc,ma); for (sum=0.0,j=1;j<=ma;j++) sum += a[j]*afunc[j]; *chisq += (tmp=(y[i]-sum)/sig[i],tmp*tmp); } free_vector(afunc,1,ma); free_vector(b,1,ndata); } #undef TOL static void svbksb(float **u, float *w, float **v, int m, int n, float b[], float x[]) { int jj,j,i; float s,*tmp; tmp=vector(1,n); for (j=1;j<=n;j++) { s=0.0; if (w[j]) { for (i=1;i<=m;i++) s += u[i][j]*b[i]; s /= w[j]; } tmp[j]=s; } for (j=1;j<=n;j++) { s=0.0; for (jj=1;jj<=n;jj++) s += v[j][jj]*tmp[jj]; x[j]=s; } free_vector(tmp,1,n); } static void svdcmp(float **a, int m, int n, float *w, float **v) { int flag,i,its,j,jj,k,l,nm; float anorm,c,f,g,h,s,scale,x,y,z,*rv1; rv1=vector(1,n); g=scale=anorm=0.0; for (i=1;i<=n;i++) { l=i+1; rv1[i]=scale*g; g=s=scale=0.0; if (i <= m) { for (k=i;k<=m;k++) scale += fabs(a[k][i]); if (scale) { for (k=i;k<=m;k++) { a[k][i] /= scale; s += a[k][i]*a[k][i]; } f=a[i][i]; g = -SIGN(sqrt(s),f); h=f*g-s; a[i][i]=f-g; for (j=l;j<=n;j++) { for (s=0.0,k=i;k<=m;k++) s += a[k][i]*a[k][j]; f=s/h; for (k=i;k<=m;k++) a[k][j] += f*a[k][i]; } for (k=i;k<=m;k++) a[k][i] *= scale; } } w[i]=scale *g; g=s=scale=0.0; if (i <= m && i != n) { for (k=l;k<=n;k++) scale += fabs(a[i][k]); if (scale) { for (k=l;k<=n;k++) { a[i][k] /= scale; s += a[i][k]*a[i][k]; } f=a[i][l]; g = -SIGN(sqrt(s),f); h=f*g-s; a[i][l]=f-g; for (k=l;k<=n;k++) rv1[k]=a[i][k]/h; for (j=l;j<=m;j++) { for (s=0.0,k=l;k<=n;k++) s += a[j][k]*a[i][k]; for (k=l;k<=n;k++) a[j][k] += s*rv1[k]; } for (k=l;k<=n;k++) a[i][k] *= scale; } } anorm=FMAX(anorm,(fabs(w[i])+fabs(rv1[i]))); } for (i=n;i>=1;i--) { if (i < n) { if (g) { for (j=l;j<=n;j++) v[j][i]=(a[i][j]/a[i][l])/g; for (j=l;j<=n;j++) { for (s=0.0,k=l;k<=n;k++) s += a[i][k]*v[k][j]; for (k=l;k<=n;k++) v[k][j] += s*v[k][i]; } } for (j=l;j<=n;j++) v[i][j]=v[j][i]=0.0; } v[i][i]=1.0; g=rv1[i]; l=i; } for (i=IMIN(m,n);i>=1;i--) { l=i+1; g=w[i]; for (j=l;j<=n;j++) a[i][j]=0.0; if (g) { g=1.0/g; for (j=l;j<=n;j++) { for (s=0.0,k=l;k<=m;k++) s += a[k][i]*a[k][j]; f=(s/a[i][i])*g; for (k=i;k<=m;k++) a[k][j] += f*a[k][i]; } for (j=i;j<=m;j++) a[j][i] *= g; } else for (j=i;j<=m;j++) a[j][i]=0.0; ++a[i][i]; } for (k=n;k>=1;k--) { for (its=1;its<=30;its++) { flag=1; for (l=k;l>=1;l--) { nm=l-1; if ((float)(fabs(rv1[l])+anorm) == anorm) { flag=0; break; } if ((float)(fabs(w[nm])+anorm) == anorm) break; } if (flag) { c=0.0; s=1.0; for (i=l;i<=k;i++) { f=s*rv1[i]; rv1[i]=c*rv1[i]; if ((float)(fabs(f)+anorm) == anorm) break; g=w[i]; h=pythag(f,g); w[i]=h; h=1.0/h; c=g*h; s = -f*h; for (j=1;j<=m;j++) { y=a[j][nm]; z=a[j][i]; a[j][nm]=y*c+z*s; a[j][i]=z*c-y*s; } } } z=w[k]; if (l == k) { if (z < 0.0) { w[k] = -z; for (j=1;j<=n;j++) v[j][k] = -v[j][k]; } break; } if (its == 30) { sprintf (MsgText, "No convergence in 30 svdcmp iterations"); n_error (MsgText); exit (1); } x=w[l]; nm=k-1; y=w[nm]; g=rv1[nm]; h=rv1[k]; f=((y-z)*(y+z)+(g-h)*(g+h))/(2.0*h*y); g=pythag(f,1.0); f=((x-z)*(x+z)+h*((y/(f+SIGN(g,f)))-h))/x; c=s=1.0; for (j=l;j<=nm;j++) { i=j+1; g=rv1[i]; y=w[i]; h=s*g; g=c*g; z=pythag(f,h); rv1[j]=z; c=f/z; s=h/z; f=x*c+g*s; g = g*c-x*s; h=y*s; y *= c; for (jj=1;jj<=n;jj++) { x=v[jj][j]; z=v[jj][i]; v[jj][j]=x*c+z*s; v[jj][i]=z*c-x*s; } z=pythag(f,h); w[j]=z; if (z) { z=1.0/z; c=f*z; s=h*z; } f=c*g+s*y; x=c*y-s*g; for (jj=1;jj<=m;jj++) { y=a[jj][j]; z=a[jj][i]; a[jj][j]=y*c+z*s; a[jj][i]=z*c-y*s; } } rv1[l]=0.0; rv1[k]=f; w[k]=x; } } free_vector(rv1,1,n); } static float pythag(float a, float b) { float absa,absb; absa=fabs(a); absb=fabs(b); if (absa > absb) return absa*sqrt(1.0+SQR(absb/absa)); else return (absb == 0.0 ? 0.0 : absb*sqrt(1.0+SQR(absa/absb))); } void fpoly(float x, float p[], int np) { int j; p[1]=1.0; for (j=2;j<=np;j++) p[j]=p[j-1]*x; } void piksrt (float arr[], int n) { int i,j; float a; for (j=2;j<=n;j++) { a=arr[j]; i=j-1; while (i > 0 && arr[i] > a) { arr[i+1]=arr[i]; i--; } arr[i+1]=a; } } void shell (float a[], int n) { int i,j,inc; float v; inc=1; do { inc *= 3; inc++; } while (inc <= n); do { inc /= 3; for (i=inc+1;i<=n;i++) { v=a[i]; j=i; while (a[j-inc] > v) { a[j]=a[j-inc]; j -= inc; if (j <= inc) break; } a[j]=v; } } while (inc > 1); } #define M 7 #define NSTACK 50 int sort(float arr[], int n) { int i,ir=n,j,k,l=1; int jstack=0,*istack; float a; int *ivector (int nl, int nh); void free_ivector (int *v, int nl, int nh); istack=ivector(1,NSTACK); if (istack == NULL) return (1); for (;;) { if (ir-l < M) { for (j=l+1;j<=ir;j++) { a=arr[j]; for (i=j-1;i>=l;i--) { if (arr[i] <= a) break; arr[i+1]=arr[i]; } arr[i+1]=a; } if (jstack == 0) break; ir=istack[jstack--]; l=istack[jstack--]; } else { k=(l+ir) >> 1; SWAP(arr[k],arr[l+1]) if (arr[l] > arr[ir]) { SWAP(arr[l],arr[ir]) } if (arr[l+1] > arr[ir]) { SWAP(arr[l+1],arr[ir]) } if (arr[l] > arr[l+1]) { SWAP(arr[l],arr[l+1]) } i=l+1; j=ir; a=arr[l+1]; for (;;) { do i++; while (arr[i] < a); do j--; while (arr[j] > a); if (j < i) break; SWAP(arr[i],arr[j]); } arr[l+1]=arr[j]; arr[j]=a; jstack += 2; if (jstack > NSTACK) { sprintf (MsgText, "NSTACK too small in sort"); n_error (MsgText); return (1); } if (ir-i+1 >= j-l) { istack[jstack]=ir; istack[jstack-1]=i; ir=j-1; } else { istack[jstack]=j-1; istack[jstack-1]=l; l=i; } } } free_ivector(istack,1,NSTACK); return (0); } #undef M #undef NSTACK #define JMAX 40 float rtbis(float (*func)(float), float soff, float x1, float x2, float xacc) { int j; float dx,f,fmid,xmid,rtb; f=(*func)(x1)-soff; fmid=(*func)(x2)-soff; if (f*fmid >= 0.0) { sprintf (MsgText,"Root must be bracketed for bisection in rtbis"); n_error (MsgText); return (0.0); } rtb = f < 0.0 ? (dx=x2-x1,x1) : (dx=x1-x2,x2); for (j=1;j<=JMAX;j++) { fmid=(*func)(xmid=rtb+(dx *= 0.5))-soff; if (fmid <= 0.0) rtb=xmid; if (fabs(dx) < xacc || fmid == 0.0) return rtb; } sprintf (MsgText, "Too many bisections in rtbis"); n_error (MsgText); return 0.0; } #undef JMAX void lfit (float x[], float y[], float sig[], int ndat, float a[], int ia[], int ma, float **covar, float *chisq, void (*funcs)(float, float [], int)) { int i,j,k,l,m,mfit=0; float ym,wt,sum,sig2i,**beta,*afunc; /*void covsrt(float **covar, int ma, int ia[], int mfit);*/ beta=matrix(1,ma,1,1); afunc=vector(1,ma); for (j=1;j<=ma;j++) if (ia[j]) mfit++; if (mfit == 0) return; for (j=1;j<=mfit;j++) { for (k=1;k<=mfit;k++) covar[j][k]=0.0; beta[j][1]=0.0; } for (i=1;i<=ndat;i++) { (*funcs)(x[i],afunc,ma); ym=y[i]; if (mfit < ma) { for (j=1;j<=ma;j++) if (!ia[j]) ym -= a[j]*afunc[j]; } sig2i=1.0/SQR(sig[i]); for (j=0,l=1;l<=ma;l++) { if (ia[l]) { wt=afunc[l]*sig2i; for (j++,k=0,m=1;m<=l;m++) if (ia[m]) covar[j][++k] += wt*afunc[m]; beta[j][1] += ym*wt; } } } for (j=2;j<=mfit;j++) for (k=1;k= big) { big=fabs(a[j][k]); irow=j; icol=k; } } else if (ipiv[k] > 1) return; } ++(ipiv[icol]); if (irow != icol) { for (l=1;l<=n;l++) SWAP(a[irow][l],a[icol][l]) for (l=1;l<=m;l++) SWAP(b[irow][l],b[icol][l]) } indxr[i]=irow; indxc[i]=icol; if (a[icol][icol] == 0.0) return; pivinv=1.0/a[icol][icol]; a[icol][icol]=1.0; for (l=1;l<=n;l++) a[icol][l] *= pivinv; for (l=1;l<=m;l++) b[icol][l] *= pivinv; for (ll=1;ll<=n;ll++) if (ll != icol) { dum=a[ll][icol]; a[ll][icol]=0.0; for (l=1;l<=n;l++) a[ll][l] -= a[icol][l]*dum; for (l=1;l<=m;l++) b[ll][l] -= b[icol][l]*dum; } } for (l=n;l>=1;l--) { if (indxr[l] != indxc[l]) for (k=1;k<=n;k++) SWAP(a[k][indxr[l]],a[k][indxc[l]]); } free_ivector(ipiv,1,n); free_ivector(indxr,1,n); free_ivector(indxc,1,n); } #define NR_END 1 #define FREE_ARG char* float *vector(int nl, int nh) /* allocate a float vector with subscript range v[nl..nh] */ { float *v; v=(float *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(float))); return v-nl+NR_END; } void free_vector(float *v, int nl, int nh) /* free a float vector allocated with vector() */ { free((FREE_ARG) (v+nl-NR_END)); } int *ivector(int nl, int nh) { /* allocate an int vector with subscript range v[nl..nh] */ int *v; v = NULL; v=(int *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(int))); return v-nl+NR_END; } void free_ivector(int *v, int nl, int nh) { /* free an int vector allocated with ivector */ free((FREE_ARG) (v+nl-NR_END)); } float **matrix(int nrl, int nrh, int ncl, int nch) /* allocate a float matrix with subscript range m[nrl..nrh][ncl..nch] */ { int i, nrow=nrh-nrl+1,ncol=nch-ncl+1; float **m; /* allocate pointers to rows */ m=(float **) malloc((size_t)((nrow+NR_END)*sizeof(float*))); if (!m) { sprintf (MsgText, "Memory allocation failure 1 in matrix"); n_error (MsgText); exit (1); } m += NR_END; m -= nrl; /* allocate rows and set pointers to them */ m[nrl]=(float *) malloc((size_t)((nrow*ncol+NR_END)*sizeof(float))); if (!m[nrl]) { sprintf (MsgText, "Memory allocation failure 2 in matrix"); n_error (MsgText); exit (1); } m[nrl] += NR_END; m[nrl] -= ncl; for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol; /* return pointer to array of pointers to rows */ return m; } void free_matrix(float **m, int nrl, int nrh, int ncl, int nch) /* free a float matrix allocated by matrix() */ { free((FREE_ARG) (m[nrl]+ncl-NR_END)); free((FREE_ARG) (m+nrl-NR_END)); } #undef NR_END #undef FREE_ARG