aboutsummaryrefslogtreecommitdiff
path: root/noao/onedspec/t_tweak.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/t_tweak.x
downloadiraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz
Initial commit
Diffstat (limited to 'noao/onedspec/t_tweak.x')
-rw-r--r--noao/onedspec/t_tweak.x1352
1 files changed, 1352 insertions, 0 deletions
diff --git a/noao/onedspec/t_tweak.x b/noao/onedspec/t_tweak.x
new file mode 100644
index 00000000..e50dccea
--- /dev/null
+++ b/noao/onedspec/t_tweak.x
@@ -0,0 +1,1352 @@
+include <error.h>
+include <gset.h>
+include <imset.h>
+include <imhdr.h>
+include <math.h>
+include <math/iminterp.h>
+include <pkg/gtools.h>
+include <smw.h>
+include <units.h>
+include <pkg/xtanswer.h>
+
+# Tweak data object definitions.
+define TWK_SLEN 999 # Length of sample region string
+define TWK_LEN 580 # Length of data object
+
+define TWK_TYPE Memc[P2C($1)] # Tweak type (maxchars=19)
+define TWK_SH Memi[$1+11] # Spectrum pointer
+define TWK_CAL Memi[$1+12] # Calibration pointer
+define TWK_WAVE Memi[$1+13] # Pointer to wavelengths
+define TWK_SPEC Memi[$1+14] # Pointer to calibrated spectrum
+define TWK_SHIFT Memr[P2R($1+15)] # Shift
+define TWK_DSHIFT Memr[P2R($1+16)] # Shift step
+define TWK_SCALE Memr[P2R($1+17)] # Scaling factor
+define TWK_DSCALE Memr[P2R($1+18)] # Scaling factor step
+define TWK_RG Memi[$1+19] # Range pointer
+define TWK_RMS Memr[P2R($1+20)] # RMS in sample regions
+define TWK_OFFSET Memr[P2R($1+21)] # Offset in graphs
+define TWK_BOX Memi[$1+22] # Boxcar smoothing size
+define TWK_THRESH Memr[P2R($1+23)] # Calibration threshold
+define TWK_SAMPLE Memc[P2C($1+30)] # Sample regions (maxchars=999)
+define TWK_HELP Memc[P2C($1+530)] # Help file (maxchars=99)
+
+# Tweak types.
+define SKYTWEAK 1 # Sky subtraction
+define TELLURIC 2 # Telluric division
+
+# Secondary graph types.
+define GNONE 0 # No graph
+define GCAL 1 # Graph calibration spectrum
+define GDATA 2 # Graph data spectrum
+
+
+# T_SKYTWEAK -- Sky subtract spectra with shift and scale tweaking.
+# The sky calibration spectra are scaled and shifted to best subtract
+# sky features. Automatic and interactive methods are provided.
+
+procedure t_skytweak ()
+
+pointer twk # TWK data object
+
+begin
+ call malloc (twk, TWK_LEN, TY_STRUCT)
+ call strcpy ("SKYTWEAK", TWK_TYPE(twk), 19)
+ call strcpy ("onedspec$doc/skytweak.key", TWK_HELP(twk), 99)
+ call tweak (twk)
+ call mfree (twk, TY_STRUCT)
+end
+
+
+# T_TELLURIC -- Correct spectra for telluric features.
+# The telluric calibration spectra are scaled by raising to a power (Beers law)
+# and shifted to best remove telluric features. Automatic and interactive
+# methods are provided.
+
+procedure t_telluric ()
+
+pointer twk # TWK data object
+
+begin
+ call malloc (twk, TWK_LEN, TY_STRUCT)
+ call strcpy ("TELLURIC", TWK_TYPE(twk), 19)
+ call strcpy ("onedspec$doc/telluric.key", TWK_HELP(twk), 99)
+ call tweak (twk)
+ call mfree (twk, TY_STRUCT)
+end
+
+
+# TWEAK -- Tweak spectra for shift and scale before applying a correction.
+# This procedure implements both sky subtraction and telluric division.
+
+procedure tweak (twk)
+
+pointer twk #I TWK data object
+
+pointer inlist # Input list
+pointer outlist # Output list
+pointer callist # Calibration list
+bool xcorr # Cross correlate for initial shift
+bool tweakrms # Tweak to minimize RMS?
+bool ignoreaps # Ignore aperture numbers?
+int lag # Cross correlation lag
+bool interactive # Interactive?
+
+int i, j, k, n, nout, ncal, answer
+real shift, scale, fcor, ical, mean
+pointer sp, input, output, calname, temp
+pointer in, smw, sh, out, pcal, cal, x, y, data, tmp
+
+int clgeti(), imtgetim(), imtlen()
+bool clgetb(), streq()
+real clgetr(), asieval()
+double shdr_wl(), shdr_lw()
+pointer imtopenp(), immap(), smw_openim(), impl3r(), imgl3r()
+errchk immap, smw_openim, shdr_open, twk_gcal, twk_tweak, impl3r, imgl3r
+
+begin
+ call smark (sp)
+ call salloc (input, SZ_FNAME, TY_CHAR)
+ call salloc (output, SZ_FNAME, TY_CHAR)
+ call salloc (calname, SZ_FNAME, TY_CHAR)
+ call salloc (temp, SZ_LINE, TY_CHAR)
+ call malloc (TWK_WAVE(twk), 1000, TY_DOUBLE)
+ call malloc (TWK_SPEC(twk), 1000, TY_REAL)
+
+ # Get task parameters.
+ inlist = imtopenp ("input")
+ outlist = imtopenp ("output")
+ callist = imtopenp ("cal")
+ ignoreaps = clgetb ("ignoreaps")
+ if (TWK_TYPE(twk) == 'T')
+ TWK_THRESH(twk) = clgetr ("threshold")
+ TWK_SHIFT(twk) = clgetr ("shift")
+ TWK_SCALE(twk) = clgetr ("scale")
+ xcorr = clgetb ("xcorr")
+ tweakrms = clgetb ("tweakrms")
+ interactive = clgetb ("interactive")
+ if (interactive)
+ answer = YES
+ else
+ answer = ALWAYSNO
+ call clgstr ("sample", TWK_SAMPLE(twk), TWK_SLEN)
+ lag = clgeti ("lag")
+ TWK_DSHIFT(twk) = max (0., clgetr ("dshift"))
+ TWK_DSCALE(twk) = max (0., min (0.99, clgetr ("dscale")))
+ TWK_OFFSET(twk) = clgetr ("offset")
+ TWK_BOX(twk) = max (1, clgeti ("smooth"))
+
+ if (imtlen (inlist) != imtlen (callist) && imtlen (callist) != 1) {
+ call imtclose (inlist)
+ call imtclose (outlist)
+ call imtclose (callist)
+ call sfree (sp)
+ call error (1, "Image lists do not match")
+ }
+
+ # Loop over all input images.
+ sh = NULL
+ ncal = 0
+ while (imtgetim (inlist, Memc[input], SZ_FNAME) != EOF) {
+ if (imtgetim (callist, Memc[calname], SZ_FNAME) != EOF) {
+ if (ncal > 0) {
+ do i = 0, ncal-1 {
+ cal = Memi[pcal+i]
+ call asifree (IM(cal))
+ call smw_close (MW(cal))
+ call shdr_close (cal)
+ }
+ call mfree (pcal, TY_POINTER)
+ ncal = 0
+ }
+ }
+
+ in = NULL; smw = NULL; sh = NULL; out = NULL
+ iferr {
+ # Set output image. Use a temporary image when output=input.
+ if (imtlen (outlist) > 0) {
+ if (imtgetim (outlist, Memc[output], SZ_FNAME) == EOF)
+ break
+ } else
+ call strcpy (Memc[input], Memc[output], SZ_FNAME)
+
+ # Map the input image.
+ tmp = immap (Memc[input], READ_ONLY, 0); in = tmp
+ tmp = smw_openim (in); smw = tmp
+ if (smw == SMW_ND)
+ call error (1, "NDSPEC data not supported")
+ call shdr_open (in, smw, 1, 1, INDEFI, SHHDR, sh)
+
+ # Map the output image.
+ if (streq (Memc[input], Memc[output]))
+ call mktemp ("temp", Memc[temp], SZ_LINE)
+ else
+ call strcpy (Memc[output], Memc[temp], SZ_LINE)
+ tmp = immap (Memc[temp], NEW_COPY, in); out = tmp
+ if (IM_PIXTYPE(out) != TY_DOUBLE)
+ IM_PIXTYPE(out) = TY_REAL
+
+ # Determine airmass if needed.
+ if (TWK_TYPE(twk) == 'T') {
+ if (IS_INDEF(AM(sh))) {
+ call printf ("%s: ")
+ call pargstr (Memc[input])
+ call flush (STDOUT)
+ AM(sh) = clgetr ("airmass")
+ }
+ }
+
+ # Calibrate all spectra in the image.
+ # Only the first band is done.
+ do i = 1, IM_LEN(in,2) {
+
+ # Get the spectra.
+ call shdr_open (in, smw, i, 1, INDEFI, SHDATA, sh)
+ call realloc (TWK_WAVE(twk), SN(sh), TY_DOUBLE)
+ x = TWK_WAVE(twk)
+ do k = 1, SN(sh) {
+ Memd[x] = shdr_lw (sh, double(k))
+ x = x + 1
+ }
+ if (ignoreaps)
+ call twk_gcal (twk, Memc[calname], INDEFI,
+ pcal, ncal, cal)
+ else
+ call twk_gcal (twk, Memc[calname], AP(sh),
+ pcal, ncal, cal)
+
+ # Determine the shift and scale.
+ TWK_SH(twk) = sh
+ TWK_CAL(twk) = cal
+ call realloc (SY(cal), SN(sh), TY_REAL)
+ call realloc (TWK_SPEC(twk), SN(sh), TY_REAL)
+ if (answer == NO || answer == YES) {
+ call printf ("%s%s: ")
+ call pargstr (IMNAME(sh))
+ call pargstr (IMSEC(sh))
+ call flush (STDOUT)
+ call xt_clanswer ("answer", answer)
+ }
+ if (answer == YES || answer == ALWAYSYES)
+ interactive = true
+ else
+ interactive = false
+ call twk_tweak (twk, xcorr, tweakrms, interactive, lag)
+ shift = TWK_SHIFT(twk)
+ if (TWK_TYPE(twk) == 'T')
+ scale = TWK_SCALE(twk) * AM(sh) / AM(cal)
+ else
+ scale = TWK_SCALE(twk)
+
+ # Calibrate the output spectrum.
+ nout = 0
+ mean = 0.
+ x = TWK_WAVE(twk)
+ y = SY(sh)
+ n = SN(sh)
+ data = impl3r (out, i, 1)
+ do k = 1, n {
+ ical = shdr_wl (cal, Memd[x]) + shift
+ if (ical < 1. || ical > SN(cal)) {
+ if (ical < 0.5 || ical > SN(cal) + 0.5)
+ nout = nout + 1
+ ical = max (1., min (real(SN(cal)), ical))
+ }
+ if (TWK_TYPE(twk) == 'T') {
+ fcor = max (TWK_THRESH(twk),
+ asieval (IM(cal),ical)) ** scale
+ Memr[data] = Memr[y] / fcor
+ mean = mean + fcor
+ } else {
+ fcor = asieval (IM(cal),ical) * scale
+ Memr[data] = Memr[y] - fcor
+ }
+ x = x + 1
+ y = y + 1
+ data = data + 1
+ }
+ mean = mean / n
+ if (TWK_TYPE(twk) == 'T')
+ call amulkr (Memr[data-n], mean, Memr[data-n], n)
+ do k = n+1, IM_LEN(out,1) {
+ Memr[data] = 0
+ data = data + 1
+ }
+
+ # Log the results.
+ if (i == 1) {
+ call printf ("%s:\n Output: %s - %s\n")
+ call pargstr (TWK_TYPE(twk))
+ call pargstr (Memc[output])
+ call pargstr (IM_TITLE(out))
+ }
+ call printf (" Input: %s%s - %s\n")
+ call pargstr (IMNAME(sh))
+ call pargstr (IMSEC(sh))
+ call pargstr (TITLE(sh))
+ call printf (" Calibration: %s%s - %s\n")
+ call pargstr (IMNAME(cal))
+ call pargstr (IMSEC(cal))
+ call pargstr (TITLE(cal))
+ call printf (" Tweak: shift = %.2f, scale = %.3f")
+ call pargr (shift)
+ call pargr (TWK_SCALE(twk))
+ if (TWK_TYPE(twk) == 'T') {
+ call printf (", normalization = %.4g\n")
+ call pargr (mean)
+ } else
+ call printf ("\n")
+ if (nout > 0) {
+ call printf (
+ " WARNING: %d pixels outside of calibration limits\n")
+ call pargi (nout)
+ }
+ call flush (STDOUT)
+ }
+ do j = 2, IM_LEN(in,3) {
+ do i = 1, IM_LEN(in,2) {
+ y = imgl3r (in, i, j)
+ data = impl3r (out, i, j)
+ call amovr (Memr[y], Memr[data], IM_LEN(out,1))
+ }
+ }
+ } then {
+ call erract (EA_WARN)
+ if (out != NULL) {
+ call imunmap (out)
+ if (!streq (Memc[input], Memc[output]))
+ call imdelete (Memc[output])
+ }
+ }
+
+ # Finish up this image.
+ if (in != NULL)
+ call imunmap (in)
+ if (smw != NULL) {
+ call smw_close (smw)
+ if (sh != NULL)
+ MW(sh) = NULL
+ }
+ if (out != NULL) {
+ call imunmap (out)
+ if (streq (Memc[input], Memc[output])) {
+ call imdelete (Memc[input])
+ call imrename (Memc[temp], Memc[output])
+ }
+ }
+ }
+
+ # Finish up.
+ if (ncal > 0) {
+ do i = 0, ncal-1 {
+ cal = Memi[pcal+i]
+ call asifree (IM(cal))
+ call smw_close (MW(cal))
+ call shdr_close (cal)
+ }
+ call mfree (pcal, TY_POINTER)
+ }
+ if (sh != NULL)
+ call shdr_close (sh)
+ call imtclose (inlist)
+ call imtclose (outlist)
+ call imtclose (callist)
+ call mfree (TWK_SPEC(twk), TY_REAL)
+ call sfree (sp)
+end
+
+
+# TWK_GCAL -- Get calibration data
+# An interpolation function is fit and stored in the image pointer field.
+# For efficiency the calibration data is saved by aperture so that additional
+# calls simply return the data pointer.
+
+procedure twk_gcal (twk, calname, ap, pcal, ncal, cal)
+
+pointer twk # TWK data object
+char calname[ARB] # Calibration image name
+int ap # Aperture
+pointer pcal # Pointer to cal data
+int ncal # Number of active cal data structures
+pointer cal # Calibration data structure
+
+int i, clgwrd()
+pointer sp, str, im, smw, immap(), smw_openim()
+real clgetr()
+errchk immap, smw_openim, shdr_open, asifit
+
+begin
+ # Check for previously saved calibration
+ for (i=0; i<ncal; i=i+1) {
+ cal = Memi[pcal+i]
+ if (AP(cal) == ap)
+ return
+ }
+
+ call smark (sp)
+ call salloc (str, SZ_FNAME, TY_CHAR)
+
+ # Allocate space for a new data pointer and get the calibration data.
+
+ if (ncal == 0)
+ call malloc (pcal, 10, TY_POINTER)
+ else if (mod (ncal, 10) == 0)
+ call realloc (pcal, ncal+10, TY_POINTER)
+
+ im = immap (calname, READ_ONLY, 0)
+ smw = smw_openim (im)
+ cal = NULL
+ call shdr_open (im, smw, 1, 1, ap, SHDATA, cal)
+ AP(cal) = ap
+ Memi[pcal+ncal] = cal
+ ncal = ncal + 1
+ call imunmap (im)
+
+ call asiinit (im, clgwrd ("interp", Memc[str], SZ_FNAME,II_FUNCTIONS))
+ call asifit (im, Memr[SY(cal)], SN(cal))
+ IM(cal) = im
+
+ # Determine airmass if needed.
+ if (TWK_TYPE(twk) == 'T') {
+ if (IS_INDEF(AM(cal))) {
+ call printf ("%s: ")
+ call pargstr (calname)
+ call flush (STDOUT)
+ AM(cal) = clgetr ("airmass")
+ }
+ }
+
+ call sfree (sp)
+end
+
+
+# TWK_TWEAK -- Determine the shift and scale using automatic and interactive
+# methods.
+
+procedure twk_tweak (twk, xcorr, tweakrms, interactive, lag)
+
+pointer twk #I TWK data object
+bool xcorr #I Cross correlate for shift
+bool tweakrms #I Tweak by minimizing RMS?
+bool interactive #I Interactive fitting?
+int lag #I Cross correlation lag
+
+int i, n, nlag
+real ical, asieval()
+double shdr_wl()
+pointer sh, cal, rg, asi, x, y, rg_xrangesd()
+errchk twk_rmsmin, twk_fit
+
+begin
+ sh = TWK_SH(twk)
+ cal = TWK_CAL(twk)
+
+ # Set ranges.
+ rg = rg_xrangesd (TWK_SAMPLE(twk), Memd[TWK_WAVE(twk)], SN(sh))
+ call rg_order (rg)
+ call rg_merge (rg)
+ TWK_RG(twk) = rg
+
+ # Cross correlate for shift.
+ if (xcorr && lag > 0) {
+ n = SN(sh)
+ nlag = n + 2 * lag
+ call malloc (x, nlag, TY_REAL)
+ call malloc (y, nlag, TY_REAL)
+
+ do i = 0, n-1 {
+ ical = max (1D0, min (double(SN(cal)),
+ shdr_wl (cal, Memd[TWK_WAVE(twk)+i])))
+ Memr[y+i] = asieval (IM(cal), ical)
+ }
+
+ call twk_prep (Memr[y], n, Memr[x], nlag)
+ call twk_prep (Memr[SY(sh)], n, Memr[y], nlag)
+ call twk_xcorr (Memr[x], Memr[y], i, rg, lag, asi, TWK_SHIFT(twk),
+ ical, 0.5)
+ call asifree (asi)
+ call mfree (x, TY_REAL)
+ call mfree (y, TY_REAL)
+ }
+
+ # Tweak by minimizing RMS.
+ if (tweakrms)
+ call twk_rmsmin (twk)
+
+ # Do interactive step.
+ if (interactive)
+ call twk_fit (twk)
+
+ call rg_free (TWK_RG(twk))
+end
+
+
+# TWK_PREP -- Prepare spectra for correlation: fit continuum, subtract, taper
+
+procedure twk_prep (in, nin, out, nout)
+
+real in[nin] # Input spectrum
+int nin # Number of pixels in input spectrum
+real out[nout] # Output spectrum
+int nout # Number of pixels output spectrum (nin+2*lag)
+
+int i, lag
+real cveval()
+pointer sp, x, w, ic, cv
+
+begin
+ call smark (sp)
+ call salloc (x, nin, TY_REAL)
+ call salloc (w, nin, TY_REAL)
+
+ call ic_open (ic)
+ call ic_pstr (ic, "function", "chebyshev")
+ call ic_puti (ic, "order", 3)
+ call ic_putr (ic, "low", 3.)
+ call ic_putr (ic, "high", 1.)
+ call ic_puti (ic, "niterate", 5)
+ call ic_putr (ic, "grow", 1.)
+ call ic_putr (ic, "xmin", 1.)
+ call ic_putr (ic, "xmax", real(nin))
+
+ do i = 1, nin {
+ Memr[x+i-1] = i
+ Memr[w+i-1] = 1
+ }
+ call ic_fit (ic, cv, Memr[x], in, Memr[w], nin, YES, YES, YES, YES)
+
+ lag = (nout - nin) / 2
+ do i = 1-lag, 0
+ out[i+lag] = 0.
+ do i = 1, lag-1
+ out[i+lag] = (1-cos (PI*i/lag))/2 * (in[i] - cveval (cv, real(i)))
+ do i = lag, nin-lag+1
+ out[i+lag] = (in[i] - cveval (cv, real(i)))
+ do i = nin-lag+2, nin
+ out[i+lag] = (1-cos (PI*(nin+1-i)/lag))/2 *
+ (in[i] - cveval (cv, real(i)))
+ do i = nin+1, nin+lag
+ out[i+lag] = 0.
+
+ call cvfree (cv)
+ call ic_closer (ic)
+ call sfree (sp)
+end
+
+
+# TWK_XCORR -- Correlate spectra, fit profile, and measure center/width
+
+procedure twk_xcorr (spec1, spec2, npix, rg, lag, asi, center, width, level)
+
+real spec1[npix] # First spectrum
+real spec2[npix] # Second spectrum
+int npix # Number of pixels in spectra
+pointer rg # Ranges
+int lag # Maximum correlation lag
+pointer asi # Pointer to correlation profile interpolator
+real center # Center of profile
+real width # Width of profile
+real level # Level at which width is determined
+
+int i, j, k, n, ishift, nprof, rg_inrange()
+real x, p, pmin, pmax, asieval()
+pointer sp, prof
+
+begin
+ nprof = 2 * lag + 1
+
+ call smark (sp)
+ call salloc (prof, nprof, TY_REAL)
+
+ ishift = nint (center)
+ n = 0
+ do j = -lag, lag {
+ p = 0.
+ do i = 1+lag, npix-lag {
+ if (rg_inrange (rg, i-lag) == NO)
+ next
+ k = i - j - ishift
+ if (k < 1 || k > npix)
+ next
+ p = p + spec1[i] * spec2[k]
+ n = n + 1
+ }
+ Memr[prof+j+lag] = p
+ }
+ if (n < 10 * nprof) {
+ call sfree (sp)
+ return
+ }
+
+ # Fit interpolator
+ call asiinit (asi, II_SPLINE3)
+ call asifit (asi, Memr[prof], nprof)
+
+ # Find the minimum and maximum
+ center = 1.
+ pmin = asieval (asi, 1.)
+ pmax = pmin
+ for (x=1; x<=nprof; x=x+.01) {
+ p = asieval (asi, x)
+ if (p < pmin)
+ pmin = p
+ if (p > pmax) {
+ pmax = p
+ center = x
+ }
+ }
+
+ # Normalize
+ pmax = pmax - pmin
+ do i = 0, nprof-1
+ Memr[prof+i] = (Memr[prof+i] - pmin) / pmax
+
+ call asifit (asi, Memr[prof], nprof)
+
+ # Find the equal flux points
+ for (x=center; x>=1 && asieval (asi,x)>level; x=x-0.01)
+ ;
+ width = x
+ for (x=center; x<=nprof && asieval (asi,x)>level; x=x+0.01)
+ ;
+ width = (x - width - 0.01) / sqrt (2.)
+ center = center - lag - 1 + ishift
+
+ call sfree (sp)
+end
+
+
+# TWK_RMSMIN -- Tweak shift and scale to minimize the RMS.
+# This changes the shift and scale parameters but not the step.
+
+procedure twk_rmsmin (twk)
+
+pointer twk #I TWK data object
+
+int i
+real lastshift, lastscale
+errchk twk_ashift, twk_ascale
+
+begin
+ lastshift = INDEFR
+ lastscale = INDEFR
+ do i = 1, 2 {
+ if (TWK_SHIFT(twk) == lastshift && TWK_SCALE(twk) == lastscale)
+ break
+ lastshift = TWK_SHIFT(twk)
+ call twk_ashift (twk)
+
+ if (TWK_SHIFT(twk) == lastshift && TWK_SCALE(twk) == lastscale)
+ break
+ lastscale = TWK_SCALE(twk)
+ call twk_ascale (twk)
+ }
+end
+
+
+# TWK_ASCALE -- Automatically determine scale by minimizing RMS.
+
+procedure twk_ascale (twk)
+
+pointer twk #I TWK data object
+
+int i
+real shift, oscale, dscale, lastscale, scale[3], rms[3]
+errchk twk_spec
+
+begin
+ dscale = TWK_DSCALE(twk)
+ if (dscale == 0.)
+ return
+ oscale = TWK_SCALE(twk)
+ shift = TWK_SHIFT(twk)
+ do i = 1, 3 {
+ scale[i] = (1 - (i - 2) * dscale) * oscale
+ call twk_spec (twk, shift, scale[i])
+ rms[i] = TWK_RMS(twk)
+ lastscale = TWK_SCALE(twk)
+ }
+ while (dscale > 0.01) {
+ if (scale[1] / oscale < 0.5 || scale[3] / oscale > 2.) {
+ TWK_SCALE(twk) = oscale
+ break
+ }
+ if (rms[1] < rms[2]) {
+ scale[3] = scale[2]
+ scale[2] = scale[1]
+ scale[1] = (1 - dscale) * scale[2]
+ rms[3] = rms[2]
+ rms[2] = rms[1]
+ call twk_spec (twk, shift, scale[1])
+ rms[1] = TWK_RMS(twk)
+ lastscale = TWK_SCALE(twk)
+ } else if (rms[3] < rms[2]) {
+ scale[1] = scale[2]
+ scale[2] = scale[3]
+ scale[3] = (1+dscale) * scale[2]
+ rms[1] = rms[2]
+ rms[2] = rms[3]
+ call twk_spec (twk, shift, scale[3])
+ rms[3] = TWK_RMS(twk)
+ lastscale = TWK_SCALE(twk)
+ } else {
+ dscale = dscale / 2
+ scale[1] = (1-dscale) * scale[2]
+ scale[3] = (1+dscale) * scale[2]
+ call twk_spec (twk, shift, scale[1])
+ rms[1] = TWK_RMS(twk)
+ call twk_spec (twk, shift, scale[3])
+ rms[3] = TWK_RMS(twk)
+ lastscale = TWK_SCALE(twk)
+ }
+ if (rms[1] < rms[2])
+ TWK_SCALE(twk) = scale[1]
+ else if (rms[3] < rms[2])
+ TWK_SCALE(twk) = scale[3]
+ else
+ TWK_SCALE(twk) = scale[2]
+ }
+
+ if (TWK_SCALE(twk) != lastscale)
+ call twk_spec (twk, shift, TWK_SCALE(twk))
+end
+
+
+# TWK_ASHIFT -- Automatically determine shift by minimizing RMS.
+
+procedure twk_ashift (twk)
+
+pointer twk #I TWK data object
+
+int i
+real scale, oshift, dshift, lastshift, shift[3], rms[3]
+errchk twk_spec
+
+begin
+ dshift = TWK_DSHIFT(twk)
+ if (dshift == 0.)
+ return
+ oshift = TWK_SHIFT(twk)
+ scale = TWK_SCALE(twk)
+ do i = 1, 3 {
+ shift[i] = oshift + dshift * (i - 2)
+ call twk_spec (twk, shift[i], scale)
+ rms[i] = TWK_RMS(twk)
+ lastshift = TWK_SHIFT(twk)
+ }
+ while (dshift > 0.01) {
+ if (abs (oshift - shift[2]) > 2.) {
+ TWK_SHIFT(twk) = oshift
+ break
+ }
+ if (rms[1] < rms[2]) {
+ shift[3] = shift[2]
+ shift[2] = shift[1]
+ shift[1] = shift[2] - dshift
+ rms[3] = rms[2]
+ rms[2] = rms[1]
+ call twk_spec (twk, shift[1], scale)
+ rms[1] = TWK_RMS(twk)
+ lastshift = TWK_SHIFT(twk)
+ } else if (rms[3] < rms[2]) {
+ shift[1] = shift[2]
+ shift[2] = shift[3]
+ shift[3] = shift[2] + dshift
+ rms[1] = rms[2]
+ rms[2] = rms[3]
+ call twk_spec (twk, shift[3], scale)
+ rms[3] = TWK_RMS(twk)
+ lastshift = TWK_SHIFT(twk)
+ } else {
+ dshift = dshift / 2
+ shift[1] = shift[2] - dshift
+ call twk_spec (twk, shift[1], scale)
+ rms[1] = TWK_RMS(twk)
+ shift[3] = shift[2] + dshift
+ call twk_spec (twk, shift[3], scale)
+ rms[3] = TWK_RMS(twk)
+ lastshift = TWK_SHIFT(twk)
+ }
+ if (rms[1] < rms[2])
+ TWK_SHIFT(twk) = shift[1]
+ else if (rms[3] < rms[2])
+ TWK_SHIFT(twk) = shift[3]
+ else
+ TWK_SHIFT(twk) = shift[2]
+ }
+
+ if (TWK_SHIFT(twk) != lastshift)
+ call twk_spec (twk, TWK_SHIFT(twk), scale)
+end
+
+
+# TWK_SPEC -- Evaluate the calibrated spectrum with the specified shift
+# and scale. Compute the RMS within the sample regions. Apply a
+# smoothing if necessary. The output spectrum and shift and scale
+# used are returned in the TWK data structure.
+
+procedure twk_spec (twk, shift, scale)
+
+pointer twk #I TWK data object
+real shift #I Shift
+real scale #I Scale
+
+char type
+pointer sh, cal, asi, x, y, ycal, z, rg, temp
+int i, j, k, n, ncal, nstat, box, rg_inrange()
+real thresh, amratio, norm, sum1, sum2, xcal, xcal1, zval, asieval()
+double shdr_wl()
+
+begin
+ # Dereference the data structures.
+ type = TWK_TYPE(twk)
+ sh = TWK_SH(twk)
+ cal = TWK_CAL(twk)
+ asi = IM(cal)
+ x = TWK_WAVE(twk)
+ y = SY(sh)
+ ycal = SY(cal)
+ z = TWK_SPEC(twk)
+ n = SN(sh)
+ ncal = SN(cal)
+ rg = TWK_RG(twk)
+ thresh = TWK_THRESH(twk)
+ amratio = AM(sh) / AM(cal)
+
+ # Evaluate the calibrated spectrum and the statistics.
+ norm = 0.
+ sum1 = 0.
+ sum2 = 0.
+ nstat = 0
+ do i = 0, n-1 {
+ # Spectra
+ xcal = shdr_wl (cal, Memd[x+i]) + shift
+ xcal1 = max (1., min (real(ncal), xcal))
+ #Memr[ycal+i] = asieval (asi, xcal1) ** (amratio * scale)
+ #Memr[z+i] = Memr[y+i] / (Memr[ycal+i]
+ Memr[ycal+i] = asieval (asi, xcal1)
+ if (type == 'T') {
+ Memr[ycal+i] = max (thresh, Memr[ycal+i])
+ if (Memr[ycal+i] <= 0.)
+ call error (1,
+ "Calibration spectrum negative or zero (set threshold parameter)")
+ Memr[z+i] = Memr[y+i] / (Memr[ycal+i] ** (amratio * scale))
+ } else
+ Memr[z+i] = Memr[y+i] - (Memr[ycal+i] * scale)
+ norm = norm + Memr[z+i]
+ }
+
+ do i = 3, n-4 {
+ # Statistics
+ if (rg_inrange (rg, i+1) == NO)
+ next
+# if (xcal < 1 || xcal > ncal)
+# next
+# zval = Memr[z+i]
+ zval = Memr[z+i] - (Memr[z+i-3] + Memr[z+i+3]) / 2
+ sum1 = sum1 + zval
+ sum2 = sum2 + zval * zval
+ nstat = nstat + 1
+ }
+
+ # Normalize
+ if (TWK_TYPE(twk) == 'T') {
+ norm = norm / n
+ if (norm > 0.) {
+ call adivkr (Memr[z], norm, Memr[z], n)
+ sum1 = sum1 / norm
+ sum2 = sum2 / norm / norm
+ }
+ }
+
+ # RMS
+ if (nstat == 0)
+ TWK_RMS(twk) = INDEF
+ else
+ TWK_RMS(twk) = sqrt (nstat * sum2 - sum1**2) / nstat
+
+ TWK_SHIFT(twk) = shift
+ TWK_SCALE(twk) = scale
+
+ # Smooth
+ if (TWK_BOX(twk) > 1) {
+ call malloc (temp, n, TY_REAL)
+ box = TWK_BOX(twk)
+ box = min (n, box)
+ i = (1-box) / 2
+ sum1 = 0.
+ for (j=i; j<i+box; j=j+1)
+ sum1 = sum1 + Memr[z+max(0,j)]
+ for (k=0; k<n; k=k+1) {
+ Memr[temp+k] = sum1
+ sum1 = sum1 - Memr[z+max(0,i)] + Memr[z+min(n-1,j)]
+ i = i + 1
+ j = j + 1
+ }
+ call adivkr (Memr[temp], real(box), Memr[z], n)
+ call mfree (temp, TY_REAL)
+ }
+end
+
+
+# TWK_FIT -- Interactive fitting procedure.
+
+procedure twk_fit (twk)
+
+pointer twk #I TWK data object
+
+int i, j, n, newgraph, newdata, key, wcs, pix, clgcur(), gt_geti()
+int graph1, graph2
+real wx, wy, shift[3], scale[3], dy, gt_getr()
+double shdr_wl()
+pointer sp, str, cmd, z[3]
+pointer sh, gp, gt[2], gopen(), gt_init(), rg_xrangesd()
+errchk twk_spec, twk_rmsmin
+
+begin
+ sh = TWK_SH(twk)
+ n = SN(sh)
+
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+ call salloc (cmd, SZ_LINE, TY_CHAR)
+ call salloc (z[1], n, TY_REAL)
+ call salloc (z[3], n, TY_REAL)
+ z[2] = TWK_SPEC(twk)
+
+ # Initialize the graphics.
+ gp = gopen ("stdgraph", NEW_FILE+AW_DEFER, STDGRAPH)
+ gt[1] = gt_init ()
+ call sprintf (Memc[str], SZ_LINE,
+ "%s: spectrum = %s%s, calibration = %s%s")
+ call pargstr (TWK_TYPE(twk))
+ call pargstr (IMNAME(sh))
+ call pargstr (IMSEC(sh))
+ call pargstr (IMNAME(TWK_CAL(twk)))
+ call pargstr (IMSEC(TWK_CAL(twk)))
+ call gt_sets (gt[1], GTTITLE, Memc[str])
+ if (UN_LABEL(UN(sh)) != EOS) {
+ call gt_sets (gt[1], GTXLABEL, UN_LABEL(UN(sh)))
+ call gt_sets (gt[1], GTXUNITS, UN_UNITS(UN(sh)))
+ } else
+ call gt_sets (gt[1], GTXLABEL, "Pixels")
+ call gt_sets (gt[1], GTTYPE, "line")
+
+ gt[2] = gt_init ()
+ if (UN_LABEL(UN(sh)) != EOS) {
+ call gt_sets (gt[2], GTXLABEL, UN_LABEL(UN(sh)))
+ call gt_sets (gt[2], GTXUNITS, UN_UNITS(UN(sh)))
+ } else
+ call gt_sets (gt[2], GTXLABEL, "Pixels")
+ call gt_sets (gt[2], GTTYPE, "line")
+
+ # Cursor loop.
+ if (TWK_DSCALE(twk) > 0.)
+ graph1 = 'y'
+ else
+ graph1 = 'x'
+ graph2 = GCAL
+ newdata = YES
+ key = 'r'
+ repeat {
+ switch (key) {
+ case ':':
+ call twk_colon (Memc[cmd], twk, gp, gt, wcs, newdata, newgraph)
+ case '?':
+ call twk_colon ("help", twk, gp, gt, wcs, newdata, newgraph)
+ case 'a':
+ call twk_rmsmin (twk)
+ newdata = YES
+ case 'c':
+ if (graph2 == GCAL)
+ graph2 = GNONE
+ else
+ graph2 = GCAL
+ call gt_setr (gt[2], GTYMIN, INDEF)
+ call gt_setr (gt[2], GTYMAX, INDEF)
+ newgraph = YES
+ case 'd':
+ if (graph2 == GDATA)
+ graph2 = GNONE
+ else
+ graph2 = GDATA
+ call gt_setr (gt[2], GTYMIN, INDEF)
+ call gt_setr (gt[2], GTYMAX, INDEF)
+ newgraph = YES
+ case 'e':
+ switch (graph1) {
+ case 'x':
+ if (TWK_DSHIFT(twk) == 0.)
+ TWK_DSHIFT(twk) = 0.1
+ else
+ TWK_DSHIFT(twk) = 2 * TWK_DSHIFT(twk)
+ case 'y':
+ if (TWK_DSCALE(twk) == 0.)
+ TWK_DSCALE(twk) = 0.1
+ else
+ TWK_DSCALE(twk) = min (0.99, 2 * TWK_DSCALE(twk))
+ }
+ newdata = YES
+ case 'q':
+ break
+ case 'r':
+ newgraph = YES
+ case 's':
+ dy = wx
+ call printf ("s to add sample region or n for new regions:\n")
+ if (clgcur ("cursor",wx,wy,wcs,key,Memc[cmd],SZ_LINE) == EOF)
+ break
+ switch (key) {
+ case 'n':
+ call rg_free (TWK_RG(twk))
+ call sprintf (TWK_SAMPLE(twk), TWK_SLEN, "%g:%g")
+ call pargr (dy)
+ call pargr (wx)
+ TWK_RG(twk) = rg_xrangesd (TWK_SAMPLE(twk),
+ Memd[TWK_WAVE(twk)], SN(sh))
+ newdata = YES
+ case 's':
+ call rg_free (TWK_RG(twk))
+ if (TWK_SAMPLE(twk) == '*') {
+ call sprintf (TWK_SAMPLE(twk), TWK_SLEN, "%g:%g")
+ call pargr (dy)
+ call pargr (wx)
+ } else {
+ call sprintf (Memc[cmd], SZ_LINE, ",%g:%g")
+ call pargr (dy)
+ call pargr (wx)
+ call strcat (Memc[cmd], TWK_SAMPLE(twk), TWK_SLEN)
+ }
+ TWK_RG(twk) = rg_xrangesd (TWK_SAMPLE(twk),
+ Memd[TWK_WAVE(twk)], SN(sh))
+ newdata = YES
+ }
+ case 'w':
+ call gt_window (gt[wcs], gp, "cursor", newgraph)
+ if (wcs == 1) {
+ call gt_setr (gt[2], GTXMIN, gt_getr (gt[1], GTXMIN))
+ call gt_setr (gt[2], GTXMAX, gt_getr (gt[1], GTXMAX))
+ call gt_seti (gt[2], GTXFLIP, gt_geti (gt[1], GTXFLIP))
+ } else {
+ call gt_setr (gt[1], GTXMIN, gt_getr (gt[2], GTXMIN))
+ call gt_setr (gt[1], GTXMAX, gt_getr (gt[2], GTXMAX))
+ call gt_seti (gt[1], GTXFLIP, gt_geti (gt[2], GTXFLIP))
+ }
+ case 'x', 'y':
+ pix = max (1, min (n, nint (shdr_wl (sh, double (wx))))) - 1
+ j = 1
+ dy = abs (wy - Memr[z[j]+pix])
+ do i = 2, 3
+ if (abs (wy - Memr[z[i]+pix]) < dy) {
+ j = i
+ dy = abs (wy - Memr[z[j]+pix])
+ }
+ TWK_SHIFT(twk) = shift[j]
+ TWK_SCALE(twk) = scale[j]
+ if (j == 2 && graph1 == key) {
+ if (key == 'x')
+ TWK_DSHIFT(twk) = TWK_DSHIFT(twk) / 2.
+ else if (key == 'y')
+ TWK_DSCALE(twk) = TWK_DSCALE(twk) / 2.
+ }
+ if (TWK_DSHIFT(twk) == 0.)
+ graph1 = 'y'
+ else if (TWK_DSHIFT(twk) == 0.)
+ graph1 = 'x'
+ else
+ graph1 = key
+ newdata = YES
+ default:
+ call printf ("\007\n")
+ }
+
+ if (newdata == YES) {
+ if (graph1 == 'x') {
+ shift[1] = TWK_SHIFT(twk) - TWK_DSHIFT(twk)
+ shift[2] = TWK_SHIFT(twk)
+ shift[3] = TWK_SHIFT(twk) + TWK_DSHIFT(twk)
+ scale[1] = TWK_SCALE(twk)
+ scale[2] = TWK_SCALE(twk)
+ scale[3] = TWK_SCALE(twk)
+ } else if (graph1 == 'y') {
+ shift[1] = TWK_SHIFT(twk)
+ shift[2] = TWK_SHIFT(twk)
+ shift[3] = TWK_SHIFT(twk)
+ scale[1] = TWK_SCALE(twk) * (1 - TWK_DSCALE(twk))
+ scale[2] = TWK_SCALE(twk)
+ scale[3] = TWK_SCALE(twk) * (1 + TWK_DSCALE(twk))
+ }
+ iferr {
+ TWK_SPEC(twk) = z[1]
+ call twk_spec (twk, shift[1], scale[1])
+ call asubkr (Memr[z[1]], TWK_OFFSET(twk), Memr[z[1]], n)
+ TWK_SPEC(twk) = z[3]
+ call twk_spec (twk, shift[3], scale[3])
+ call aaddkr (Memr[z[3]], TWK_OFFSET(twk), Memr[z[3]], n)
+ TWK_SPEC(twk) = z[2]
+ call twk_spec (twk, shift[2], scale[2])
+ newdata = NO
+ } then {
+ TWK_SPEC(twk) = z[2]
+ call gt_free (gt[1])
+ call gt_free (gt[2])
+ call gclose (gp)
+ call sfree (sp)
+ call erract (EA_ERROR)
+ }
+
+ call sprintf (Memc[str], SZ_LINE, "scale = %5g")
+ call pargr (TWK_SCALE(twk))
+ if (graph1 == 'y') {
+ call sprintf (Memc[cmd], SZ_LINE, " +/- %6g")
+ call pargr (TWK_DSCALE(twk))
+ call strcat (Memc[cmd], Memc[str], SZ_LINE)
+ }
+ call sprintf (Memc[cmd], SZ_LINE, ", shift = %.2f")
+ call pargr (TWK_SHIFT(twk))
+ call strcat (Memc[cmd], Memc[str], SZ_LINE)
+ if (graph1 == 'x') {
+ call sprintf (Memc[cmd], SZ_LINE, " +/- %.2f")
+ call pargr (TWK_DSHIFT(twk))
+ call strcat (Memc[cmd], Memc[str], SZ_LINE)
+ }
+ call sprintf (Memc[cmd], SZ_LINE, ", offset = %3g")
+ call pargr (TWK_OFFSET(twk))
+ call strcat (Memc[cmd], Memc[str], SZ_LINE)
+ call sprintf (Memc[cmd], SZ_LINE, ", rms = %.3g")
+ call pargr (TWK_RMS(twk))
+ call strcat (Memc[cmd], Memc[str], SZ_LINE)
+ call gt_sets (gt[1], GTCOMMENTS, Memc[str])
+
+ newgraph = YES
+ }
+
+ if (newgraph == YES) {
+ call twk_graph (twk, gp, gt, graph1, graph2, Memr[SX(sh)],
+ Memr[z[1]], Memr[z[2]], Memr[z[3]], SN(sh))
+ newgraph = NO
+ }
+ } until (clgcur ("cursor", wx, wy, wcs, key, Memc[cmd], SZ_LINE) == EOF)
+
+ call gt_free (gt[1])
+ call gt_free (gt[2])
+ call gclose (gp)
+ call sfree (sp)
+end
+
+
+# TWK_GRAPH -- Make the interactive graph.
+
+procedure twk_graph (twk, gp, gt, graph1, graph2, x, y1, y2, y3, npts)
+
+pointer twk #I TWK data object
+pointer gp #I GIO pointer
+pointer gt[2] #I GTOOLS pointer
+int graph1 #I Type for graph 1
+int graph2 #I Type for graph 2
+real x[npts] #I X values
+real y1[npts] #I Y values
+real y2[npts] #I Y values
+real y3[npts] #I Y values
+int npts #I Number of values
+
+real xmin, xmax, ymin, ymax, xmin1, xmax1, ymin1, ymax1
+
+begin
+ call gclear (gp)
+ call gseti (gp, G_WCS, 1)
+ if (graph2 != GNONE) {
+ call gsview (gp, 0.1, 0.9, 0.4, 0.9)
+ call gseti (gp, G_XLABELTICKS, NO)
+ call gt_seti (gt[1], GTDRAWXLABELS, NO)
+ }
+ call gt_ascale (gp, gt[1], x, y1, npts)
+ call ggwind (gp, xmin, xmax, ymin, ymax)
+ call gt_ascale (gp, gt[1], x, y2, npts)
+ call ggwind (gp, xmin1, xmax1, ymin1, ymax1)
+ xmin = min (xmin, xmin1)
+ xmax = max (xmax, xmax1)
+ ymin = min (ymin, ymin1)
+ ymax = max (ymax, ymax1)
+ call gt_ascale (gp, gt[1], x, y3, npts)
+ call ggwind (gp, xmin1, xmax1, ymin1, ymax1)
+ xmin = min (xmin, xmin1)
+ xmax = max (xmax, xmax1)
+ ymin = min (ymin, ymin1)
+ ymax = max (ymax, ymax1)
+ call gswind (gp, xmin, xmax, ymin, ymax)
+ call gt_swind (gp, gt[1])
+ call gt_labax (gp, gt[1])
+
+ call gt_plot (gp, gt[1], x, y1, npts)
+ call gt_plot (gp, gt[1], x, y2, npts)
+ call gt_plot (gp, gt[1], x, y3, npts)
+ call rg_gxmarkr (gp, TWK_SAMPLE(twk), x, npts, 1)
+
+ switch (graph2) {
+ case GCAL:
+ call gseti (gp, G_WCS, 2)
+ call gseti (gp, G_YNMAJOR, 3)
+ call gseti (gp, G_XLABELTICKS, YES)
+ call gt_seti (gt[2], GTDRAWXLABELS, YES)
+ call gt_seti (gt[2], GTDRAWTITLE, NO)
+ call gt_ascale (gp, gt[2], x, Memr[SY(TWK_CAL(twk))], npts)
+ call gsview (gp, 0.1, 0.9, 0.1, 0.4)
+ call gswind (gp, xmin, xmax, INDEF, INDEF)
+ call gt_swind (gp, gt[2])
+ call gt_labax (gp, gt[2])
+ call gt_plot (gp, gt[2], x, Memr[SY(TWK_CAL(twk))], npts)
+ case GDATA:
+ call gseti (gp, G_WCS, 2)
+ call gseti (gp, G_YNMAJOR, 3)
+ call gseti (gp, G_XLABELTICKS, YES)
+ call gt_seti (gt[2], GTDRAWXLABELS, YES)
+ call gt_seti (gt[2], GTDRAWTITLE, NO)
+ call gt_ascale (gp, gt[2], x, Memr[SY(TWK_SH(twk))], npts)
+ call gsview (gp, 0.1, 0.9, 0.1, 0.4)
+ call gswind (gp, xmin, xmax, INDEF, INDEF)
+ call gt_swind (gp, gt[2])
+ call gt_labax (gp, gt[2])
+ call gt_plot (gp, gt[2], x, Memr[SY(TWK_SH(twk))], npts)
+ }
+end
+
+
+# List of colon commands.
+define CMDS "|help|shift|scale|dshift|dscale|offset|smooth|sample|"
+define HELP 1 # Print help
+define SHIFT 2 # Shift
+define SCALE 3 # Scale factor
+define DSHIFT 4 # Shift intervale
+define DSCALE 5 # Scale factor interval
+define OFFSET 6 # Offset
+define SMOOTH 7 # Boxcar smoothing
+define SAMPLE 8 # Sample
+
+# TWK_COLON -- Act on colon commands.
+
+procedure twk_colon (command, twk, gp, gt, wcs, newdata, newgraph)
+
+char command[ARB] #I Colon command
+pointer twk #I TWK data object
+pointer gp #I GIO
+pointer gt[2] #I GTOOLS
+int wcs #I WCS
+int newdata #O New data flag
+int newgraph #O New graph flag
+
+int ncmd, ival, gt_geti(), strdic(), nscan()
+real rval, gt_getr()
+pointer sp, cmd, rg, rg_xrangesd()
+
+begin
+ # Check for GTOOLS command.
+ if (command[1] == '/') {
+ call gt_colon (command, gp, gt[wcs], newgraph)
+ if (wcs == 1) {
+ call gt_setr (gt[2], GTXMIN, gt_getr (gt[1], GTXMIN))
+ call gt_setr (gt[2], GTXMAX, gt_getr (gt[1], GTXMAX))
+ call gt_seti (gt[2], GTXFLIP, gt_geti (gt[1], GTXFLIP))
+ } else {
+ call gt_setr (gt[1], GTXMIN, gt_getr (gt[2], GTXMIN))
+ call gt_setr (gt[1], GTXMAX, gt_getr (gt[2], GTXMAX))
+ call gt_seti (gt[1], GTXFLIP, gt_geti (gt[2], GTXFLIP))
+ }
+ return
+ }
+
+ call smark (sp)
+ call salloc (cmd, SZ_LINE, TY_CHAR)
+
+ # Scan the command string.
+ call sscan (command)
+ call gargwrd (Memc[cmd], SZ_LINE)
+ ncmd = strdic (Memc[cmd], Memc[cmd], SZ_LINE, CMDS)
+
+ # Execute command.
+ switch (ncmd) {
+ case HELP:
+ call gpagefile (gp, TWK_HELP(twk), TWK_TYPE(twk))
+ case SHIFT:
+ call gargr (rval)
+ if (nscan() == 1) {
+ call printf ("shift %g\n")
+ call pargr (TWK_SHIFT(twk))
+ } else {
+ TWK_SHIFT(twk) = rval
+ newdata = YES
+ }
+ case SCALE:
+ call gargr (rval)
+ if (nscan() == 1) {
+ call printf ("scale %g\n")
+ call pargr (TWK_SCALE(twk))
+ } else {
+ TWK_SCALE(twk) = rval
+ newdata = YES
+ }
+ case DSHIFT:
+ call gargr (rval)
+ if (nscan() == 1) {
+ call printf ("dshift %g\n")
+ call pargr (TWK_DSHIFT(twk))
+ } else {
+ TWK_DSHIFT(twk) = rval
+ newdata = YES
+ }
+ case DSCALE:
+ call gargr (rval)
+ if (nscan() == 1) {
+ call printf ("dscale %g\n")
+ call pargr (TWK_DSCALE(twk))
+ } else {
+ if (rval < 0. || rval >= 1.)
+ call printf ("dscale must be between zero and one\007\n")
+ else {
+ TWK_DSCALE(twk) = rval
+ newdata = YES
+ }
+ }
+ case OFFSET:
+ call gargr (rval)
+ if (nscan() == 1) {
+ call printf ("offset %g\n")
+ call pargr (TWK_OFFSET(twk))
+ } else if (rval != TWK_OFFSET(twk)) {
+ TWK_OFFSET(twk) = rval
+ call gt_setr (gt[1], GTYMIN, INDEF)
+ call gt_setr (gt[1], GTYMAX, INDEF)
+ newdata = YES
+ }
+ case SMOOTH:
+ call gargi (ival)
+ if (nscan() == 1) {
+ call printf ("smooth %d\n")
+ call pargi (TWK_BOX(twk))
+ } else {
+ ival = max (1, ival)
+ if (ival != TWK_BOX(twk)) {
+ TWK_BOX(twk) = max (1, ival)
+ newdata = YES
+ }
+ }
+ case SAMPLE:
+ call gargstr (Memc[cmd], SZ_LINE)
+ if (Memc[cmd] == EOS) {
+ call printf ("sample %s\n")
+ call pargstr (TWK_SAMPLE(twk))
+ } else {
+ ifnoerr (rg = rg_xrangesd (Memc[cmd+1], Memd[TWK_WAVE(twk)],
+ SN(TWK_SH(twk)))) {
+ call rg_free (TWK_RG(twk))
+ call strcpy (Memc[cmd+1], TWK_SAMPLE(twk), TWK_SLEN)
+ TWK_RG(twk) = rg
+ newdata = YES
+ } else
+ call erract (EA_WARN)
+ }
+ default:
+ call printf ("\007\n")
+ }
+
+ call sfree (sp)
+end