aboutsummaryrefslogtreecommitdiff
path: root/noao/onedspec/t_sfit.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_sfit.x
downloadiraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz
Initial commit
Diffstat (limited to 'noao/onedspec/t_sfit.x')
-rw-r--r--noao/onedspec/t_sfit.x986
1 files changed, 986 insertions, 0 deletions
diff --git a/noao/onedspec/t_sfit.x b/noao/onedspec/t_sfit.x
new file mode 100644
index 00000000..54e896bb
--- /dev/null
+++ b/noao/onedspec/t_sfit.x
@@ -0,0 +1,986 @@
+include <imhdr.h>
+include <pkg/gtools.h>
+include <pkg/rg.h>
+include <math/curfit.h>
+include <error.h>
+include <smw.h>
+
+# SFIT -- Fit a function to spectra and output the fit, difference or
+# ratio; or print the power series coefficients of the fit. The fitting
+# parameters may be set interactively using the icfit package.
+
+# Image header keywords for saving the previous fit
+
+define SFT_KW "SFIT"
+define SFT_KWB "SFITB"
+
+# Choices for the type of output
+
+define OUT_TYPES "|data|fit|difference|ratio|"
+
+define DATA 1
+define FIT 2
+define DIFFERENCE 3
+define RATIO 4
+
+# Choices for the interactive prompts
+# (the 1st define is for clgwrd (strdic), the 2nd for CL enumeration)
+# Note that the CL assumes that the separator is `|'.
+
+define SFT_ANS1 "|yes|no|skip|YES|NO|SKIP|"
+define SFT_ANS1X "yes|no|skip|YES|NO|SKIP"
+
+define SFT_ANS2 "|spectrum|image|all|cancel|"
+define SFT_ANS2X "spectrum|image|all|cancel"
+
+define LEN_ANS 7
+
+define YES_ONCE 1
+define NO_ONCE 2
+define SKIP_ONCE 3
+define YES_ALWAYS 4
+define NO_ALWAYS 5
+define SKIP_ALWAYS 6
+
+define SKIP_SPEC 1
+define SKIP_IMAGE 2
+define SKIP_ALL 3
+define SKIP_CANCEL 4
+
+# Switches and pointers
+
+define SFT_OFF 22
+
+define INTERACTIVE Memi[$1] # all spectra are noninteractive
+define REPLACE Memi[$1+1] # replace rejected points?
+define WAVESCALE Memi[$1+2] # X is wavelength if possible
+define LOGSCALE Memi[$1+3] # axes are logarithmic
+define OVERRIDE Memi[$1+4] # allow lines to be redone
+define LISTONLY Memi[$1+5] # don't modify images
+define OUTTYPE Memi[$1+6] # output type code
+
+define GRAPH_OPEN Memi[$1+7] # keep track of gopen
+define LOG_TO_STDOUT Memi[$1+8] # STDOUT/ERR is used
+define PROMPT Memi[$1+9] # prompt flag
+define QUIET Memi[$1+10] # quiet flag
+
+define RGIN Memi[$1+11] # lines specified
+define RGFIT Memi[$1+12] # all lines to fit
+define RGREFIT Memi[$1+13] # those to fit again
+define RGINB Memi[$1+14] # bands specified
+define RGFITB Memi[$1+15] # all bands to fit
+define RGREFITB Memi[$1+16] # those to fit again
+
+define NLOGFD Memi[$1+17] # number of logfiles
+define LOGFD Memi[$1+18] # array of logfiles
+
+define IC Memi[$1+19] # current ic descriptor
+define YMAX Memi[$1+20] # max number of lines
+define BMAX Memi[$1+21] # max number of lines
+define IC_DESC Memi[$1+SFT_OFF+($3-1)*YMAX($1)+$2-1] # ic descriptors
+
+
+# T_SFIT -- Entry point for the task. Read parameters,
+# initialize structures and loop over the image templates.
+
+procedure t_sfit ()
+
+pointer listin, listout, input, output, graphics
+pointer sf, gp, gt, in, out, mw, sh, sp
+int stat
+
+int sft_icfit(), imtgetim(), gt_init(), imtlen()
+bool clgetb()
+pointer imtopenp()
+
+begin
+ call smark (sp)
+ call salloc (input, SZ_FNAME, TY_CHAR)
+ call salloc (output, SZ_FNAME, TY_CHAR)
+ call salloc (graphics, SZ_FNAME, TY_CHAR)
+
+ # Open the image templates
+ listin = imtopenp ("input")
+
+ if (clgetb ("listonly"))
+ listout = NULL
+ else {
+ listout = imtopenp ("output")
+ if (imtlen (listin) != imtlen (listout)) {
+ call imtclose (listin)
+ call imtclose (listout)
+ call sfree (sp)
+ call error (1, "Input and output image lists do not match")
+ }
+ }
+
+ # Initialize the various descriptors
+ iferr (call sft_init (listin, listout, sf)) {
+ call imtclose (listin)
+ if (listout != NULL)
+ call imtclose (listout)
+ call sfree (sp)
+ call erract (EA_ERROR)
+ }
+
+ # The graphics pointers are passed explicitly
+ if (INTERACTIVE(sf) == YES) {
+ call clgstr ("graphics", Memc[graphics], SZ_FNAME)
+ gt = gt_init()
+ call gt_sets (gt, GTTYPE, "line")
+ }
+
+ # Fit the lines in each input image.
+
+ while (imtgetim (listin, Memc[input], SZ_FNAME) != EOF) {
+
+ if (listout != NULL)
+ stat = imtgetim (listout, Memc[output], SZ_FNAME)
+ else
+ call strcpy (Memc[input], Memc[output], SZ_FNAME)
+
+ iferr {
+ call sft_immap (Memc[input], Memc[output],
+ in, out, mw, sh, sf, gp)
+ } then {
+ call erract (EA_WARN)
+ next
+ }
+
+ stat = sft_icfit (in, out, mw, sh, sf, gp, gt, Memc[graphics])
+
+ call sft_unmap (in, out, mw, sh, sf)
+
+ if (stat == EOF)
+ break
+ }
+
+ if (INTERACTIVE(sf) == YES)
+ call gt_free (gt)
+ if (GRAPH_OPEN(sf) == YES)
+ call gclose (gp)
+
+ call sft_close (sf)
+ call imtclose (listin)
+ if (listout != NULL)
+ call imtclose (listout)
+ call sfree (sp)
+end
+
+
+# SFT_INIT -- Initialize templates, ranges, logfiles, type, icfit descriptors.
+
+procedure sft_init (listin, listout, sf)
+
+pointer listin, listout #I Image template descriptors
+pointer sf #I Pointer to task switches
+
+pointer input, output, im, sp, mw
+int ymax, bmax, i, j
+
+real clgetr()
+bool clgetb()
+int clgwrd(), clgeti(), btoi(), strlen()
+int rg_next(), imtgetim(), imaccess(), xt_logopen()
+pointer rg_ranges(), immap(), smw_openim()
+errchk immap, smw_openim
+
+begin
+ call smark (sp)
+ call salloc (input, SZ_LINE, TY_CHAR)
+ call salloc (output, SZ_FNAME, TY_CHAR)
+
+ sf = NULL
+ iferr {
+
+ # find the maximum number of lines and bands (spectra)
+ ymax = 0
+ bmax = 0
+
+ while (imtgetim (listin, Memc[input], SZ_LINE) != EOF)
+ if (imaccess (Memc[input], READ_ONLY) == YES) {
+ im = immap (Memc[input], READ_ONLY, 0)
+ mw = smw_openim (im)
+ ymax = max (SMW_LLEN(mw,2), ymax)
+ bmax = max (SMW_LLEN(mw,3), bmax)
+ call smw_close (mw)
+ call imunmap (im)
+ }
+ call imtrew (listin)
+
+ if (listout != NULL) {
+ while (imtgetim (listout, Memc[output], SZ_FNAME) != EOF)
+ if (imaccess (Memc[output], READ_ONLY) == YES) {
+ im = immap (Memc[output], READ_ONLY, 0)
+ mw = smw_openim (im)
+ ymax = max (SMW_LLEN(mw,2), ymax)
+ bmax = max (SMW_LLEN(mw,3), bmax)
+ call smw_close (mw)
+ call imunmap (im)
+ }
+ call imtrew (listout)
+ }
+
+ # allocate space for the task switch structure
+ call malloc (sf, SFT_OFF + ymax * bmax, TY_STRUCT)
+
+ YMAX(sf) = ymax
+ BMAX(sf) = bmax
+
+ # NULL the pointers for error handling
+ RGIN(sf) = NULL
+ RGINB(sf) = NULL
+ NLOGFD(sf) = 0
+ do j = 1, BMAX(sf)
+ do i = 1, YMAX(sf)
+ IC_DESC(sf,i,j) = NULL
+
+ # Set the switches
+ INTERACTIVE(sf) = btoi (clgetb ("interactive"))
+ REPLACE(sf) = btoi (clgetb ("replace"))
+ WAVESCALE(sf) = btoi (clgetb ("wavescale"))
+ LOGSCALE(sf) = btoi (clgetb ("logscale"))
+ OVERRIDE(sf) = btoi (clgetb ("override"))
+ LISTONLY(sf) = btoi (clgetb ("listonly"))
+ GRAPH_OPEN(sf) = NO
+ PROMPT(sf) = INTERACTIVE(sf)
+ QUIET(sf) = btoi (INTERACTIVE(sf) == NO)
+
+ # Expand the range specification, allow either hyphens or colons
+
+ call clgstr ("lines", Memc[input], SZ_LINE)
+ do i = 1, strlen (Memc[input])
+ if (Memc[input+i-1] == '-')
+ Memc[input+i-1] = ':'
+ else if (Memc[input+i-1] == 'x' || Memc[input+i-1] == 'X')
+ call error (1, "Range step (`x' notation) not implemented")
+
+ RGIN(sf) = rg_ranges (Memc[input], 1, YMAX(sf))
+ call rg_order (RGIN(sf))
+ call rg_merge (RGIN(sf))
+
+ call clgstr ("bands", Memc[input], SZ_LINE)
+ do i = 1, strlen (Memc[input])
+ if (Memc[input+i-1] == '-')
+ Memc[input+i-1] = ':'
+ else if (Memc[input+i-1] == 'x' || Memc[input+i-1] == 'X')
+ call error (1, "Range step (`x' notation) not implemented")
+
+ RGINB(sf) = rg_ranges (Memc[input], 1, BMAX(sf))
+ call rg_order (RGINB(sf))
+ call rg_merge (RGINB(sf))
+
+ i = 0
+ j = 0
+ if (rg_next (RGIN(sf), i) == EOF || rg_next (RGINB(sf), j) == EOF)
+ call error (1, "With range specification for `lines or bands'")
+ else {
+ # Open the initial icfit descriptor
+ call ic_open (IC(sf))
+
+ call clgstr ("sample", Memc[input], SZ_LINE)
+ call ic_pstr (IC(sf), "sample", Memc[input])
+ call clgstr ("function", Memc[input], SZ_LINE)
+ call ic_pstr (IC(sf), "function", Memc[input])
+
+ call ic_puti (IC(sf), "naverage", clgeti ("naverage"))
+ call ic_puti (IC(sf), "order", clgeti ("order"))
+ call ic_putr (IC(sf), "low", clgetr ("low_reject"))
+ call ic_putr (IC(sf), "high", clgetr ("high_reject"))
+ call ic_puti (IC(sf), "niterate", clgeti ("niterate"))
+ call ic_putr (IC(sf), "grow", clgetr ("grow"))
+ call ic_puti (IC(sf), "markrej", btoi (clgetb ("markrej")))
+
+ IC_DESC(sf,i,j) = IC(sf)
+ }
+
+ # Get the desired output type
+ OUTTYPE(sf) = clgwrd ("type", Memc[input], SZ_LINE, OUT_TYPES)
+
+ # Open the logfiles
+ NLOGFD(sf) = xt_logopen ("logfiles", "SFIT:", LOGFD(sf),
+ LOG_TO_STDOUT(sf))
+
+ } then {
+ call sfree (sp)
+ call sft_close (sf)
+ call erract (EA_ERROR)
+ }
+
+ call sfree (sp)
+ return
+end
+
+
+# SFT_CLOSE -- Close the various descriptors.
+
+procedure sft_close (sf)
+
+pointer sf #I Pointer to task switches
+
+int i, j
+
+begin
+ if (sf != NULL) {
+ if (RGIN(sf) != NULL)
+ call rg_free (RGIN(sf))
+ if (RGINB(sf) != NULL)
+ call rg_free (RGINB(sf))
+ if (NLOGFD(sf) != 0)
+ call xt_logclose (LOGFD(sf), NLOGFD(sf), "END:")
+ do j = 1, BMAX(sf)
+ do i = 1, YMAX(sf)
+ if (IC_DESC(sf,i,j) != NULL)
+ call ic_closer (IC_DESC(sf,i,j))
+ call mfree (sf, TY_STRUCT)
+ }
+end
+
+
+# SFT_IMMAP -- Map images for sfit.
+
+procedure sft_immap (input, output, in, out, mw, sh, sf, gp)
+
+char input[ARB] #I Input image name
+char output[ARB] #I Output image name
+pointer in, out #O IMIO pointers
+pointer mw #O MWCS pointer
+pointer sh #O SHDR pointer
+pointer sf #I Pointer for task switches
+pointer gp #I GIO pointer
+
+int i, ax1, ax2, ax3
+pointer inroot, insect, outroot, outsect, b1, b2
+pointer sp, inranges, outranges
+pointer rgin, rgout, rgtmp, rgtmpb
+long v1[IM_MAXDIM], v2[IM_MAXDIM]
+char emsg[SZ_LINE]
+
+int imaccess(), imaccf(), imgnlr(), impnlr(), strcmp()
+pointer immap(), smw_openim()
+pointer rg_ranges(), rg_window(), rg_union(), rg_intersect()
+errchk immap, smw_openim
+
+define err_ 13
+
+begin
+ call smark (sp)
+ call salloc (inroot, SZ_FNAME, TY_CHAR)
+ call salloc (insect, SZ_FNAME, TY_CHAR)
+ call salloc (outroot, SZ_FNAME, TY_CHAR)
+ call salloc (outsect, SZ_FNAME, TY_CHAR)
+ call salloc (inranges, SZ_LINE, TY_CHAR)
+ call salloc (outranges, SZ_LINE, TY_CHAR)
+
+ in = NULL
+ out = NULL
+ mw = NULL
+ sh = NULL
+ RGFIT(sf) = NULL
+ RGREFIT(sf) = NULL
+ RGFITB(sf) = NULL
+ RGREFITB(sf) = NULL
+
+ call imgimage (input, Memc[inroot], SZ_FNAME)
+ call imgsection (input, Memc[insect], SZ_FNAME)
+
+ call imgimage (output, Memc[outroot], SZ_FNAME)
+ call imgsection (output, Memc[outsect], SZ_FNAME)
+
+ if (Memc[insect] != EOS || Memc[outsect] != EOS) {
+
+ call sprintf (emsg, SZ_LINE, "Sections not allowed (%s --> %s)")
+ call pargstr (input)
+ call pargstr (output)
+ goto err_
+
+ } else if (imaccess (Memc[inroot], READ_ONLY) == NO) {
+
+ call sprintf (emsg, SZ_LINE, "Cannot access %s")
+ call pargstr (input)
+ goto err_
+
+ } else if (LISTONLY(sf) == YES) {
+
+ # The `out = in' allows the ranges code at the end of this
+ # procedure to cover all cases (with a little inefficiency).
+ # No check on the sizes of the input and output images.
+
+ in = immap (Memc[inroot], READ_ONLY, 0)
+ out = in
+
+ } else if (strcmp (Memc[inroot], Memc[outroot]) == 0) {
+
+ # Overwrite the input image.
+ in = immap (Memc[inroot], READ_WRITE, 0)
+ out = in
+
+ } else if (imaccess (Memc[outroot], READ_WRITE) == NO) {
+
+ in = immap (Memc[inroot], READ_ONLY, 0)
+ out = immap (Memc[outroot], NEW_COPY, in)
+ if (IM_PIXTYPE(out) != TY_DOUBLE)
+ IM_PIXTYPE(out) = TY_REAL
+
+ # Do this since imcopy is unimplemented
+
+ call amovkl (long(1), v1, IM_MAXDIM)
+ call amovkl (long(1), v2, IM_MAXDIM)
+
+ while (imgnlr (in, b1, v1) != EOF && impnlr (out, b2, v2) != EOF)
+ call amovr (Memr[b1], Memr[b2], IM_LEN(in, 1))
+
+ } else {
+
+ in = immap (Memc[inroot], READ_ONLY, 0)
+ out = immap (Memc[outroot], READ_WRITE, 0)
+
+ # This relies on the axes beyond IM_NDIM(im) being unity
+
+ do i = 1, max (IM_NDIM(in), IM_NDIM(out))
+ if (IM_LEN(in, i) != IM_LEN(out, i)) {
+ call sprintf (emsg, SZ_LINE, "%s & %s aren't the same size")
+ call pargstr (Memc[inroot])
+ call pargstr (Memc[outroot])
+ goto err_
+ }
+
+ }
+
+ do i = 4, IM_NDIM(in)
+ if (IM_LEN(in, i) != 1) {
+ call sprintf (emsg, SZ_LINE, "Too many dimensions for %s")
+ call pargstr (Memc[inroot])
+ goto err_
+ }
+
+ if (imaccf (in, SFT_KW) == YES)
+ call imgstr (in, SFT_KW, Memc[inranges], SZ_LINE)
+ else
+ call strcpy ("", Memc[inranges], SZ_LINE)
+
+ if (imaccf (out, SFT_KW) == YES)
+ call imgstr (out, SFT_KW, Memc[outranges], SZ_LINE)
+ else {
+ call strcpy ("", Memc[outranges], SZ_LINE)
+ call imastr (out, SFT_KW, Memc[outranges])
+ }
+
+ mw = smw_openim (in)
+ ax1 = SMW_LLEN(mw,1)
+ ax2 = SMW_LLEN(mw,2)
+ ax3 = SMW_LLEN(mw,3)
+
+ rgin = rg_ranges (Memc[inranges], 1, ax2)
+ rgout = rg_ranges (Memc[outranges], 1, ax2)
+ rgtmp = rg_union (rgin, rgout)
+ call rg_free (rgin)
+ call rg_free (rgout)
+
+ if (imaccf (in, SFT_KWB) == YES)
+ call imgstr (in, SFT_KWB, Memc[inranges], SZ_LINE)
+ else
+ call strcpy ("", Memc[inranges], SZ_LINE)
+
+ if (imaccf (out, SFT_KWB) == YES)
+ call imgstr (out, SFT_KWB, Memc[outranges], SZ_LINE)
+ else {
+ call strcpy ("", Memc[outranges], SZ_LINE)
+ call imastr (out, SFT_KWB, Memc[outranges])
+ }
+
+ rgin = rg_ranges (Memc[inranges], 1, ax3)
+ rgout = rg_ranges (Memc[outranges], 1, ax3)
+ rgtmpb = rg_union (rgin, rgout)
+ call rg_free (rgin)
+ call rg_free (rgout)
+
+ if (OVERRIDE(sf) == YES) {
+ RGFIT(sf) = rg_window (RGIN(sf), 1, ax2)
+ RGREFIT(sf) = rgtmp
+ RGFITB(sf) = rg_window (RGINB(sf), 1, ax3)
+ RGREFITB(sf) = rgtmpb
+ } else {
+ call rg_inverse (rgtmp, 1, ax2)
+ RGFIT(sf) = rg_intersect (RGIN(sf), rgtmp)
+ RGREFIT(sf) = rg_ranges ("0", 1, 2)
+ call rg_free (rgtmp)
+ #call rg_inverse (rgtmpb, 1, ax3)
+ #RGFITB(sf) = rg_intersect (RGINB(sf), rgtmpb)
+ #RGREFITB(sf) = rg_ranges ("0", 1, 2)
+ #call rg_free (rgtmpb)
+ RGFITB(sf) = rg_window (RGINB(sf), 1, ax3)
+ RGREFITB(sf) = rgtmpb
+ }
+
+ if (RG_NPTS(RGFIT(sf)) <= 0) {
+ call sprintf (emsg, SZ_LINE, "No lines left to fit for %s")
+ call pargstr (Memc[inroot])
+ goto err_
+ }
+
+ call sfree (sp)
+ return
+
+err_ call sfree (sp)
+ call sft_unmap (in, out, mw, sh, sf)
+ if (GRAPH_OPEN(sf) == YES) {
+ call gclose (gp)
+ GRAPH_OPEN(sf) = NO
+ }
+ # STDERR should get flushed AFTER closing graphics
+ call error (1, emsg)
+end
+
+
+# SFT_UNMAP -- Unmap images for sfit.
+
+procedure sft_unmap (in, out, mw, sh, sf)
+
+pointer in, out #I IMIO pointers
+pointer mw #I MWCS pointer
+pointer sh #I SHDR pointer
+pointer sf #I Task structure pointer
+
+begin
+ call shdr_close (sh)
+ if (mw != NULL)
+ call smw_close (mw)
+ if (out != NULL && out != in)
+ call imunmap (out)
+ if (in != NULL)
+ call imunmap (in)
+ if (RGFIT(sf) != NULL)
+ call rg_free (RGFIT(sf))
+ if (RGREFIT(sf) != NULL)
+ call rg_free (RGREFIT(sf))
+ if (RGFITB(sf) != NULL)
+ call rg_free (RGFITB(sf))
+ if (RGREFITB(sf) != NULL)
+ call rg_free (RGREFITB(sf))
+end
+
+
+# SFT_ICFIT -- Given the image descriptors determine the fitting function
+# for each line and output the fit, difference, ratio or coefficients.
+
+int procedure sft_icfit (in, out, mw, sh, sf, gp, gt, graphics)
+
+pointer in, out #I IMIO pointers
+pointer mw #I MWCS pointer
+pointer sh #I SHDR pointer
+pointer sf #I Pointer for task switches
+pointer gp #I GIO pointer
+pointer gt #I GTOOLS pointer
+char graphics[ARB] #I Graphics device
+
+pointer sp, wts, cv, data
+int line, band, i, j, n
+
+int sft_getline()
+pointer gopen(), imps3r()
+real sft_efncr()
+extern sft_efncr
+
+begin
+ call smark (sp)
+ call salloc (wts, SMW_LLEN(mw,1), TY_REAL)
+
+ line = 0
+ band = 0
+ while (sft_getline (in, mw, sh, sf, gt, line, band) != EOF) {
+
+ call amovkr (1., Memr[wts], SN(sh))
+
+ if (QUIET(sf) == NO) {
+ if (GRAPH_OPEN(sf) == NO) {
+ gp = gopen (graphics, NEW_FILE, STDGRAPH)
+ GRAPH_OPEN(sf) = YES
+ }
+ call icg_fit (IC(sf), gp, "cursor", gt, cv, Memr[SX(sh)],
+ Memr[SY(sh)], Memr[wts], SN(sh))
+ } else
+ call ic_fit (IC(sf), cv, Memr[SX(sh)], Memr[SY(sh)],
+ Memr[wts], SN(sh), YES, YES, YES, YES)
+
+ if (LISTONLY(sf) == NO) {
+ i = LINDEX(sh,1)
+ j = LINDEX(sh,2)
+ n = SMW_LLEN(mw,1)
+ switch (SMW_LAXIS(mw,1)) {
+ case 1:
+ data = imps3r (out, 1, n, i, i, j, j)
+ case 2:
+ data = imps3r (out, i, i, 1, n, j, j)
+ case 3:
+ data = imps3r (out, i, i, j, j, 1, n)
+ }
+ if (SN(sh) < n)
+ call aclrr (Memr[data], n)
+
+ switch (OUTTYPE(sf)) {
+ case DATA:
+ if (REPLACE(sf) == YES)
+ call ic_clean (IC(sf), cv, Memr[SX(sh)], Memr[SY(sh)],
+ Memr[wts], SN(sh))
+ call amovr (Memr[SY(sh)], Memr[data], SN(sh))
+ call sft_update (out, mw, line, band)
+ case FIT:
+ call cvvector (cv, Memr[SX(sh)], Memr[data], SN(sh))
+ call sft_update (out, mw, line, band)
+ case DIFFERENCE:
+ call cvvector (cv, Memr[SX(sh)], Memr[data], SN(sh))
+ if (REPLACE(sf) == YES)
+ call ic_clean (IC(sf), cv, Memr[SX(sh)], Memr[SY(sh)],
+ Memr[wts], SN(sh))
+ call asubr (Memr[SY(sh)], Memr[data], Memr[data], SN(sh))
+ call sft_update (out, mw, line, band)
+ case RATIO:
+ call cvvector (cv, Memr[SX(sh)], Memr[data], SN(sh))
+ if (REPLACE(sf) == YES)
+ call ic_clean (IC(sf), cv, Memr[SX(sh)], Memr[SY(sh)],
+ Memr[wts], SN(sh))
+ call advzr (Memr[SY(sh)], Memr[data], Memr[data], SN(sh),
+ sft_efncr)
+ call sft_update (out, mw, line, band)
+ default:
+ call error (1, "bad switch in sft_icfit")
+ }
+ }
+
+ call sft_power (in, line, cv, gp, sf)
+ call cvfree (cv)
+
+ }
+
+ # This terminates the cursor (GIN) mode echoplex suppression in
+ # case the next sft_immap generates a password prompt from ZFIOKS.
+ # Note that any such password prompt (from the kernel!) will
+ # now show up on the status line, not the graphics plane.
+
+ if (GRAPH_OPEN(sf) == YES) {
+ call printf ("\r")
+ call flush (STDOUT)
+ }
+
+ call sfree (sp)
+ return (line)
+end
+
+
+# SFT_GETLINE -- Get image data to be fit. Returns the line and band numbers.
+# Returns EOF when done.
+
+int procedure sft_getline (in, mw, sh, sf, gt, line, band)
+
+pointer in #I IMIO pointer
+pointer mw #I MWCS pointer
+pointer sh #I SHDR pointer
+pointer sf #I Pointer for task switches
+pointer gt #I GTOOLS pointer
+int line #U Line number
+int band #U Band number
+
+int i
+bool waveok
+char ask[LEN_ANS]
+pointer linebuf, rg1, rg2, sp
+
+int clgwrd(), rg_next(), rg_inrange()
+pointer rg_ranges(), rg_intersect()
+real sft_efncr()
+extern sft_efncr
+errchk shdr_open
+
+define again_ 99
+
+begin
+ call smark (sp)
+ call salloc (linebuf, SZ_LINE, TY_CHAR)
+
+ if (band == 0)
+ if (rg_next (RGFITB(sf), band) == EOF)
+ return (EOF)
+
+again_ if (rg_next (RGFIT(sf), line) == EOF) {
+ line = 0
+ if (rg_next (RGFITB(sf), band) == EOF)
+ return (EOF)
+ goto again_
+ }
+
+ if (PROMPT(sf) == YES) {
+ call clprintf ("ask.p_min", "%s")
+ call pargstr (SFT_ANS1X)
+
+ if (rg_inrange (RGREFIT(sf), line) == YES &&
+ rg_inrange (RGREFITB(sf), band) == YES) {
+ call clprintf ("ask.p_prompt",
+ "Refit [%d,%d] of %s w/ graph? ")
+ } else {
+ call clprintf ("ask.p_prompt",
+ "Fit [%d,%d] of %s w/ graph? ")
+ }
+ call pargi (line)
+ call pargi (band)
+ call pargstr (IM_HDRFILE(in))
+
+ switch (clgwrd ("ask", ask, LEN_ANS, SFT_ANS1)) {
+
+ case YES_ONCE:
+ QUIET(sf) = NO
+
+ case NO_ONCE:
+ QUIET(sf) = YES
+
+ case SKIP_ONCE:
+ goto again_
+
+ case YES_ALWAYS:
+ QUIET(sf) = NO
+ PROMPT(sf) = NO
+
+ case NO_ALWAYS:
+ QUIET(sf) = YES
+ PROMPT(sf) = NO
+
+ case SKIP_ALWAYS:
+ call clprintf ("ask", "cancel")
+ call clprintf ("ask.p_min", "%s")
+ call pargstr (SFT_ANS2X)
+ call clprintf ("ask.p_prompt",
+ "Skip what? (`all' to exit task) ")
+
+ switch (clgwrd ("ask", ask, LEN_ANS, SFT_ANS2)) {
+
+ case SKIP_SPEC:
+ call clprintf ("ask", "yes")
+ # delete the spectrum from the list
+ call sprintf (Memc[linebuf], SZ_LINE, "%d")
+ call pargi (line)
+
+ rg1 = rg_ranges (Memc[linebuf], 1, SMW_LLEN(mw,2))
+ call rg_inverse (rg1, 1, SMW_LLEN(mw,2))
+ rg2 = rg_intersect (RGIN(sf), rg1)
+ call rg_free (rg1)
+ call rg_free (RGIN(sf))
+
+ RGIN(sf) = rg2
+ goto again_
+
+ case SKIP_IMAGE:
+ call clprintf ("ask", "yes")
+ return (EOF)
+
+ case SKIP_ALL:
+ call clprintf ("ask", "yes")
+ return (EOF)
+
+ case SKIP_CANCEL:
+ call clprintf ("ask", "yes")
+ line = line - 1
+ goto again_
+
+ default:
+ call error (1, "bad switch (2) in sft_getline")
+
+ }
+
+ default:
+ call error (1, "bad switch (1) in sft_getline")
+
+ }
+
+ }
+
+ call shdr_open (in, mw, line, band, INDEFI, SHDATA, sh)
+
+ if (LOGSCALE(sf) == YES)
+ call alogr (Memr[SY(sh)], Memr[SY(sh)], SN(sh), sft_efncr)
+
+ if (WAVESCALE(sf) == YES) {
+ waveok = true
+ } else
+ waveok = false
+
+ if (!waveok)
+ do i = 1, SN(sh)
+ Memr[SX(sh)+i-1] = i
+
+ if (LOGSCALE(sf) == YES)
+ call alogr (Memr[SX(sh)], Memr[SX(sh)], SN(sh), sft_efncr)
+
+ # Initialize and/or update the icfit descriptor
+
+ if (IC_DESC(sf,line,band) == NULL) {
+ call ic_open (IC_DESC(sf,line,band))
+ call ic_copy (IC(sf), IC_DESC(sf,line,band))
+ #call ic_pstr (IC_DESC(sf,line,band), "sample", "*")
+ }
+
+ IC(sf) = IC_DESC(sf,line,band)
+
+ call ic_putr (IC(sf), "xmin", min (Memr[SX(sh)], Memr[SX(sh)+SN(sh)-1]))
+ call ic_putr (IC(sf), "xmax", max (Memr[SX(sh)], Memr[SX(sh)+SN(sh)-1]))
+
+ if (QUIET(sf) == NO) {
+ if (waveok && LOGSCALE(sf) == YES) {
+ call ic_pstr (IC(sf), "xlabel", "log wavelength")
+ call ic_pstr (IC(sf), "ylabel", "log data")
+ } else if (LOGSCALE(sf) == YES) {
+ call ic_pstr (IC(sf), "xlabel", "log column")
+ call ic_pstr (IC(sf), "ylabel", "log data")
+ } else if (waveok) {
+ call ic_pstr (IC(sf), "xlabel", "wavelength")
+ call ic_pstr (IC(sf), "ylabel", "")
+ } else {
+ call ic_pstr (IC(sf), "xlabel", "column")
+ call ic_pstr (IC(sf), "ylabel", "")
+ }
+
+ call sprintf (Memc[linebuf], SZ_LINE, "%s, [%d,%d]\n%s")
+ call pargstr (IM_HDRFILE(in))
+ call pargi (line)
+ call pargi (band)
+ call pargstr (TITLE(sh))
+
+ call gt_sets (gt, GTTITLE, Memc[linebuf])
+ }
+
+ call sfree (sp)
+ return (OK)
+end
+
+
+# SFT_EFNCR -- Called by advzr on division by zero or by alogr for a
+# zero or negative argument.
+
+real procedure sft_efncr (x)
+
+real x
+
+begin
+ return (0.)
+end
+
+
+# SFT_POWER -- Transform the curfit output into a power series and
+# print the coefficients to the logfiles. This should be modified to
+# print the errors as well. That requires modifying the curfit routine
+# cvpower to deal with errors; and adding an icfit routine (or include
+# file define) that allows access to the dynamic arrays of sample points
+# that are initialized if the sample is less than the whole set of points.
+
+procedure sft_power (im, line, cv, gp, sf)
+
+pointer im #I IMIO descriptor for labeling
+int line #I Image line number for labeling
+pointer cv #I CURFIT pointer
+pointer gp #I GIO pointer for tidy output
+pointer sf #I Pointer for task switches
+
+pointer ps_coeff, linebuf, sp
+int ncoeffs, i, j, fd
+
+int cvstati(), strcmp()
+
+begin
+ if (NLOGFD(sf) <= 0)
+ return
+
+ call smark (sp)
+ call salloc (linebuf, SZ_LINE, TY_CHAR)
+
+ # cvpower only works with legendre or chebyshev functions
+
+ call ic_gstr (IC(sf), "function", Memc[linebuf], SZ_LINE)
+ if (strcmp (Memc[linebuf], "legendre") != 0 &&
+ strcmp (Memc[linebuf], "chebyshev") != 0) {
+ call sfree (sp)
+ return
+ }
+
+ if (GRAPH_OPEN(sf) == YES && LOG_TO_STDOUT(sf) == YES) {
+ call gclose (gp)
+ GRAPH_OPEN(sf) = NO
+ }
+
+ ncoeffs = cvstati (cv, CVNCOEFF)
+ call salloc (ps_coeff, ncoeffs, TY_REAL)
+ call cvpower (cv, Memr[ps_coeff], ncoeffs)
+
+ do i = 1, NLOGFD(sf) {
+ fd = Memi[LOGFD(sf)+i-1]
+
+ call fprintf (fd, "Line %d of %s:\n\n")
+ call pargi (line)
+ call pargstr (IM_HDRFILE(im))
+
+ call fprintf (fd, " coeff value\n")
+
+ do j = 1, ncoeffs {
+ call fprintf (fd, "\t%d\t%12.5e\n")
+ call pargi (j)
+ call pargr (Memr[ps_coeff+j-1])
+ }
+
+ call fprintf (fd, "\n")
+ call flush (fd)
+ }
+
+ call sfree (sp)
+end
+
+
+# SFT_UPDATE -- Update the keyword with completed spectrum. Flush the pixels.
+
+procedure sft_update (im, mw, line, band)
+
+pointer im #I IMIO pointer
+pointer mw #I MWCS pointer
+int line #I Line just completed
+int band #I Band just completed
+
+pointer linebuf, rg1, rg2, rgold, sp
+
+pointer rg_ranges(), rg_union()
+
+begin
+ call smark (sp)
+ call salloc (linebuf, SZ_LINE, TY_CHAR)
+
+ # this could be recoded to use "rg_add"
+
+ call sprintf (Memc[linebuf], SZ_LINE, "%d")
+ call pargi (line)
+ rg1 = rg_ranges (Memc[linebuf], 1, SMW_LLEN(mw,2))
+
+ call imgstr (im, SFT_KW, Memc[linebuf], SZ_LINE)
+ rg2 = rg_ranges (Memc[linebuf], 1, SMW_LLEN(mw,2))
+
+ rgold = rg_union (rg1, rg2)
+ call rg_encode (rgold, Memc[linebuf], SZ_LINE)
+ call impstr (im, SFT_KW, Memc[linebuf])
+
+ call rg_free (rg1)
+ call rg_free (rg2)
+ call rg_free (rgold)
+
+ call sprintf (Memc[linebuf], SZ_LINE, "%d")
+ call pargi (band)
+ rg1 = rg_ranges (Memc[linebuf], 1, SMW_LLEN(mw,3))
+
+ call imgstr (im, SFT_KWB, Memc[linebuf], SZ_LINE)
+ rg2 = rg_ranges (Memc[linebuf], 1, SMW_LLEN(mw,3))
+
+ rgold = rg_union (rg1, rg2)
+ call rg_encode (rgold, Memc[linebuf], SZ_LINE)
+ call impstr (im, SFT_KWB, Memc[linebuf])
+
+ call rg_free (rg1)
+ call rg_free (rg2)
+ call rg_free (rgold)
+
+ call imflush (im)
+ call sfree (sp)
+end