diff options
author | Joseph Hunkeler <jhunkeler@gmail.com> | 2015-07-08 20:46:52 -0400 |
---|---|---|
committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2015-07-08 20:46:52 -0400 |
commit | fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4 (patch) | |
tree | bdda434976bc09c864f2e4fa6f16ba1952b1e555 /math/curfit/curfit.sem | |
download | iraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz |
Initial commit
Diffstat (limited to 'math/curfit/curfit.sem')
-rw-r--r-- | math/curfit/curfit.sem | 708 |
1 files changed, 708 insertions, 0 deletions
diff --git a/math/curfit/curfit.sem b/math/curfit/curfit.sem new file mode 100644 index 00000000..28058626 --- /dev/null +++ b/math/curfit/curfit.sem @@ -0,0 +1,708 @@ +# Semi-code for curfit.h + +# define the permitted types of curves + +define CHEBYSHEV 1 +define LEGENDRE 2 +define L2SPLINE4 3 + +# define the weighting flags + +define NORMAL 1 # user enters weights +define UNIFORM 2 # equal weights, weight 1.0 +define SPACING 3 # weigth proportional to spacing of data points + +define SPLINE_ORDER 4 + +# set up the curve fitting structure + +define LEN_CVSTRUCT + +struct curfit { + +define CV_TYPE Memi[] # Type of curve to be fitted +define CV_ORDER Memi[] # Order of the fit +define CV_NPIECES Memi[] # Number of polynomial pieces, spline +define CV_NCOEFF Memi[] # Number of coefficients +define CV_XMAX Memr[] # Maximum x value +define CV_XMIN Memr[] # Minimum x value +define CV_RANGE Memr[] # Xmax minus xmin +define CV_MAXMIN Memr[] # Xmax plus xmin +define CV_SPACING Memr[] # Knot spacing for splines +define CV_YNORM Memr[] # Norm of the Y vector +define CV_NPTS Memi[] # Number of data points + +define CV_MATRIX Memi[] # Pointer to original matrix +define CV_CHOFAC Memi[] # Pointer to Cholesky factorization +define CV_BASIS Memi[] # Pointer to basis functions +define CV_VECTOR Memi[] # Pointer to vector +define CV_COEFF Memi[] # Pointer to coefficient vector +define CV_LEFT Memi[] # + +} + +# matrix and vector element definitions + +define MATRIX Memr[$1+($2-1)*NCOEFF(cv)] # Matrix element +define CHOFAC Memr[$1+($2-1)*NCOEFF(cv)] # Triangular matrix +define VECTOR Memr[$1+$2] # Right side +define COEFF Memr[$1+$2] # Coefficient vector +define LEFT Memi[$1+$2] + +# matrix and vector definitions + +define MAT Memr[$1] +define CHO Memr[$1] +define VECT Memr[$1] +define COF Memr[$1] + +# semi-code for the initialization procedure + +include "curfit.h" + +# CVINIT -- Procedure to set up the curve descriptor. + +procedure cvinit (cv, curve_type, order, xmin, xmax) + +pointer cv # pointer to curve descriptor structure +int curve_type # type of curve to be fitted +int order # order of curve to be fitted, or in the case of the + # spline the number of polynomial pieces to be fit +real xmin # minimum value of x +real xmax # maximum value of x + +begin + # allocate space for the curve descriptor + call smark (sp) + call salloc (cv, LEN_CVSTRUCT, TY_STRUCT) + + if (order < 1) + call error (0, "CVINIT: Illegal order.") + + if (xmax <= xmin) + call error (0, "CVINIT: xmax <= xmin.") + + switch (curve_type) { + case CHEBYSHEV, LEGENDRE: + CV_ORDER(cv) = order + CV_NCOEFF(CV) = order + CV_RANGE(cv) = xmax - xmin + CV_MAXMIN(cv) = xmax + xmin + case L2SPLINE4: + CV_ORDER(cv) = SPLINE_ORDER + CV_NCOEFF(cv) = order + SPLINE_ORDER - 1 + CV_NPIECES(cv) = order + CV_SPACING(cv) = (xmax - xmin) / order + default: + call error (0, "CVINIT: Unknown curve type.") + } + + CV_TYPE(cv) = curve_type + CV_XMIN(cv) = xmin + CV_XMAX(cv) = xmax + + # allocate space for the matrix and vectors + call calloc (CV_MATRIX(cv), CV_ORDER(cv)*CV_NCOEFF(cv), TY_REAL) + call calloc (CV_CHOFAC(cv), CV_ORDER(cv)*CV_NCOEFF(cv), TY_REAL) + call calloc (CV_VECTOR(cv), CV_NCOEFF(cv), TY_REAL) + call calloc (CV_COEFF(cv), CV_NCOEFF(cv), TY_REAL) + + # initialize pointer to basis functions to null + CV_BASIS(cv) = NULL + + CV_NPTS(cv) = 0 + CV_YNORM(cv) = 0. +end + +# semi-code for cvaccum + +include "curfit.h" + +# CVACCUM -- Procedure to add a single point to the data set. + +procedure cvaccum (cv, x, y, w, wtflag) + +pointer cv # curve descriptor +real x # x value +real y # y value +real w # weight of the data point +int wtflag # type of weighting desired + +begin + # calculate the weights + switch (wtflag) { + case UNIFORM: + w = 1.0 + case NORMAL, SPACING: # problem spacing + default: + w = 1.0 + } + + # caculate all non-zero basis functions for a given data point + switch (CV_TYPE(cv)) { + case CHEBYSHEV: + left = 1 + call chebyshev (cv, x, basis) + case LEGENDRE: + left = 1 + call legendre (cv, x, basis) + case L2SPLINE4: + call l2spline4 (cv, x, left, basis) + } + + # accumulate into the matrix + leftm1 = left - 1 + vptr = CV_VECTOR(cv) - 1 + do i = 1, CV_ORDER(cv) { + bw = basis[i] * w + jj = leftm1 + i + mptr = CV_MATRIX(cv) + jj - 1 + VECTOR(vptr, jj) = VECTOR(vptr, jj) + bw * y + ii = 1 + do j = i, CV_ORDER(cv) { + MATRIX(mptr, ii) = MATRIX(mptr, ii) + basis[j] * bw + ii = ii + 1 + } + } + + CV_NPTS(cv) = CV_NPTS(cv) + 1 + CV_YNORM(cv) = CV_YNORM(cv) + w * y * y +end + +# semi-code for cvreject + +include "curfit.h" + +# CVREJECT -- Procedure to subtract a single datapoint from the data set +# to be fitted. + +procedure cvreject (cv, x, y, w) + +pointer cv # curve fitting image descriptor +real x # x value +real y # y value +real w # weight of the data point + +begin + # caculate all type non-zero basis functions for a given data point + switch (CV_TYPE(cv)) { + case CHEBYSHEV: + left = 1 + call chebyshev (cv, x, basis) + case LEGENDRE: + left = 1 + call legendre (cv, x, basis) + case L2SPLINE4: + call l2spline4 (cv, x, left, basis) + } + + # subtract the data point from the matrix + leftm1 = left - 1 + vptr = CV_VECTOR(cv) - 1 + do i = 1, CV_ORDER(cv) { + bw = basis[i] * w + jj = leftm1 + i + mptr = CV_MATRIX(cv) + jj - 1 + VECTOR(vptr, jj) = VECTOR(vptr, jj) - bw * y + ii = 1 + do j = i, CV_ORDER(cv) { + MATRIX(mptr, ii) = MATRIX(mptr, ii) - basis[j] * bw + ii = ii + 1 + } + } + + CV_NPTS(cv) = CV_NPTS(cv) - 1 + CV_NORM(cv) = CV_NORM(cv) - w * y * y +end + +# semi-code for cvsolve + +include "curfit.h" + +# CVSOLVE -- Procedure to solve a matrix equation of the form Ax = B. +# The Cholesky factorization of matrix A is calculated in the first +# step, followed by forward and back substitution to solve for the vector +# x. + +procedure cvsolve (cv, ier) + +pointer cv # pointer to the image descriptor structure +int ier # ier = 0, everything OK + # ier = 1, matrix is singular + +begin + # solve matrix by adapting Deboor's bchfac.f and bchslv.f routines + # so that the original matrix and vector are not destroyed + + call chofac (MAT(CV_MATRIX(cv)), CV_ORDER(cv), CV_NCOEFF(cv), + CHO(CV_CHOFAC(cv)), ier) + call choslv (CHO(CV_CHOFAC(cv)), CV_ORDER(cv), CV_NCOEFF(cv), + VECT(CV_VECTOR(cv)), COF(CV_COEFF(cv))) +end + +# semi-code for cvfit + +include "curfit.h" + +# CVFIT -- Procedure to fit a curve to an array of data points x and y with +# weights w. + +procedure cvfit (x, y, w, npts, wtflag, ier) + +real x[npts] # array of abcissa +real y[npts] # array of ordinates +real w[npts] # array of weights +int wtflag # type of weighting +int ier + +begin + # calculate weights + switch (wtflag) { + case UNIFORM: + call amovkr (1., w, npts) + case SPACING: + w[1] = x[2] - x[1] # check for npts > 1 + do i = 2, npts - 1 + w[i] = x[i+1] - x[i-1] + w[npts] = x[npts] - x[npts-1] + case NORMAL: + default: + call amovkr (1., w, npts) + } + + # accumulate data points + do i = 1, npts { + + CV_NPTS(cv) = CV_NPTS(cv) + 1 + + # calculate the norm of the Y vector + CV_YNORM(cv) = CV_YNORM(cv) + w[i] * y[i] * y[i] + + # calculate non zero basis functions + switch (CV_TYPE(cv)) { + case CHEBYSHEV: + left = 1 + call chebyshev (cv, x, basis) + case LEGENDRE: + left = 1 + call legendre (cv, x, basis) + case L2SPLINE4: + call l2spline4 (cv, x, left, basis) + } + + # accumulate the matrix + leftm1 = left - 1 + vptr = CV_VECTOR(cv) - 1 + do i = 1, CV_ORDER(cv) { + bw = basis[i] * w + jj = leftm1 + i + mptr = CV_MATRIX(cv) + jj - 1 + VECTOR(vptr, jj) = VECTOR(vptr, jj) + bw * y + ii = 1 + do j = i, CV_ORDER(cv) { + MATRIX(mptr, ii) = MATRIX(mptr, ii) + basis[j] * bw + ii = ii + 1 + } + } + } + + # solve the matrix + ier = 0 + call chofac (MAT(CV_MATRIX(cv)), CV_ORDER(cv), CV_NCOEFF(cv), + CHO(CV_CHOFAC(cv)), ier) + call choslv (CHO(CV_CHOFAC(cv)), CV_ORDER(cv), CV_NCOEFF(cv), + VECT(CV_VECTOR(cv)), COF(CV_COEFF(cv))) +end + +# semi-code for cvrefit + +include "curfit.com" + +# CV_REFIT -- Procedure to refit the data assuming that the x and w values do +# not change. + +procedure cvrefit (cv, x, y, w, ier) + +pointer cv +real x[ARB] +real y[ARB] +real w[ARB] +int ier + +begin + # if first call to refit then calculate and store the basis + # functions + + vcptr = CV_VECTOR(cv) - 1 + do i = 1, NCOEFF(cv) + VECTOR(vcptr+i) = 0. + + CV_YNORM(cv) = 0. + lptr = CV_LEFT(cv) - 1 + bcptr = CV_BASIS(cv) - CV_NPTS(cv) + + if (CV_BASIS(cv) == NULL) { + + call calloc (CV_BASIS(cv), CV_NPTS(cv)*CV_ORDER(cv), TY_REAL) + call calloc (CV_LEFT(cv), CV_NPTS(cv), TY_INT) + + do l = 1, CV_NPTS(cv) { + bptr = bcptr + l * CV_NPTS(cv) + switch (CV_TYPE(cv)) { + case LEGENDRE: + LEFT(lptr+l) = 1 + call legendre (cv, x, BASIS(bptr)) + case CHEBYSHEV: + LEFT(lptr+l) = 1 + call chebyshev (cv, x, BASIS(bptr)) + case L2SPLINE4: + call l2spline4 (cv, x, LEFT(lptr+l), BASIS(bptr)) + } + } + } + + # reset vector to zero + + # accumulate right side of the matrix equation + do l = 1, CV_NPTS(cv) { + + CV_YNORM(cv) = CV_YNORM(cv) + w[l] * y[l] * y[l] + leftm1 = LEFT(lptr+l) - 1 + bptr = bcptr + l * CV_NPTS(cv) + + do i = 1, CV_ORDER(cv) { + vptr = vcptr + leftm1 + i + VECTOR(vptr) = VECTOR(vptr) + BASIS(bptr) * w[l] * y[l] + } + } + + # solve the matrix + call choslv (CHOFAC(CV_CHOFAC(cv)), CV_ORDER(cv), CV_NCOEFF(CV), + VECTOR(CV_VECTOR(cv)), COEFF(CV_COEFF(cv))) +end + +# semi-code for cvcoeff + +# CVCOEFF -- Procedure to fetch the number and magnitude of the coefficients. + +procedure cvcoeff (cv, coeff, ncoeff) + +pointer cv # pointer to the curve fitting descriptor +real coeff[ncoeff] # the coefficients of the fit +int ncoeff # the number of coefficients + +begin + ncoeff = CV_NCOEFF(cv) + cptr = CV_COEFF(cv) - 1 + do i = 1, ncoeff + coeff[i] = COEFF(cptr, i) +end + +# semi-code for cvvector + +include "curfit.h" + +# CVVECTOR -- Procedure to evaluate the fitted curve + +procedure cvvector (cv, x, npts, yfit) + +pointer cv # pointer to the curve descriptor structure +real x[npts] # data x values +int npts # number of data points +real yfit[npts] # the fitted y values + +begin + do l = 1, npts { + + # calculate the non-zero basis functions + switch (CV_TYPE(cv) { + case LEGENDRE: + left = 1 + call legendre (cv, x[l], XBASIS(CV_XBASIS(cv))) + case CHEBYSHEV: + left = 1 + call chebyshev (cv, x[l], XBASIS(CV_XBASIS(cv))) + case L2SPLINE4: + call l2spline4 (cv, x[l], left, XBASIS(CV_XBASIS(cv))) + } + + sum = 0.0 + leftm1 = left - 1 + cptr = CV_COEFF(cv) - 1 + xptr = CV_XBASIS(cv) - 1 + + do i = 1, CV_NCOEFF(cv) { + jj = leftm1 + i + sum = sum + XBASIS(xptr + i) * COEFF(cptr + jj) + } + } +end + +# semi-code for cveval + +include "curfit.h" + +# CVEVAL -- Procedure to evaluate curve at a given x + +real procedure cveval (cv, x) + +pointer cv # pointer to image descriptor structure +real x # x value + +int left, leftm1, i +pointer cptr, xptr +real sum + +begin + switch (CV_TYPE(cv)) { + case CHEBYSHEV: + left = 1 + call chebyshev (cv, x, XBASIS(CV_XBASIS(cv))) + case LEGENDRE: + left = 1 + call legendre (cv, x, XBASIS(CV_XBASIS(cv))) + case L2SPLINE4: + call l2spline4 (cv, x, left, XBASIS(CV_XBASIS(cv))) + } + + sum = 0. + leftm1 = left - 1 + cptr = CV_COEFF(cv) - 1 + xptr = CV_XBASIS(cv) - 1 + do i = 1, CV_NCOEFF(cv) { + jj = leftm1 + i + sum = sum + XBASIS(xptr + i) * COEFF(cptr + jj) + } + + return (sum) +end + +# semi-code for cverrors + +include "curfit.h" + +# CVERRORS -- Procedure to calculate the standard deviation of the fit and the +# standard deviations of the coefficients + +procedure cverrors (cv, rms, errors) + +pointer cv # curve descriptor +real rms # standard deviation of data with respect to fit +real errors[ARB] # errors in coefficients + +begin + # calculate the variance + rms = CV_YNORM(cv) + cptr = CV_COEFF(cv) - 1 + vptr = CV_VECTOR(cv) - 1 + do i = 1, CV_NCOEFF(cv) + rms = rms - COEFF(cptr, i) * VECTOR(vptr, i) + rms = rms / (CV_NPTS(cv) - CV_NCOEFF(cv)) + + # calculate the standard deviations + do i = 1, CV_NCOEFF(cv) { + do j = 1, CV_NCOEFF(cv) + cov[j] = 0. + cov[i] = 1. + call choslv (CHO(CV_CHOFAC(cv)), CV_ORDER(cv), + CV_NCOEFF(cv), cov, cov) + errors[i] = sqrt (cov[i] * rms) + } + + rms = sqrt (rms) +end + +# semi-code for CVFREE + +# CVFREE -- Procedure to free the curve descriptor + +procedure cvfree (cv) + +pointer cv + +begin + call sfree (cv) +end + +include "curfit.h" + +# LEGENDRE -- Procedure to calculate the Legendre functions. + +procedure legendre (cv, x, basis) + +pointer cv +real x +real basis[ARB] + +begin + # normalize to the range x = -1. to 1. + xnorm = (2. * x - CV_MAXMIN(cv)) / CV_RANGE(cv) + + b[1] = 1.0 + if (CV_ORDER(cv) == 1) + return + + b[2] = xnorm + if (CV_ORDER(cv) == 2) + return + + do i = 3, CV_ORDER(cv) { + ri = i + b[i] = ((2.*ri-3.)*xnorm*b[i-1] - (ri-2.)*b[i-2]) / (ri-1.) + } +end + +# CHEBYSHEV -- Procedure to calculate Chebyshev polynomials. + +procedure chebyshev (cv, x, basis) + +real x +int order +real basis[ARB] + +begin + # normalize to the range -1. to 1. + xnorm = (2. * x - CV_MAXMIN(cv)) / CV_RANGE(cv) + + b[1] = 1. + if (CV_ORDER(cv) == 1) + return + + b[2] = xnorm + if (CV_ORDER(cv) == 2) + return + + do i = 3, CV_ORDER(cv) { + ri = i + b[i] = 2.*xnorm*b[i-1] - b[i-2] + } +end + +define NPTS_SPLINE 401 # Number of points in the spline lookup table +define INTERVALS 100 # Number of intervals per spline knot + +# L2SPLINE4 -- Procedure to calculate the cubic spline functions + +procedure (cv, x, left, basis) + +pointer cv +real x +int left +real basis[ARB] + +real table[NPTS_SPLINE] + +# data table containing the spline +include "table.dat" + +begin + xnorm = (x - CV_XMIN(cv)) / CV_SPACING(cv) + temp = min (int (xnorm), npieces - 1) + left = temp + 1 + xnorm = xnorm - temp + + near = int ((1. - xnorm + 0.5) * INTERVALS) + 1 + basis[1] = table[near] + near = table[near] + INTERVALS + basis[2] = table[near] + near = table[near] + INTERVALS + basis[3] = table[near] + near = table[near] + INTERVALS + basis[4] = table[near] +end + +# CHOFAC -- Routine to calculate the Cholesky factorization of a banded +# matrix. + +procedure chofac (matrix, nbands, nrows, matfac, ier) + +real matrix[nbands, nrows] +int nbands +int nrows +real matfac[nbands, nrows] +int ier + +begin + ier = 0 + + if (nrows == 1) { + if (matrix[1,1] .gt. 0.) + matfac[1,1] = 1./matrix[1,1] + return + } + + + # copy matrix into matfac + do n = 1, nrows { + do j = 1, nbands + matfac[j,n] = matrix[j,n] + } + + do n = 1, nrows { + + # test to see if matrix is singular + if (matfac[1,n] + matrix[1,n] <= matrix[1,n]) { + do j = 1, nbands + w[j,n] = 0. + ier = 1 + next + } + + matfac[1,n] = 1./matfac[1,n] + imax = min (nbands - 1, nrows - n) + if (imax < 1) + next + + jmax = imax + do i = 1, imax { + ratio = matfac[i+1,n] * matfac[1,n] + do j = 1, jmax + matfac[j,n+i] = matfac[j,n+i] - matfac[j+i,n] * ratio + jmax = jmax - 1 + matfac[i+1,n] = ratio + } + } +end + +# CHOSLV -- Solve the matrix whose Cholesky factorization was calculated in +# CHOFAC. + +procedure choslv (matfac, nbands, nrows, vector, coeff) + +real matfac[nbands,nrows] +int nbands +int nrows +real vector[nrows] +real coeff[nrows] + +begin + if (nrows == 1) { + coeff[1] = vector[1] * matfac[1,1] + return + } + + # copy vector to coefficients + do i = 1, nrows + coeff[i] = vector[i] + + # forward substitution + nbndm1 = nbands - 1 + do n = 1, nrows { + jmax = min (nbndm1, nrows - n) + if (jmax < 1) + next + do j = 1, jmax + coeff[j+n] = coeff[j+n] - matfac[j+1,n] * b[n] + } + + # back substitution + for (n = nrows; n > 0; n = n - 1) { + coeff[n] = coeff[n] * matfac[1,n] + jmax = min (nbndm1, nrows - 1) + if (jmax >= 1) { + do j = 1, jmax + coeff[n] = coeff[n] - matfac[j+1,n] * coeff[j+n] + } + } + +end |