aboutsummaryrefslogtreecommitdiff
path: root/noao/onedspec/splot/eqwidthcp.x
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@gmail.com>2015-07-08 20:46:52 -0400
committerJoseph Hunkeler <jhunkeler@gmail.com>2015-07-08 20:46:52 -0400
commitfa080de7afc95aa1c19a6e6fc0e0708ced2eadc4 (patch)
treebdda434976bc09c864f2e4fa6f16ba1952b1e555 /noao/onedspec/splot/eqwidthcp.x
downloadiraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz
Initial commit
Diffstat (limited to 'noao/onedspec/splot/eqwidthcp.x')
-rw-r--r--noao/onedspec/splot/eqwidthcp.x240
1 files changed, 240 insertions, 0 deletions
diff --git a/noao/onedspec/splot/eqwidthcp.x b/noao/onedspec/splot/eqwidthcp.x
new file mode 100644
index 00000000..4fc4fd3d
--- /dev/null
+++ b/noao/onedspec/splot/eqwidthcp.x
@@ -0,0 +1,240 @@
+include <gset.h>
+
+
+# EQWIDTH_CP -- Equivalent width following algorithm provided by
+# Caty Pilachowski. This assumes a Gaussian line profile
+# and fits to the specified core level, the width at the
+# specified flux level above the core, and the specified
+# continuum. The line position is found by searching
+# near the vertical cursor for the nearest minimum.
+
+define LEFT 1 # Fit to left edge
+define RIGHT 2 # Fit to right edge
+define BOTH 3 # Fit to both edges
+
+procedure eqwidth_cp (sh, gfd, center, cont, ylevel, y, n, key, fd1, fd2,
+ xg, yg, sg, lg, pg, ng)
+
+pointer sh
+int gfd
+real center, cont, ylevel
+real y[n]
+int n
+int key
+int fd1, fd2
+pointer xg, yg, sg, lg, pg # Pointers to fit parameters
+int ng # Number of components
+
+int i, i1, i2, isrch, icore, edge
+double xleft, xright, rcore, rinter, yl, gfwhm, lfwhm, flux, eqw, w, w1, w2
+double xpara[3], ypara[3], coefs[3], xcore, ycore
+double shdr_lw(), shdr_wl()
+
+# Initialize reasonable values
+# isrch -- nr of pixels on either side of cursor to search for min
+
+data isrch /3/
+
+begin
+ # Check continuum.
+ if (cont <= 0.) {
+ call eprintf ("Continuum cannot be less than zero.\n")
+ return
+ }
+
+ # Determine which edges of the line to use.
+ switch (key) {
+ case 'a', 'l':
+ edge = LEFT
+ case 'b', 'r':
+ edge = RIGHT
+ default:
+ edge = BOTH
+ }
+
+ # Search for local minimum or maximum
+ icore = max (1, min (n, nint (shdr_wl (sh, double(center)))))
+ i1 = max (1, icore-isrch)
+ i2 = min (n, icore+isrch)
+
+ # If half lines is selected, restrict the search
+ if (edge == LEFT)
+ i2 = max (i2-2, icore+1)
+ if (edge == RIGHT)
+ i1 = min (i1+2, icore-1)
+
+ # Search for core.
+ # Someday it may be desirable to use parabolic interpolation
+ # to locate an estimated minimum or maximum for the region
+ do i = i1, i2 {
+ if (abs (y[i] - cont) > abs (y[icore] - cont))
+ icore = i
+ }
+
+ # Fit parabola to three points around minimum pixel
+ xpara[1] = icore - 1
+ xpara[2] = icore
+ xpara[3] = icore + 1
+ ypara[1] = y[icore-1]
+ ypara[2] = y[icore]
+ ypara[3] = y[icore+1]
+
+ call para (xpara, ypara, coefs)
+
+ # Compute pixel value at minimum
+ xcore = -coefs[2] / 2.0 / coefs[3]
+ ycore = coefs[1] + coefs[2] * xcore + coefs[3] * xcore**2
+
+ # Locate left and right line edges. If the ylevel is INDEF then use
+ # the half flux point.
+ if (IS_INDEF (ylevel))
+ yl = (cont + ycore) / 2.
+ else
+ yl = ylevel
+
+ rcore = abs (ycore - cont)
+ rinter = abs (yl - cont)
+
+ if (rcore <= rinter) {
+ call eprintf (
+ "Y cursor must be between the continuum and the line core\n")
+ return
+ }
+
+ # Bound flux level of interest
+ if ((edge == LEFT) || (edge == BOTH)) {
+ for (i=icore; i >= 1; i=i-1)
+ if (abs (y[i] - cont) < rinter)
+ break
+
+ if (i < 1) {
+ call eprintf ("Can't find left edge of line\n")
+ return
+ }
+
+ xleft = float (i) + (yl - y[i]) / (y[i+1] - y[i])
+ if (edge == LEFT)
+ xright = xcore + (xcore - xleft)
+ }
+
+ # Now bound the right side
+ if ((edge == RIGHT) || (edge == BOTH)) {
+ for (i=icore; i <= n; i=i+1)
+ if (abs (y[i] - cont) < rinter)
+ break
+
+ if (i > n) {
+ call eprintf ("Can't find right edge of line\n")
+ return
+ }
+
+ xright = float (i) - (yl - y[i]) / (y[i-1] - y[i])
+ if (edge == RIGHT)
+ xleft = xcore - (xright - xcore)
+ }
+
+ # Compute in wavelength
+ w = shdr_lw (sh, double(xcore))
+ w1 = shdr_lw (sh, double(xleft))
+ w2 = shdr_lw (sh, double(xright))
+
+ # Apply Gaussian model
+ gfwhm = 1.665109 * abs (w2 - w1) / 2. / sqrt (log (rcore/rinter))
+ lfwhm = 0.
+ rcore = ycore - cont
+ flux = 1.064467 * rcore * gfwhm
+ eqw = -flux / cont
+
+ call printf (
+ "center = %9.7g, eqw = %9.4g, gfwhm = %9.4g\n")
+ call pargd (w)
+ call pargd (eqw)
+ call pargd (gfwhm)
+
+ if (fd1 != NULL) {
+ call fprintf (fd1, " %9.7g %9.7g %9.6g %9.4g %9.6g %9.4g %9.4g\n")
+ call pargd (w)
+ call pargr (cont)
+ call pargd (flux)
+ call pargd (eqw)
+ call pargd (ycore - cont)
+ call pargd (gfwhm)
+ call pargd (lfwhm)
+ }
+ if (fd2 != NULL) {
+ call fprintf (fd2, " %9.7g %9.7g %9.6g %9.4g %9.6g %9.4g %9.4g\n")
+ call pargd (w)
+ call pargr (cont)
+ call pargd (flux)
+ call pargd (eqw)
+ call pargd (ycore - cont)
+ call pargd (gfwhm)
+ call pargd (lfwhm)
+ }
+
+ # Mark line computed
+ call gline (gfd, real(w), cont, real(w), real(ycore))
+ call gline (gfd, real(w1), real(yl), real(w2), real(yl))
+
+ w1 = w - 2 * gfwhm
+ w2 = cont + rcore * exp (-(1.665109*(w1-w)/gfwhm)**2)
+ call gseti (gfd, G_PLTYPE, 2)
+ call gseti (gfd, G_PLCOLOR, 2)
+ call gamove (gfd, real(w1), real(w2))
+ for (; w1 <= w+2*gfwhm; w1=w1+0.05*gfwhm) {
+ w2 = cont + rcore * exp (-(1.665109*(w1-w)/gfwhm)**2)
+ call gadraw (gfd, real(w1), real(w2))
+ }
+ call gseti (gfd, G_PLTYPE, 1)
+ call gseti (gfd, G_PLCOLOR, 1)
+
+ # Save fit parameters
+ if (ng == 0) {
+ call malloc (xg, 1, TY_REAL)
+ call malloc (yg, 1, TY_REAL)
+ call malloc (sg, 1, TY_REAL)
+ call malloc (lg, 1, TY_REAL)
+ call malloc (pg, 1, TY_INT)
+ } else if (ng != 1) {
+ call realloc (xg, 1, TY_REAL)
+ call realloc (yg, 1, TY_REAL)
+ call realloc (sg, 1, TY_REAL)
+ call realloc (lg, 1, TY_REAL)
+ call realloc (pg, 1, TY_INT)
+ }
+ Memr[xg] = w
+ Memr[yg] = rcore
+ Memr[sg] = gfwhm
+ Memr[lg] = lfwhm
+ Memi[pg] = 1
+ ng = 1
+end
+
+# PARA -- Fit a parabola to three points
+
+procedure para (x, y, c)
+
+double x[3], y[3], c[3]
+double x12, x13, x23, x213, x223, y13, y23
+
+begin
+ x12 = x[1] - x[2]
+ x13 = x[1] - x[3]
+ x23 = x[2] - x[3]
+
+ if (x12 == 0. || x13 == 0. || x23 == 0.)
+ call error (1, "X points are not distinct")
+
+ # Compute relative to an origin at x[3]
+ x213 = x13 * x13
+ x223 = x23 * x23
+ y13 = y[1] - y[3]
+ y23 = y[2] - y[3]
+ c[3] = (y13 - y23 * x13 / x23) / (x213 - x223 * x13 / x23)
+ c[2] = (y23 - c[3] * x223) / x23
+ c[1] = y[3]
+
+ # Compute relative to an origin at 0.
+ c[1] = c[1] - x[3] * (c[2] - c[3] * x[3])
+ c[2] = c[2] - 2 * c[3] * x[3]
+end