diff options
author | Joe Hunkeler <jhunkeler@gmail.com> | 2015-08-11 16:51:37 -0400 |
---|---|---|
committer | Joe Hunkeler <jhunkeler@gmail.com> | 2015-08-11 16:51:37 -0400 |
commit | 40e5a5811c6ffce9b0974e93cdd927cbcf60c157 (patch) | |
tree | 4464880c571602d54f6ae114729bf62a89518057 /noao/onedspec/splot/deblend.x | |
download | iraf-osx-40e5a5811c6ffce9b0974e93cdd927cbcf60c157.tar.gz |
Repatch (from linux) of OSX IRAF
Diffstat (limited to 'noao/onedspec/splot/deblend.x')
-rw-r--r-- | noao/onedspec/splot/deblend.x | 627 |
1 files changed, 627 insertions, 0 deletions
diff --git a/noao/onedspec/splot/deblend.x b/noao/onedspec/splot/deblend.x new file mode 100644 index 00000000..d43a9d52 --- /dev/null +++ b/noao/onedspec/splot/deblend.x @@ -0,0 +1,627 @@ +include <math.h> +include <mach.h> + +# Profile types. +define GAUSS 1 # Gaussian profile +define LORENTZ 2 # Lorentzian profile +define VOIGT 3 # Voigt profile + +# Elements of fit array. +define BKG 1 # Background +define POS 2 # Position +define INT 3 # Intensity +define GAU 4 # Gaussian FWHM +define LOR 5 # Lorentzian FWHM + +# Type of constraints. +define FIXED 1 # Fixed parameter +define SINGLE 2 # Fit a single value for all lines +define INDEP 3 # Fit independent values for all lines + + +# DOFIT -- Fit line profiles. This is an interface to DOFIT1 +# which puts parameters into the required form and vice-versa. +# It also implements a constrained approach to the solution. + +procedure dofit (fit, x, y, s, npts, dx, nsub, y1, dy, + xp, yp, gp, lp, tp, np, chisq) + +int fit[5] # Fit constraints +real x[npts] # X data +real y[npts] # Y data +real s[npts] # Sigma data +int npts # Number of points +real dx # Pixel size +int nsub # Number of subpixels +real y1 # Continuum offset +real dy # Continuum slope +real xp[np] # Profile positions +real yp[np] # Profile intensities +real gp[np] # Profile Gaussian FWHM +real lp[np] # Profile Lorentzian FWHM +int tp[np] # Profile type +int np # Number of profiles +real chisq # Chi squared + +int i, j, fit1[5] +pointer sp, a, b +errchk dofit1 + +begin + call smark (sp) + call salloc (a, 8 + 5 * np, TY_REAL) + + # Convert positions and widths relative to first component. + Memr[a] = dx + Memr[a+1] = nsub + Memr[a+2] = y1 + Memr[a+3] = dy + Memr[a+4] = yp[1] + Memr[a+5] = xp[1] + Memr[a+6] = gp[1] + Memr[a+7] = lp[1] + do i = 1, np { + b = a + 5 * i + 3 + Memr[b] = yp[i] / Memr[a+4] + Memr[b+1] = xp[i] - Memr[a+5] + switch (tp[i]) { + case GAUSS: + if (Memr[a+6] == 0.) + Memr[a+6] = gp[i] + Memr[b+2] = gp[i] / Memr[a+6] + case LORENTZ: + if (Memr[a+7] == 0.) + Memr[a+7] = lp[i] + Memr[b+3] = lp[i] / Memr[a+7] + case VOIGT: + if (Memr[a+6] == 0.) + Memr[a+6] = gp[i] + Memr[b+2] = gp[i] / Memr[a+6] + if (Memr[a+7] == 0.) + Memr[a+7] = lp[i] + Memr[b+3] = lp[i] / Memr[a+7] + } + Memr[b+4] = tp[i] + } + + # Do fit. + fit1[INT] = fit[INT] + do i = 1, fit[BKG] { + fit1[BKG] = i + fit1[GAU] = min (SINGLE, fit[GAU]) + fit1[LOR] = min (SINGLE, fit[LOR]) + do j = FIXED, fit[POS] { + fit1[POS] = j + if (np > 1 || j != INDEP) + call dofit1 (fit1, x, y, s, npts, Memr[a], np, chisq) + } + if (np > 1 && (fit[GAU] == INDEP || fit[LOR] == INDEP)) { + fit1[GAU] = fit[GAU] + fit1[LOR] = fit[LOR] + call dofit1 (fit1, x, y, s, npts, Memr[a], np, chisq) + } + } + + y1 = Memr[a+2] + dy = Memr[a+3] + do i = 1, np { + b = a + 5 * i + 3 + yp[i] = Memr[b] * Memr[a+4] + xp[i] = Memr[b+1] + Memr[a+5] + switch (tp[i]) { + case GAUSS: + gp[i] = abs (Memr[b+2] * Memr[a+6]) + case LORENTZ: + lp[i] = abs (Memr[b+3] * Memr[a+7]) + case VOIGT: + gp[i] = abs (Memr[b+2] * Memr[a+6]) + lp[i] = abs (Memr[b+3] * Memr[a+7]) + } + } + + call sfree (sp) +end + + +# DOREFIT -- Refit line profiles. This assumes the input is very close +# to the final solution and minimizes the number of calls to the +# fitting routines. This is intended for efficient use in the +# in computing bootstrap error estimates. + +procedure dorefit (fit, x, y, s, npts, dx, nsub, y1, dy, + xp, yp, gp, lp, tp, np, chisq) + +int fit[5] # Fit constraints +real x[npts] # X data +real y[npts] # Y data +real s[npts] # Sigma data +int npts # Number of points +real dx # Pixel size +int nsub # Number of subpixels +real y1 # Continuum offset +real dy # Continuum slope +real xp[np] # Profile positions +real yp[np] # Profile intensities +real gp[np] # Profile Gaussian FWHM +real lp[np] # Profile Lorentzian FWHM +int tp[np] # Profile type +int np # Number of profiles +real chisq # Chi squared + +int i +pointer sp, a, b +errchk dofit1 + +begin + call smark (sp) + call salloc (a, 8 + 5 * np, TY_REAL) + + # Convert positions and widths relative to first component. + Memr[a] = dx + Memr[a+1] = nsub + Memr[a+2] = y1 + Memr[a+3] = dy + Memr[a+4] = yp[1] + Memr[a+5] = xp[1] + Memr[a+6] = gp[1] + Memr[a+7] = lp[1] + do i = 1, np { + b = a + 5 * i + 3 + Memr[b] = yp[i] / Memr[a+4] + Memr[b+1] = xp[i] - Memr[a+5] + switch (tp[i]) { + case GAUSS: + if (Memr[a+6] == 0.) + Memr[a+6] = gp[i] + Memr[b+2] = gp[i] / Memr[a+6] + case LORENTZ: + if (Memr[a+7] == 0.) + Memr[a+7] = lp[i] + Memr[b+3] = lp[i] / Memr[a+7] + case VOIGT: + if (Memr[a+6] == 0.) + Memr[a+6] = gp[i] + Memr[b+2] = gp[i] / Memr[a+6] + if (Memr[a+7] == 0.) + Memr[a+7] = lp[i] + Memr[b+3] = lp[i] / Memr[a+7] + } + Memr[b+4] = tp[i] + } + + # Do fit. + call dofit1 (fit, x, y, s, npts, Memr[a], np, chisq) + + y1 = Memr[a+2] + dy = Memr[a+3] + do i = 1, np { + b = a + 5 * i + 3 + yp[i] = Memr[b] * Memr[a+4] + xp[i] = Memr[b+1] + Memr[a+5] + switch (tp[i]) { + case GAUSS: + gp[i] = abs (Memr[b+2] * Memr[a+6]) + case LORENTZ: + lp[i] = abs (Memr[b+3] * Memr[a+7]) + case VOIGT: + gp[i] = abs (Memr[b+2] * Memr[a+6]) + lp[i] = abs (Memr[b+3] * Memr[a+7]) + } + } + + call sfree (sp) +end + + +# MODEL -- Compute model. + +real procedure model (x, dx, nsub, xp, yp, gp, lp, tp, np) + +real x # X value to be evaluated +real dx # Pixel width +int nsub # Number of subpixels +real xp[np] # Profile positions +real yp[np] # Profile intensities +real gp[np] # Profile Gaussian FWHM +real lp[np] # Profile Lorentzian FWHM +int tp[np] # Profile type +int np # Number of profiles + +int i, j +real delta, x1, y, arg1, arg2, v, v0, u + +begin + delta = dx / nsub + x1 = x - (dx + delta) / 2 + y = 0. + do j = 1, nsub { + x1 = x1 + delta + do i = 1, np { + switch (tp[i]) { + case GAUSS: + arg1 = 1.66511 * abs ((x1 - xp[i]) / gp[i]) + if (arg1 < 5.) + y = y + yp[i] * exp (-arg1**2) + case LORENTZ: + arg2 = abs ((x1 - xp[i]) / (lp[i] / 2)) + y = y + yp[i] / (1 + arg2**2) + case VOIGT: + arg1 = 1.66511 * (x1 - xp[i]) / gp[i] + arg2 = 0.832555 * lp[i] / gp[i] + call voigt (0., arg2, v0, u) + call voigt (arg1, arg2, v, u) + y = y + yp[i] * v / v0 + } + } + } + y = y / nsub + return (y) +end + + +# DERIVS -- Compute model and derivatives for MR_SOLVE procedure. +# This could be optimized more for the Voigt profile by reversing +# the do loops since v0 need only be computed once per line. + +procedure derivs (x, a, y, dyda, na) + +real x # X value to be evaluated +real a[na] # Parameters +real y # Function value +real dyda[na] # Derivatives +int na # Number of parameters + +int i, j, nsub +real dx, dx1, delta, x1, wg, wl, arg1, arg2, I0, dI, c, u, v, v0 + +begin + dx = a[1] + nsub = a[2] + delta = dx / nsub + dx1 = .1 * delta + x1 = x - (dx + delta) / 2 + y = 0. + do i = 1, na + dyda[i] = 0. + do j = 1, nsub { + x1 = x1 + delta + y = y + a[3] + a[4] * x1 + dyda[3] = dyda[3] + 1. + dyda[4] = dyda[4] + x1 + do i = 9, na, 5 { + switch (a[i+4]) { + case GAUSS: + I0 = a[5] * a[i] + wg = a[7] * a[i+2] + arg1 = 1.66511 * (x1 - a[6] - a[i+1]) / wg + if (abs (arg1) < 5.) { + dI = exp (-arg1**2) + c = I0 * dI * arg1 + y = y + I0 * dI + dyda[5] = dyda[5] + a[i] * dI + dyda[6] = dyda[6] + c / wg + dyda[7] = dyda[7] + c * arg1 / a[7] + dyda[i] = dyda[i] + a[5] * dI + dyda[i+1] = dyda[i+1] + c / wg + dyda[i+2] = dyda[i+2] + c * arg1 / a[i+2] + } + case LORENTZ: + I0 = a[5] * a[i] + wl = (a[8] * a[i+3] / 2) + arg2 = (x1 - a[6] - a[i+1]) / wl + dI = 1 / (1 + arg2**2) + c = 2 * I0 * dI * dI * arg2 + y = y + I0 * dI + dyda[5] = dyda[5] + a[i] * dI + dyda[6] = dyda[6] + c / wl + dyda[8] = dyda[8] + c * arg2 / a[8] + dyda[i] = dyda[i] + a[5] * dI + dyda[i+1] = dyda[i+1] + c / wl + dyda[i+3] = dyda[i+3] + c * arg2 / a[i+3] + case VOIGT: + a[7] = max (dx1, abs(a[7])) + a[8] = max (dx1, abs(a[8])) + a[i+2] = max (1E-6, abs(a[i+2])) + a[i+3] = max (1E-6, abs(a[i+3])) + + I0 = a[5] * a[i] + wg = a[7] * a[i+2] + wl = a[8] * a[i+3] + arg1 = 1.66511 * (x1 - a[6] - a[i+1]) / wg + arg2 = 0.832555 * wl / wg + call voigt (0., arg2, v0, u) + call voigt (arg1, arg2, v, u) + v = v / v0; u = u / v0 + dI = (1 - v) / (v0 * SQRTOFPI) + c = 2 * I0 * arg2 + y = y + I0 * v + dyda[5] = dyda[5] + a[i] * v + dyda[6] = dyda[6] + 2 * c * (arg1 * v - arg2 * u) / wl + dyda[7] = dyda[7] + + c * (dI + arg1 * (arg1 / arg2 * v - 2 * u)) / a[7] + dyda[8] = dyda[8] + c * (arg1 * u - dI) / a[8] + dyda[i] = dyda[i] + a[5] * v + dyda[i+1] = dyda[i+1] + 2 * c * (arg1 * v - arg2 * u) / wl + dyda[i+2] = dyda[i+2] + + c * (dI + arg1 * (arg1 / arg2 * v - 2 * u)) / a[i+2] + dyda[i+3] = dyda[i+3] + c * (arg1 * u - dI) / a[i+3] + } + } + } + y = y / nsub + do i = 1, na + dyda[i] = dyda[i] / nsub +end + + +# DOFIT1 -- Perform nonlinear iterative fit for the specified parameters. +# This uses the Levenberg-Marquardt method from NUMERICAL RECIPES. + +procedure dofit1 (fit, x, y, s, npts, a, nlines, chisq) + +int fit[5] # Fit constraints +real x[npts] # X data +real y[npts] # Y data +real s[npts] # Sigma data +int npts # Number of points +real a[ARB] # Fitting parameters +int nlines # Number of lines +real chisq # Chi squared + +int i, np, nfit +real mr, chi2 +pointer sp, flags, ptr +errchk mr_solve + +begin + # Number of terms is 5 for each line plus common background, center, + # intensity and widths. Also the pixel size and number of subpixels. + + np = 5 * nlines + 8 + + call smark (sp) + call salloc (flags, np, TY_INT) + ptr = flags + + # Background. + switch (fit[BKG]) { + case SINGLE: + Memi[ptr] = 3 + Memi[ptr+1] = 4 + ptr = ptr + 2 + } + + # Peaks. + switch (fit[INT]) { + case SINGLE: + Memi[ptr] = 5 + ptr = ptr + 1 + case INDEP: + do i = 1, nlines { + Memi[ptr] = 5 * i + 4 + ptr = ptr + 1 + } + } + + # Positions. + switch (fit[POS]) { + case SINGLE: + Memi[ptr] = 6 + ptr = ptr + 1 + case INDEP: + do i = 1, nlines { + Memi[ptr] = 5 * i + 5 + ptr = ptr + 1 + } + } + + # Gaussian FWHM. + switch (fit[GAU]) { + case SINGLE: + Memi[ptr] = 7 + ptr = ptr + 1 + case INDEP: + do i = 1, nlines { + Memi[ptr] = 5 * i + 6 + ptr = ptr + 1 + } + } + + # Lorentzian FWHM. + switch (fit[LOR]) { + case SINGLE: + Memi[ptr] = 8 + ptr = ptr + 1 + case INDEP: + do i = 1, nlines { + Memi[ptr] = 5 * i + 7 + ptr = ptr + 1 + } + } + + nfit = ptr - flags + mr = -1. + i = 0 + chi2 = MAX_REAL + repeat { + call mr_solve (x, y, s, npts, a, Memi[flags], np, nfit, mr, chisq) + if (chi2 - chisq > 0.0001) + i = 0 + else + i = i + 1 + chi2 = chisq + } until (i == 5) + + mr = 0. + call mr_solve (x, y, s, npts, a, Memi[flags], np, nfit, mr, chisq) + + call sfree (sp) +end + + +# MR_SOLVE -- Levenberg-Marquardt nonlinear chi square minimization. +# +# Use the Levenberg-Marquardt method to minimize the chi squared of a set +# of paraemters. The parameters being fit are indexed by the flag array. +# To initialize the Marquardt parameter, MR, is less than zero. After that +# the parameter is adjusted as needed. To finish set the parameter to zero +# to free memory. This procedure requires a subroutine, DERIVS, which +# takes the derivatives of the function being fit with respect to the +# parameters. There is no limitation on the number of parameters or +# data points. For a description of the method see NUMERICAL RECIPES +# by Press, Flannery, Teukolsky, and Vetterling, p523. + +procedure mr_solve (x, y, s, npts, params, flags, np, nfit, mr, chisq) + +real x[npts] # X data array +real y[npts] # Y data array +real s[npts] # Sigma data array +int npts # Number of data points +real params[np] # Parameter array +int flags[np] # Flag array indexing parameters to fit +int np # Number of parameters +int nfit # Number of parameters to fit +real mr # MR parameter +real chisq # Chi square of fit + +int i +real chisq1 +pointer new, a1, a2, delta1, delta2 + +errchk mr_invert + +begin + # Allocate memory and initialize. + if (mr < 0.) { + call mfree (new, TY_REAL) + call mfree (a1, TY_REAL) + call mfree (a2, TY_REAL) + call mfree (delta1, TY_REAL) + call mfree (delta2, TY_REAL) + + call malloc (new, np, TY_REAL) + call malloc (a1, nfit*nfit, TY_REAL) + call malloc (a2, nfit*nfit, TY_REAL) + call malloc (delta1, nfit, TY_REAL) + call malloc (delta2, nfit, TY_REAL) + + call amovr (params, Memr[new], np) + call mr_eval (x, y, s, npts, Memr[new], flags, np, Memr[a2], + Memr[delta2], nfit, chisq) + mr = 0.001 + } + + # Restore last good fit and apply the Marquardt parameter. + call amovr (Memr[a2], Memr[a1], nfit * nfit) + call amovr (Memr[delta2], Memr[delta1], nfit) + do i = 1, nfit + Memr[a1+(i-1)*(nfit+1)] = Memr[a2+(i-1)*(nfit+1)] * (1. + mr) + + # Matrix solution. + call mr_invert (Memr[a1], Memr[delta1], nfit) + + # Compute the new values and curvature matrix. + do i = 1, nfit + Memr[new+flags[i]-1] = params[flags[i]] + Memr[delta1+i-1] + call mr_eval (x, y, s, npts, Memr[new], flags, np, Memr[a1], + Memr[delta1], nfit, chisq1) + + # Check if chisq has improved. + if (chisq1 < chisq) { + mr = max (EPSILONR, 0.1 * mr) + chisq = chisq1 + call amovr (Memr[a1], Memr[a2], nfit * nfit) + call amovr (Memr[delta1], Memr[delta2], nfit) + call amovr (Memr[new], params, np) + } else + mr = 10. * mr + + if (mr == 0.) { + call mfree (new, TY_REAL) + call mfree (a1, TY_REAL) + call mfree (a2, TY_REAL) + call mfree (delta1, TY_REAL) + call mfree (delta2, TY_REAL) + } +end + + +# MR_EVAL -- Evaluate curvature matrix. This calls procedure DERIVS. + +procedure mr_eval (x, y, s, npts, params, flags, np, a, delta, nfit, chisq) + +real x[npts] # X data array +real y[npts] # Y data array +real s[npts] # Sigma data array +int npts # Number of data points +real params[np] # Parameter array +int flags[np] # Flag array indexing parameters to fit +int np # Number of parameters +real a[nfit,nfit] # Curvature matrix +real delta[nfit] # Delta array +int nfit # Number of parameters to fit +real chisq # Chi square of fit + +int i, j, k +real ymod, dy, dydpj, dydpk, sig2i +pointer sp, dydp + +begin + call smark (sp) + call salloc (dydp, np, TY_REAL) + + do j = 1, nfit { + do k = 1, j + a[j,k] = 0. + delta[j] = 0. + } + + chisq = 0. + do i = 1, npts { + call derivs (x[i], params, ymod, Memr[dydp], np) + if (IS_INDEF(ymod)) + next + sig2i = 1. / (s[i] * s[i]) + dy = y[i] - ymod + do j = 1, nfit { + dydpj = Memr[dydp+flags[j]-1] * sig2i + delta[j] = delta[j] + dy * dydpj + do k = 1, j { + dydpk = Memr[dydp+flags[k]-1] + a[j,k] = a[j,k] + dydpj * dydpk + } + } + chisq = chisq + dy * dy * sig2i + } + + do j = 2, nfit + do k = 1, j-1 + a[k,j] = a[j,k] + + call sfree (sp) +end + + +# MR_INVERT -- Solve a set of linear equations using Householder transforms. + +procedure mr_invert (a, b, n) + +real a[n,n] # Input matrix and returned inverse +real b[n] # Input RHS vector and returned solution +int n # Dimension of input matrices + +int krank +real rnorm +pointer sp, h, g, ip + +begin + call smark (sp) + call salloc (h, n, TY_REAL) + call salloc (g, n, TY_REAL) + call salloc (ip, n, TY_INT) + + call hfti (a, n, n, n, b, n, 1, 1E-10, krank, rnorm, + Memr[h], Memr[g], Memi[ip]) + + call sfree (sp) +end |