diff options
Diffstat (limited to 'noao/rv/rvfitfunc.x')
-rw-r--r-- | noao/rv/rvfitfunc.x | 477 |
1 files changed, 477 insertions, 0 deletions
diff --git a/noao/rv/rvfitfunc.x b/noao/rv/rvfitfunc.x new file mode 100644 index 00000000..30248393 --- /dev/null +++ b/noao/rv/rvfitfunc.x @@ -0,0 +1,477 @@ +include <gset.h> +include "rvpackage.h" +include "rvflags.h" + +# RV_FIT - Fit the CCF in the specified region. Return the exact pixel +# shift and sigma of the fit. + +procedure rv_fit (rv, xcf, ycf, ledge, redge, npts, ishift, shift, sigma) + +pointer rv #I RV struct pointer +real xcf[ARB], ycf[ARB] #I Array of correlation peaks +int ledge #I Left edge to fit +int redge #I Right edge to fit +int npts #I Npts between edges +int ishift #I Initial index of shift +real shift #O Computed shift +real sigma #O Sigma of fit + +pointer gp +real hght, init, peak, c[4] +real a, b, thresh, fwhm +int i, tnum + +real rv_width(), center1d() +int rv_getshift() + +include "fitcom.com" +include "rvsinc.com" +define NPARS 4 + +begin + # Erase the old fit first. + call rv_erase_fit (rv, false) + RV_FITDONE(rv) = NO + RV_ERRCODE(rv) = OK + IS_DBLSTAR(rv) = NO + + # Do some window bounds checking. + if (ledge < (RV_WINCENTER(rv)-RV_WINDOW(rv)) || + redge > (RV_WINCENTER(rv)+RV_WINDOW(rv))) { + call rv_err_comment (rv, + "WARNING: Some points in fit are outside window bounds.", "") + if (RV_INTERACTIVE(rv) == YES) { + call rv_errmsg ( + "Warning: Some points in fit are outside window bounds.") + call tsleep (1) + } + } + + # Save some info + RV_ISHIFT(rv) = ishift + RV_ISTART(rv) = ledge + RV_IEND(rv) = redge + gp = RV_GP(rv) + + # Initialize some variables + tnum = RV_TEMPNUM(rv) + + # Do the fitting + switch (RV_FITFUNC(rv)) { + case GAUSSIAN: # call gaussian fitting + call rv_fgauss (rv, xcf, ycf, ledge, redge, npts, ishift, c, sigma) + if (RV_ERRCODE(rv) == ERR_FIT) { + if (c[3] <= 0.0) { + return + } else { + call rv_draw_fit (rv, gp, NO) + return + } + } + shift = c[2] + if (IS_INDEF(RV_BACKGROUND(rv))) + hght = c[1] + c[4] + else + hght = c[1] + RV_BACKGROUND(rv) + + case LORENTZIAN: # call lorentzian fitting + call rv_fgauss (rv, xcf, ycf, ledge, redge, npts, ishift, c, sigma) + #c[3] = abs (c[3]) + if (RV_ERRCODE(rv) == ERR_FIT) { + call rv_draw_fit (rv, gp, NO) + return + } + shift = c[2] + call lorentz (shift, 3, c, 4, hght) + hght = 2.0 * c[1] / c[3] + if (!IS_INDEF(RV_BACKGROUND(rv))) + hght = hght + RV_BACKGROUND(rv) + + case PARABOLA: # call parabola fitting routine + call rv_fparab (rv, xcf, ycf, ledge, redge, npts, ishift, c, sigma) + shift = -c[2] / (2. * c[3]) + hght = c[1] + (c[2] * shift) + (c[3] * shift * shift) + peak = c[1] - c[2]**2 / (4. * c[3]) + RV_FWHM(rv) = sqrt ( abs(-peak / (2. * c[3]))) + + case CENTER1D: + init = real (rv_getshift (ycf[ledge], npts, MAXIMUM)) + call alimr (ycf[ledge], npts, a, b) + #thresh = (b - a) - 0.01 + thresh = 0.0 + peak = center1d (init, ycf[ledge], npts, npts/5., 1, 2., thresh) + RV_HEIGHT(rv) = INDEF + RV_FWHM(rv) = INDEF + RV_ERROR(rv) = INDEFD + RV_R(rv) = INDEF + RV_DISP(rv) = INDEF + if (RV_GP(rv) != NULL && RV_INTERACTIVE(rv) == YES) { + call gpmark (gp, xcf[ledge], ycf[ledge], npts, 4, 2., 2.) + call gflush (gp) + } + + if (IS_INDEF(peak)) { # check for an error + RV_ERRCODE(rv) = ERR_FIT + return + } else { + shift = peak + (xcf[ledge] - 1.0) + + if (RV_GP(rv) != NULL && RV_INTERACTIVE(rv) == YES) { + call gline (gp, shift, ycf[ishift], shift, ycf[ishift]+0.1) + call gflush (gp) + } + } + RV_FITDONE(rv) = YES + return + + case SINC: + call rv_sinc (rv, shift, fwhm, hght) + RV_FWHM(rv) = fwhm + RV_SHIFT(rv) = shift + RV_ERROR(rv) = INDEFD + RV_R(rv) = INDEF + RV_DISP(rv) = INDEF + if (RV_GP(rv) != NULL && RV_INTERACTIVE(rv) == YES) + call gpmark (gp, xcf[ledge], ycf[ledge], npts, 4, 2., 2.) + RV_FITDONE(rv) = YES + if (IS_INDEF(fwhm)) { # no fwhm computed, so leave here + call rv_draw_fit (rv, gp, NO) + return + } + } + call amovr (c, COEFF(rv,1), NPARS) + RV_FWHM(rv) = rv_width (rv) + RV_HEIGHT(rv) = hght + + # Redraw the new points fit if they were changed. Also save new fit + # window parameters + if (ledge != RV_ISTART(rv) && RV_FITFUNC(rv) != SINC) { + if (gp != NULL && RV_INTERACTIVE(rv) == YES) { + call gseti (gp, G_PMLTYPE, GL_CLEAR) + call gpmark (gp, xcf[RV_ISTART(rv)], ycf[RV_ISTART(rv)], + (RV_IEND(rv)-RV_ISTART(rv)+1), 4, 2., 2.) + call gseti (gp, G_PMLTYPE, GL_SOLID) + call gpmark (gp, xcf[ledge], ycf[ledge], npts, 4, 2., 2.) + call gpline (gp, xcf[RV_ISTART(rv)], ycf[RV_ISTART(rv)], + (RV_IEND(rv)-RV_ISTART(rv)+1)) + call gflush (gp) + } + RV_ISTART(rv) = ledge + RV_IEND(rv) = ledge + npts + } + nfit = npts + + # Compute the antisymmetric part of correlation and velocity error + call realloc (RV_ANTISYM(rv), RV_CCFNPTS(rv), TY_REAL) + if (!IS_INDEF(RV_FWHM(rv))) { + call rv_antisym (rv, shift, hght, RV_FWHM(rv), ycf, RV_CCFNPTS(rv), + ANTISYM(rv,1), ccfvar, RV_ERROR(rv), RV_R(rv)) + } else { + RV_R(rv) = INDEF + if (RV_DCFLAG(rv) != -1) + RV_ERROR(rv) = sigma * RV_DELTAV(rv) + else + RV_ERROR(rv) = sigma + } + + # Now get the dispersion of the peak + if (RV_DCFLAG(rv) != -1 && !IS_INDEF(RV_FWHM(rv))) + RV_DISP(rv) = RV_FWHM(rv) * RV_DELTAV(rv) + else + RV_DISP(rv) = INDEF + + # Debugging info + if (DBG_DEBUG(rv) == YES && DBG_LEVEL(rv)>=2) { + call d_printf(DBG_FD(rv), "rvfitfunc:\n") + call d_printf(DBG_FD(rv), "\tledge=%d redge=%d npts=%d ishift=%d\n") + call pargi(ledge); call pargi(redge) + call pargi(npts); call pargi(ishift) + call d_printf(DBG_FD(rv), + "\tshift=%.4g sigma=%.4g fwhm=%.4g disp=%.4g hght=%.4g peak=%.4g\n") + call pargr(shift); call pargr(sigma); call pargr(RV_FWHM(rv)) + call pargr(RV_DISP(rv));call pargr(hght); call pargr(peak) + do i = 1, NPARS { + call d_printf (DBG_FD(rv), "\t c[%d]=%g +/- %g\n") + call pargi(i); call pargr(c[i]); call pargr (ECOEFF(rv,i)) + } + call flush (DBG_FD(rv)) + } + + # Put stuff in the common for the log + binshift = xcf[ishift] + + if (RV_ERRCODE(rv) == OK) { + RV_FITDONE(rv) = YES + RV_UPDATE(rv) = YES + } + + # Plot the computed fit. + call rv_draw_fit (rv, gp, NO) + + # Mark the background level. + if (RV_FITFUNC(rv) == GAUSSIAN || RV_FITFUNC(rv) == LORENTZIAN) { + if (RV_INTERACTIVE(rv) == YES) + call rv_draw_background (rv, gp) + } +end + + +# RV_WIDTH - Procedure to compute the width of the CCF. + +real procedure rv_width (rv) + +pointer rv #I RV struct pointer + +real fwhm, h, l, r, peak, shift +int gstati() + +include "fitcom.com" + +begin + # Now correct it for a fixed baseline + switch (RV_FITFUNC(rv)) { + case GAUSSIAN: + fwhm = sqrt (COEFF(rv,3)) * 2.35482 + l = COEFF(rv,2) - fwhm / 2. + r = COEFF(rv,2) + fwhm / 2. + call cgauss1d (l, 1, COEFF(rv,1), nfitpars, h) + case LORENTZIAN: + fwhm = 2. * abs (COEFF(rv,3)) + fwhm = abs (COEFF(rv,3)) # for new lorentzian + l = COEFF(rv,2) - fwhm / 2. + r = COEFF(rv,2) + fwhm / 2. + call lorentz (l, 1, COEFF(rv,1), nfitpars, h) + case PARABOLA: + peak = COEFF(rv,1) - COEFF(rv,2)**2 / (4. * COEFF(rv,3)) + fwhm = sqrt ( abs(- peak / (2. * COEFF(rv,3)))) + #return (fwhm) + shift = -COEFF(rv,2) / (2.*COEFF(rv,3)) + l = shift - fwhm / 2. + r = shift + fwhm / 2. + h = COEFF(rv,1) + COEFF(rv,2) * l + COEFF(rv,3) * l**2 + case CENTER1D: + return (INDEF) + case SINC: + # The structure parameters were computed before, we just need + # this to draw the marker. + l = RV_SHIFT(rv) - RV_FWHM(rv) / 2. + r = RV_SHIFT(rv) + RV_FWHM(rv) / 2. + h = RV_FWHM_Y(rv) + fwhm = RV_FWHM(rv) + } + RV_FWHM_Y(rv) = h + + # Now draw the line showing the width + if (RV_GP(rv) != NULL && RV_INTERACTIVE(rv) == YES) { + if (gstati(RV_GP(rv),G_PLCOLOR) != C_BACKGROUND) { + call gseti (RV_GP(rv), G_PLTYPE, GL_DASHED) + call gseti (RV_GP(rv), G_PLCOLOR, RV_LINECOLOR(rv)) + } + call gline (RV_GP(rv), l, h, r, h) + if (gstati(RV_GP(rv),G_PLCOLOR) != C_BACKGROUND) { + call gseti (RV_GP(rv), G_PLTYPE, GL_SOLID) + call gseti (RV_GP(rv), G_PLCOLOR, C_FOREGROUND) + } + call gflush (RV_GP(rv)) + } + + return (fwhm) +end + + +# RV_XFIT - Set the fitting endpoints as described for the 'g' keystroke +# command. + +procedure rv_xfit (rv, x, do_correction) + +pointer rv #I RV struct pointer +real x #I Current cursor x position +int do_correction #I Do heliocentric correction? + +real sregion, eregion, y +real shift, sigma +int istart, iend, ishift, npts, stat + +int rv_getshift(), rv_rvcorrect() + +include "fitcom.com" + +begin + sregion = x # get endpoints + call rv_getpts (rv, eregion, y, 2) + + npts = RV_CCFNPTS(rv) # Fit the region + call rv_fixx (sregion, eregion, WRKPIXX(rv,1), WRKPIXX(rv,npts)) + istart = int (npts/2 + 1 + sregion) + iend = int (npts/2 + 1 + eregion) + npts = int (iend - istart + 1) + nfit = npts + ishift = rv_getshift (WRKPIXY(rv,istart), npts, MAXIMUM) + + # now jump into the fitting routines + call rv_fit (rv, WRKPIXX(rv,1), WRKPIXY(rv,1), istart, iend, npts, + ishift+istart-1, shift, sigma) + if (RV_ERRCODE(rv) == ERR_FIT) { + if (RV_INTERACTIVE(rv) == YES) + call rv_errmsg ("Fit did not converge") + else + call rv_err_comment (rv, "Fit did not converge", "") + return + } + RV_SHIFT(rv) = shift + RV_SIGMA(rv) = sigma + + if (do_correction == YES) { + stat = rv_rvcorrect (rv, shift, sigma, RV_VOBS(rv), RV_VCOR(rv), + RV_ERROR(rv)) + if (stat != OK) { + call rv_err_comment (rv, + "WARNING: Heliocentric correction not done properly.", "") + } + if (RV_INTERACTIVE(rv) == YES) + call rv_writeln (rv, STDOUT) + } +end + + +# RV_YFIT - Fit the CCF based on the Y value of the cursor, as described +# for the 'y' keystroke command or the HEIGHT parameter. + +procedure rv_yfit (rv, y, do_correction) + +pointer rv #I RV struct pointer +real y #I Current Y cursor value +int do_correction #I Do heliocentric correction? + +real sregion, eregion +real shift, sigma, center +int istart, iend, ishift, npts, stat, i + +int rv_getshift(), rv_rvcorrect() + +include "fitcom.com" + +begin + # Search the array for the closest points in y + npts = RV_WINR(rv) - RV_WINL(rv) + 1 + center = RV_CCFNPTS(rv)/2 + 1 + WRKPIXX(rv,RV_WINCENTER(rv)) + i = int (center - RV_WINDOW(rv)) + ishift = rv_getshift (WRKPIXY(rv,i), npts, MAXIMUM) + i - 1 + i = 0 + while (WRKPIXY(rv,ishift-i) > y && i <= npts) { + sregion = WRKPIXX(rv, ishift-i) + i = i + 1 + } + i = 0 + while (WRKPIXY(rv, ishift+i) > y && i <= npts) { + eregion = WRKPIXX(rv, ishift+i) + i = i + 1 + } + + # Pick up at fitting routines + npts = RV_CCFNPTS(rv) + istart = int (npts/2 + 1 + sregion) + iend = int (npts/2 + 1 + eregion) + npts = (iend - istart + 1) + + # Do the minwidth/maxwidth/window constraints + call rv_fix_window (rv, 1., real(RV_CCFNPTS(rv)), y, WRKPIXX(rv,1), + WRKPIXY(rv,1), istart, iend, ishift, npts) + + # Go ahead and fit this puppy + call rv_fit (rv, WRKPIXX(rv,1), WRKPIXY(rv,1), istart, iend, + npts, ishift, shift, sigma) + if (RV_ERRCODE(rv) == ERR_FIT) { + if (RV_INTERACTIVE(rv) == YES) + call rv_errmsg ("Fit did not converge") + else + call rv_err_comment (rv, "Fit did not converge", "") + return + } + RV_SHIFT(rv) = shift + RV_SIGMA(rv) = sigma + + if (do_correction == YES) { + stat = rv_rvcorrect (rv, shift, sigma, RV_VOBS(rv), RV_VCOR(rv), + RV_ERROR(rv)) + if (RV_INTERACTIVE(rv) == YES) + call rv_writeln (rv, STDOUT) + } +end + + +# RV_FIX_WINDOW - Resize the fit window according to the minwidth/maxwidth +# constraint parameters. This routine also recenters the window on the +# initial guess at the shift so points are evenly spaced about the peak. +# Does a bounds check to avoid segmentation violations. + +procedure rv_fix_window (rv, x1, x2, y, xcf, ycf, istart, iend, ishift, npts) + +pointer rv #I RV struct pointer +real x1, x2 #I Bounds check +real y #I Threshold level +real xcf[ARB], ycf[ARB] #I CCF array +int istart #U Start pixel of fit +int iend #U End pixel of fit +int ishift #U Peak pixel of fit +int npts #U Npts in between + +int i, np1, np2 + +begin + if (npts < RV_MINWIDTH(rv)) { + np1 = RV_MINWIDTH(rv) - npts # Pad some points + istart = istart - (np1 / 2) + iend = iend + (np1 / 2) + if (mod(np1,2) == 1) + iend = iend + 1 + } else if (npts > RV_MAXWIDTH(rv)) { + np1 = npts - RV_MAXWIDTH(rv) # Delete some points + istart = istart + (np1 / 2) + iend = iend - (np1 / 2) + if (mod(np1,2) == 1) + iend = iend - 1 + } + npts = int (iend - istart + 1) + + # Next, we have to make sure we honor the original constraint that + # all points are above a certain level + if (npts > RV_MINWIDTH(rv)) { + i = istart + while (ycf[i] < y && i <= ishift) # Fix left side + i = i + 1 + if (i != istart) + istart = i #+ 1 + i = iend + while (ycf[i] < y && i >= ishift) # Fix right side + i = i - 1 + if (i != iend) + iend = i #- 1 + } + npts = int (iend - istart + 1) + + # Now recenter the window on the peak + np1 = ishift - istart + np2 = iend - ishift + if ((np1 - np2) < -1) { # Peak is left of center + istart = istart - abs(np1 - np2) / 2 + iend = iend - abs(np1 - np2) / 2 + } else if ((np1 - np2) > 1) { # Peak is right of center + istart = istart + abs(np1 - np2) / 2 + iend = iend + abs(np1 - np2) / 2 + } + npts = int (iend - istart + 1) + + # Lastly, make sure we aren't out of bounds after all this work + if (istart < x1) { + np1 = (x1 - istart) + istart = int (x1) + iend = iend + np1 + } + if (iend > x2) { + np1 = (iend - x2) + iend = int (x2) + istart = istart - np1 + } + npts = int (iend - istart + 1) # Update npts and return +end |