aboutsummaryrefslogtreecommitdiff
path: root/noao/onedspec/ecidentify/ecffit
diff options
context:
space:
mode:
Diffstat (limited to 'noao/onedspec/ecidentify/ecffit')
-rw-r--r--noao/onedspec/ecidentify/ecffit/ecfcolon.x102
-rw-r--r--noao/onedspec/ecidentify/ecffit/ecfeval.x68
-rw-r--r--noao/onedspec/ecidentify/ecffit/ecffit.com23
-rw-r--r--noao/onedspec/ecidentify/ecffit/ecffit.h20
-rw-r--r--noao/onedspec/ecidentify/ecffit/ecffit.key53
-rw-r--r--noao/onedspec/ecidentify/ecffit/ecffit.x193
-rw-r--r--noao/onedspec/ecidentify/ecffit/ecfgdata.x37
-rw-r--r--noao/onedspec/ecidentify/ecffit/ecfget.x84
-rw-r--r--noao/onedspec/ecidentify/ecffit/ecfgraph.x50
-rw-r--r--noao/onedspec/ecidentify/ecffit/ecfnearest.x85
-rw-r--r--noao/onedspec/ecidentify/ecffit/ecfreject.x53
-rw-r--r--noao/onedspec/ecidentify/ecffit/ecfrms.x26
-rw-r--r--noao/onedspec/ecidentify/ecffit/ecfset.x92
-rw-r--r--noao/onedspec/ecidentify/ecffit/ecfshift.x55
-rw-r--r--noao/onedspec/ecidentify/ecffit/ecfsolve.x196
-rw-r--r--noao/onedspec/ecidentify/ecffit/ecftitle.x48
-rw-r--r--noao/onedspec/ecidentify/ecffit/mkpkg21
17 files changed, 1206 insertions, 0 deletions
diff --git a/noao/onedspec/ecidentify/ecffit/ecfcolon.x b/noao/onedspec/ecidentify/ecffit/ecfcolon.x
new file mode 100644
index 00000000..4307335b
--- /dev/null
+++ b/noao/onedspec/ecidentify/ecffit/ecfcolon.x
@@ -0,0 +1,102 @@
+include <error.h>
+include <gset.h>
+
+# List of colon commands
+define CMDS "|show|function|xorder|yorder|niterate|lowreject|highreject|"
+
+define SHOW 1 # Show parameters
+define FUNCTION 2 # Set or show function type
+define XORDER 3 # Set or show x order of function
+define YORDER 4 # Set or show y order of function
+define NITERATE 5 # Set or show rejection iterations
+define LOW 6 # Set or show low rejection threshold
+define HIGH 7 # Set or show high rejection threshold
+
+# ECF_COLON -- Processes colon commands.
+
+procedure ecf_colon (cmdstr, gp)
+
+char cmdstr[ARB] # Command string
+pointer gp # GIO pointer
+
+double dval
+int ncmd, ival
+int nscan(), strdic()
+include "ecffit.com"
+
+begin
+ # Use formated scan to parse the command string.
+ # The first word is the command and it may be minimum match
+ # abbreviated with the list of commands.
+
+ call sscan (cmdstr)
+ call gargwrd (ecfstr, SZ_LINE)
+ ncmd = strdic (ecfstr, ecfstr, SZ_LINE, CMDS)
+
+ switch (ncmd) {
+ case SHOW: # :show - Show the values of the fitting parameters.
+ call gdeactivate (gp, AW_CLEAR)
+ call printf ("function %s\nxorder %d\nyorder %d\n")
+ call pargstr (function)
+ call pargi (xorder)
+ call pargi (yorder)
+ call printf ("niterate %d\nlowreject %g\nhighreject\nnreject %d\n")
+ call pargi (niterate)
+ call pargd (low)
+ call pargd (high)
+ call pargi (nreject)
+ call printf ("slope %d\noffset %d\nshift %g\n")
+ call pargi (slope)
+ call pargi (offset)
+ call pargd (shift)
+ call printf ("rms %g\n")
+ call pargd (rms)
+ call greactivate (gp, AW_PAUSE)
+ case FUNCTION: # :function - List or set the fitting function.
+ call gargwrd (ecfstr, SZ_LINE)
+ if (nscan() == 1) {
+ call printf ("function = %s\n")
+ call pargstr (function)
+ } else {
+ iferr (call ecf_sets ("function", ecfstr))
+ call erract (EA_WARN)
+ }
+ case XORDER: # xorder: List or set the function order.
+ call gargi (ival)
+ if (nscan() == 1) {
+ call printf ("xorder %d\n")
+ call pargi (xorder)
+ } else
+ xorder = ival
+ case YORDER: # yorder: List or set the function order.
+ call gargi (ival)
+ if (nscan() == 1) {
+ call printf ("yorder %d\n")
+ call pargi (yorder)
+ } else
+ yorder = ival
+ case NITERATE: # niterate: List or set rejection iterations.
+ call gargi (ival)
+ if (nscan() == 1) {
+ call printf ("niterate %d\n")
+ call pargi (niterate)
+ } else
+ niterate = ival
+ case LOW: # low: List or set low rejection threshold.
+ call gargd (dval)
+ if (nscan() == 1) {
+ call printf ("lowreject %g\n")
+ call pargd (low)
+ } else
+ low = dval
+ case HIGH: # highreject: List or set high rejection threshold.
+ call gargd (dval)
+ if (nscan() == 1) {
+ call printf ("highreject %g\n")
+ call pargd (high)
+ } else
+ high = dval
+ default:
+ call printf ("Unrecognized or ambiguous command\007")
+ }
+end
diff --git a/noao/onedspec/ecidentify/ecffit/ecfeval.x b/noao/onedspec/ecidentify/ecffit/ecfeval.x
new file mode 100644
index 00000000..1901522f
--- /dev/null
+++ b/noao/onedspec/ecidentify/ecffit/ecfeval.x
@@ -0,0 +1,68 @@
+# ECF_EVAL -- Evaluate wavelength at a given order and pixel position.
+
+double procedure ecf_eval (ecf, order, x)
+
+pointer ecf # GSURFIT pointer
+int order # Order
+double x # X point
+
+int ecf_oeval()
+double y, dgseval()
+include "ecffit.com"
+
+begin
+ y = ecf_oeval (ecf, order)
+ if (ecf == NULL)
+ return (x + shift / y)
+ else
+ return ((dgseval (ecf, x, y) + shift) / y)
+end
+
+
+# ECF_VECTOR -- Evaluate echelle dispersion function for a vector of points of
+# the same order.
+
+procedure ecf_vector (ecf, order, x, fit, npts)
+
+pointer ecf # GSURFIT pointer
+int order # Order
+double x[npts] # X points
+double fit[npts] # Fitted points
+int npts # Number of points
+
+double yval
+pointer sp, y
+int ecf_oeval()
+include "ecffit.com"
+
+begin
+ call smark (sp)
+ call salloc (y, npts, TY_DOUBLE)
+
+ yval = ecf_oeval (ecf, order)
+ if (ecf == NULL)
+ call amovd (x, fit, npts)
+ else {
+ call amovkd (yval, Memd[y], npts)
+ call dgsvector (ecf, x, Memd[y], fit, npts)
+ call adivkd (fit, yval, fit, npts)
+ }
+ if (shift != 0.)
+ call aaddkd (fit, shift / yval, fit, npts)
+
+ call sfree (sp)
+end
+
+
+# ECF_OEVAL -- Evaluate the fit order.
+
+int procedure ecf_oeval (ecf, order)
+
+pointer ecf # GSURFIT pointer
+int order # User order
+
+include "ecffit.com"
+
+begin
+ return (slope * order + offset)
+end
diff --git a/noao/onedspec/ecidentify/ecffit/ecffit.com b/noao/onedspec/ecidentify/ecffit/ecffit.com
new file mode 100644
index 00000000..61f3104a
--- /dev/null
+++ b/noao/onedspec/ecidentify/ecffit/ecffit.com
@@ -0,0 +1,23 @@
+# Common parameters.
+
+char function[SZ_FNAME] # Fitting function
+char ecfstr[SZ_LINE] # Working char string
+int gstype # Surface function type
+int xorder # X order of surface function
+int yorder # Y order of surface function
+int niterate # Number of rejection iterations
+int nreject # Number of rejected points
+int xtype # X axis type
+int ytype # Y axis type
+int slope # Slope of order
+int offset # Order offset of fit
+double low, high # Low and high rejection thresholds
+double xmin, xmax # X range
+double ymin, ymax # Y range
+double shift # First order shift
+double rms # RMS of fit
+
+
+common /ecfcom/ low, high, xmin, xmax, ymin, ymax, shift, rms, gstype,
+ xorder, yorder, niterate, nreject, xtype, ytype, slope, offset,
+ function, ecfstr
diff --git a/noao/onedspec/ecidentify/ecffit/ecffit.h b/noao/onedspec/ecidentify/ecffit/ecffit.h
new file mode 100644
index 00000000..20825c71
--- /dev/null
+++ b/noao/onedspec/ecidentify/ecffit/ecffit.h
@@ -0,0 +1,20 @@
+define IGSPARAMS 7
+
+define FEATURE 1
+define X 2
+define Y 3
+define Z 4
+define W 5
+define S 6
+define R 7
+
+define IGS_FUNCTION 1
+define IGS_XORDER 2
+define IGS_YORDER 3
+define IGS_XMIN 4
+define IGS_XMAX 5
+define IGS_YMIN 6
+define IGS_YMAX 7
+define IGS_OFFSET 8
+
+define SFTYPES "|chebyshev|legendre|" # Surface types
diff --git a/noao/onedspec/ecidentify/ecffit/ecffit.key b/noao/onedspec/ecidentify/ecffit/ecffit.key
new file mode 100644
index 00000000..f24407b9
--- /dev/null
+++ b/noao/onedspec/ecidentify/ecffit/ecffit.key
@@ -0,0 +1,53 @@
+ ECHELLE DISPERSION FUNCTION FITTING KEYS
+
+
+CURSOR KEY SUMMARY
+
+? Help c Print coordinates d Delete point
+f Fit dispersion o Fit with fixed order offset q Quit
+r Redraw graph u Undelete point w Window graph
+x Set ordinate y Set abscissa I Interrupt
+
+
+COLON COMMAND SUMMARY
+
+:show :function [value] :highreject [value] :lowreject [value]
+:niterate [value] :xorder [value] :yorder [value]
+
+
+CURSOR KEYS
+
+? Print this list of cursor keys
+c Print cursor coordinates
+d Delete the nearest undeleted point to the cursor
+f Fit dispersion function including determining the order offset
+o Fit dispersion function with the order offset fixed
+q Quit and return to the spectrum display
+r Redraw the graph
+u Undelete the nearest deleted point to the cursor (may be outside the window)
+w Window the graph (type ? to the window prompt for more help)
+x Set the quantity plotted along the ordinate (x axis)
+y Set the quantity plotted along the abscissa (y axis)
+I Interrupt the task immediately
+
+
+COLON COMMANDS
+
+:show Print current function and orders
+:function [value] Print or set the function type (chebyshev|legendre)
+:highreject [value] Print or set high rejection limit
+:lowreject [value] Print or set high rejection limit
+:niterate [value] Print or set number of rejection iterations
+:xorder [value] Print or set the order for the dispersion dependence
+:yorder [value] Print or set the order for the echelle order dependence
+
+
+The dispersion function fitted is given by a two dimensional function
+(either chebyshev or legendre) of the pixel position along the
+dispersion of an order (called x) and the order number (called y). The
+order number is determined from the aperture number by an offset and
+direction of increasing order number. The basic order dependence is
+separated from the surface function as given below.
+
+ y = offset +/- aperture
+ wavelength = f (x, y) / y
diff --git a/noao/onedspec/ecidentify/ecffit/ecffit.x b/noao/onedspec/ecidentify/ecffit/ecffit.x
new file mode 100644
index 00000000..408a1b77
--- /dev/null
+++ b/noao/onedspec/ecidentify/ecffit/ecffit.x
@@ -0,0 +1,193 @@
+include <error.h>
+include <pkg/gtools.h>
+
+define HELP "noao$onedspec/ecidentify/ecffit/ecffit.key"
+define PROMPT "fitcoords surface fitting options"
+
+# EC_FIT -- Echelle dispersion fitting.
+#
+# X - Pixel coordinates along dispersion
+# Y - Relative order number
+# Z - Wavelength
+
+procedure ecf_fit (ecf, gp, gt, xd, yd, zd, wd, npts, fixedorder)
+
+pointer ecf # GSURFIT pointer
+pointer gp # GIO pointer
+pointer gt # GTOOLS pointer
+double xd[npts] # Pixel coordinates along dispersion
+double yd[npts] # Order number
+double zd[npts] # Wavelength
+double wd[npts] # Weights
+int npts # Number of points
+int fixedorder # Fixed order?
+
+real wx, wy
+int wcs, key
+int i, newgraph
+pointer sp, wd1, rd, xr, yr
+char cmd[SZ_LINE]
+
+int ecf_nearest()
+int clgcur(), scan(), nscan()
+errchk ecf_solve()
+include "ecffit.com"
+
+begin
+ # Allocate residuals and weights with rejected points arrays
+ call smark (sp)
+ call salloc (wd1, npts, TY_DOUBLE)
+ call salloc (rd, npts, TY_DOUBLE)
+ call amovd (wd, Memd[wd1], npts)
+
+ # Compute a solution and return if not interactive.
+ if (gp == NULL) {
+ call ecf_solve (ecf, xd, yd, zd, Memd[wd1], Memd[rd], npts,
+ fixedorder)
+ call ecf_reject (ecf, xd, yd, zd, Memd[wd1], Memd[rd], npts,
+ fixedorder)
+ do i = 1, npts
+ if (Memd[wd1+i-1] != wd[i])
+ wd[i] = -1.
+ call sfree (sp)
+ return
+ }
+
+ # Allocate real graph vectors.
+ call salloc (xr, npts, TY_REAL)
+ call salloc (yr, npts, TY_REAL)
+
+ # Read cursor commands.
+ key = 'f'
+ repeat {
+ switch (key) {
+ case 'o':
+ call printf ("Order offset (%d): ")
+ call pargi (offset)
+ call flush (STDOUT)
+ if (scan() != EOF) {
+ call gargi (i)
+ if (nscan() == 1)
+ offset = i
+ call amovd (wd, Memd[wd1], npts)
+ call ecf_solve (ecf, xd, yd, zd, Memd[wd1], Memd[rd], npts,
+ YES)
+ call ecf_reject (ecf, xd, yd, zd, Memd[wd1], Memd[rd], npts,
+ YES)
+ call ecf_gdata (ecf, xtype, xd, yd, zd, Memd[rd],
+ Memr[xr], npts)
+ call ecf_gdata (ecf, ytype, xd, yd, zd, Memd[rd],
+ Memr[yr], npts)
+ call ecf_title (gt)
+ newgraph = YES
+ }
+
+ case '?': # Print help text.
+ call gpagefile (gp, HELP, PROMPT)
+
+ case ':': # List or set parameters
+ if (cmd[1] == '/')
+ call gt_colon (cmd, gp, gt, newgraph)
+ else
+ call ecf_colon (cmd, gp)
+
+ case 'x': # Set ordinate
+ call printf ("Ordinate - ")
+ call printf (
+ "(p)ixel, (o)rder, (w)avelength, (r)esidual, (v)elocity: ")
+ if (clgcur ("cursor", wx, wy, wcs, key, cmd, SZ_LINE) == EOF)
+ break
+
+ if (key != xtype) {
+ if (key=='p'||key=='o'||key=='w'||key=='r'||key=='v') {
+ xtype = key
+ call gt_setr (gt, GTXMIN, INDEF)
+ call gt_setr (gt, GTXMAX, INDEF)
+ call ecf_gdata (ecf, xtype, xd, yd, zd, Memd[rd],
+ Memr[xr], npts)
+ call ecf_title (gt)
+ newgraph = YES
+ } else
+ call printf ("\007")
+ }
+
+ case 'y': # Set abscissa
+ call printf ("Abscissa - ")
+ call printf (
+ "(p)ixel, (o)rder, (w)avelength, (r)esidual, (v)elocity: ")
+ if(clgcur ("cursor", wx, wy, wcs, key, cmd, SZ_LINE) == EOF)
+ break
+
+ if (key != ytype) {
+ if (key=='p'||key=='o'||key=='w'||key=='r'||key=='v') {
+ ytype = key
+ call gt_setr (gt, GTYMIN, INDEF)
+ call gt_setr (gt, GTYMAX, INDEF)
+ call ecf_gdata (ecf, ytype, xd, yd, zd, Memd[rd],
+ Memr[yr], npts)
+ call ecf_title (gt)
+ newgraph = YES
+ } else
+ call printf ("\007")
+ }
+
+ case 'r': # Redraw
+ newgraph = YES
+
+ case 'c': # Cursor coordinates
+ i = ecf_nearest (gp, gt, wx, wy, wcs, key, Memr[xr], Memr[yr],
+ wd, npts)
+ call printf ("%10.2g %d %10.8g\n")
+ call pargd (xd[i])
+ call pargd (yd[i])
+ call pargd (zd[i])
+
+ case 'd': # Delete
+ i = ecf_nearest (gp, gt, wx, wy, wcs, key, Memr[xr], Memr[yr],
+ wd, npts)
+ if (i > 0)
+ Memd[wd1+i-1] = wd[i]
+
+ case 'u': # Undelete
+ i = ecf_nearest (gp, gt, wx, wy, wcs, key, Memr[xr], Memr[yr],
+ wd, npts)
+ if (i > 0)
+ Memd[wd1+i-1] = wd[i]
+
+ case 'f': # Fit
+ call amovd (wd, Memd[wd1], npts)
+ call ecf_solve (ecf, xd, yd, zd, Memd[wd1], Memd[rd], npts,
+ fixedorder)
+ call ecf_reject (ecf, xd, yd, zd, Memd[wd1], Memd[rd], npts,
+ fixedorder)
+ call ecf_gdata (ecf, xtype, xd, yd, zd, Memd[rd],
+ Memr[xr], npts)
+ call ecf_gdata (ecf, ytype, xd, yd, zd, Memd[rd],
+ Memr[yr], npts)
+ call ecf_title (gt)
+ newgraph = YES
+
+ case 'w': # Window graph
+ call gt_window (gt, gp, "cursor", newgraph)
+
+ case 'q': # Quit
+ break
+
+ case 'I': # Interrupt
+ call fatal (0, "Interrupt")
+
+ default: # Ring the bell.
+ call printf ("\07\n")
+ }
+
+ if (newgraph == YES) {
+ call ecf_graph (gp, gt, Memr[xr], Memr[yr], wd, Memd[wd1], npts)
+ newgraph = NO
+ }
+ } until (clgcur ("cursor", wx, wy, wcs, key, cmd, SZ_LINE) == EOF)
+
+ do i = 1, npts
+ if (Memd[wd1+i-1] != wd[i])
+ wd[i] = -1.
+ call sfree (sp)
+end
diff --git a/noao/onedspec/ecidentify/ecffit/ecfgdata.x b/noao/onedspec/ecidentify/ecffit/ecfgdata.x
new file mode 100644
index 00000000..eebb34d6
--- /dev/null
+++ b/noao/onedspec/ecidentify/ecffit/ecfgdata.x
@@ -0,0 +1,37 @@
+include <pkg/gtools.h>
+
+# ECF_GDATA -- Get graph data for the specified axis type from the fitting data.
+
+procedure ecf_gdata (ecf, type, x, y, z, r, data, npts)
+
+pointer ecf # GSURFIT pointer
+int type # Axis type
+double x[npts] # X fit data
+double y[npts] # Y fit data
+double z[npts] # Z fit data
+double r[npts] # Residuals
+real data[npts] # Graph data
+int npts # Number of points
+
+pointer sp, v
+include "ecffit.com"
+
+begin
+ switch (type) {
+ case 'p':
+ call achtdr (x, data, npts)
+ case 'o':
+ call achtdr (y, data, npts)
+ case 'w':
+ call achtdr (z, data, npts)
+ case 'r':
+ call achtdr (r, data, npts)
+ case 'v':
+ call smark (sp)
+ call salloc (v, npts, TY_DOUBLE)
+ call adivd (r, z, Memd[v], npts)
+ call amulkd (Memd[v], 300000.D0, Memd[v], npts)
+ call achtdr (Memd[v], data, npts)
+ call sfree (sp)
+ }
+end
diff --git a/noao/onedspec/ecidentify/ecffit/ecfget.x b/noao/onedspec/ecidentify/ecffit/ecfget.x
new file mode 100644
index 00000000..025059df
--- /dev/null
+++ b/noao/onedspec/ecidentify/ecffit/ecfget.x
@@ -0,0 +1,84 @@
+# ECF_GETI -- Get the value of an integer parameter.
+
+int procedure ecf_geti (param)
+
+char param[ARB] # ECF parameter
+
+int i, strdic()
+include "ecffit.com"
+
+begin
+ i = strdic (param, ecfstr, SZ_LINE,
+ "|slope|offset|xorder|yorder|niterate|")
+ switch (i) {
+ case 1:
+ return (slope)
+ case 2:
+ return (offset)
+ case 3:
+ return (xorder)
+ case 4:
+ return (yorder)
+ case 5:
+ return (niterate)
+ default:
+ call error (0, "ecf_geti: Unknown parameter")
+ }
+end
+
+
+# ECF_GETS -- Get the value of a string parameter.
+
+procedure ecf_gets (param, str, maxchar)
+
+char param[ARB] # ECF parameter
+char str[maxchar] # String
+int maxchar # Maximum number of characters
+
+int i, strdic()
+include "ecffit.com"
+
+begin
+ i = strdic (param, ecfstr, SZ_LINE, "|function|")
+ switch (i) {
+ case 1:
+ call strcpy (function, str, maxchar)
+ default:
+ call error (0, "ecf_gets: Unknown parameter")
+ }
+end
+
+
+# ECF_GETD -- Get the values of double valued fitting parameters.
+
+double procedure ecf_getd (param)
+
+char param[ARB] # ECF parameter
+
+int i, strdic()
+include "ecffit.com"
+
+begin
+ i = strdic (param, ecfstr, SZ_LINE,
+ "|xmin|xmax|ymin|ymax|shift|rms|low|high|")
+ switch (i) {
+ case 1:
+ return (xmin)
+ case 2:
+ return (xmax)
+ case 3:
+ return (ymin)
+ case 4:
+ return (ymax)
+ case 5:
+ return (shift)
+ case 6:
+ return (rms)
+ case 7:
+ return (low)
+ case 8:
+ return (high)
+ default:
+ call error (0, "ecf_gets: Unknown parameter")
+ }
+end
diff --git a/noao/onedspec/ecidentify/ecffit/ecfgraph.x b/noao/onedspec/ecidentify/ecffit/ecfgraph.x
new file mode 100644
index 00000000..22749527
--- /dev/null
+++ b/noao/onedspec/ecidentify/ecffit/ecfgraph.x
@@ -0,0 +1,50 @@
+include <gset.h>
+include <mach.h>
+include <pkg/gtools.h>
+
+# ECF_GRAPH -- Graph the fitted data.
+
+procedure ecf_graph (gp, gt, x, y, w, rej, npts)
+
+pointer gp # GIO pointer
+pointer gt # GTOOLS pointer
+real x[npts] # X data
+real y[npts] # Y data
+double w[npts] # Weights
+double rej[npts] # Rejected points
+int npts # Number of pts points
+
+int i
+real xsize, ysize, ymin, ymax, gt_getr()
+
+begin
+ xsize = gt_getr (gt, GTXSIZE)
+ ysize = gt_getr (gt, GTYSIZE)
+
+ call gclear (gp)
+
+ ymin = MAX_REAL
+ ymax = -MAX_REAL
+ do i = 1, npts
+ if (w[i] > 0.) {
+ ymin = min (ymin, y[i])
+ ymax = max (ymax, y[i])
+ }
+
+ call gascale (gp, x, npts, 1)
+ call gswind (gp, INDEF, INDEF, ymin, ymax)
+ call gt_swind (gp, gt)
+ call gt_labax (gp, gt)
+
+ do i = 1, npts {
+ if (rej[i] == 0.) {
+ if (y[i] >= ymin && y[i] <= ymax) {
+ if (w[i] == 0.)
+ call gmark (gp, x[i], y[i], GM_CROSS, xsize, ysize)
+ else
+ call gmark (gp, x[i], y[i], GM_DIAMOND, xsize, ysize)
+ }
+ } else
+ call gmark (gp, x[i], y[i], GM_PLUS, xsize, ysize)
+ }
+end
diff --git a/noao/onedspec/ecidentify/ecffit/ecfnearest.x b/noao/onedspec/ecidentify/ecffit/ecfnearest.x
new file mode 100644
index 00000000..af1b1f78
--- /dev/null
+++ b/noao/onedspec/ecidentify/ecffit/ecfnearest.x
@@ -0,0 +1,85 @@
+include <mach.h>
+include <gset.h>
+include <pkg/gtools.h>
+
+# ECF_NEAREST -- Find nearest point to the cursor.
+
+int procedure ecf_nearest (gp, gt, wx, wy, wcs, key, x, y, w, npts)
+
+pointer gp # GIO pointer
+pointer gt # GTOOLS pointer
+real wx, wy # Cursor coordinates
+int wcs # WCS
+int key # Nearest key
+real x[npts] # Data points
+real y[npts] # Data points
+double w[npts] # Weight
+int npts # Number of data points
+
+int i, j
+real r2, r2min, x0, y0, xsize, ysize, gt_getr()
+
+begin
+ call gctran (gp, wx, wy, wx, wy, wcs, 0)
+ r2min = MAX_REAL
+ j = 0
+
+ switch (key) {
+ case 'c':
+ do i = 1, npts {
+ call gctran (gp, x[i], y[i], x0, y0, wcs, 0)
+ r2 = (x0 - wx) ** 2 + (y0 - wy) ** 2
+ if (r2 < r2min) {
+ r2min = r2
+ j = i
+ }
+ }
+ call gscur (gp, x[j], y[j])
+ case 'd':
+ do i = 1, npts {
+ if (w[i] == 0.)
+ next
+ call gctran (gp, x[i], y[i], x0, y0, wcs, 0)
+ r2 = (x0 - wx) ** 2 + (y0 - wy) ** 2
+ if (r2 < r2min) {
+ r2min = r2
+ j = i
+ }
+ }
+ if (j > 0) {
+ xsize = gt_getr (gt, GTXSIZE)
+ ysize = gt_getr (gt, GTYSIZE)
+
+ call gseti (gp, G_PMLTYPE, 0)
+ call gmark (gp, x[j], y[j], GM_PLUS, xsize, ysize)
+ call gseti (gp, G_PMLTYPE, 1)
+ call gmark (gp, x[j], y[j], GM_CROSS, xsize, ysize)
+ w[j] = 0.
+ call gscur (gp, x[j], y[j])
+ }
+ case 'u':
+ do i = 1, npts {
+ if (w[i] != 0.)
+ next
+ call gctran (gp, x[i], y[i], x0, y0, wcs, 0)
+ r2 = (x0 - wx) ** 2 + (y0 - wy) ** 2
+ if (r2 < r2min) {
+ r2min = r2
+ j = i
+ }
+ }
+ if (j > 0) {
+ xsize = gt_getr (gt, GTXSIZE)
+ ysize = gt_getr (gt, GTYSIZE)
+
+ call gseti (gp, G_PMLTYPE, 0)
+ call gmark (gp, x[j], y[j], GM_CROSS, xsize, ysize)
+ call gseti (gp, G_PMLTYPE, 1)
+ call gmark (gp, x[j], y[j], GM_PLUS, xsize, ysize)
+ w[j] = 1.
+ call gscur (gp, x[j], y[j])
+ }
+ }
+
+ return (j)
+end
diff --git a/noao/onedspec/ecidentify/ecffit/ecfreject.x b/noao/onedspec/ecidentify/ecffit/ecfreject.x
new file mode 100644
index 00000000..a772069e
--- /dev/null
+++ b/noao/onedspec/ecidentify/ecffit/ecfreject.x
@@ -0,0 +1,53 @@
+include <mach.h>
+
+# ECF_REJECT -- Reject points with large residuals from the fit.
+
+procedure ecf_reject (ecf, x, y, z, w, r, npts, fixedorder)
+
+pointer ecf # GSURFIT pointer
+double x[npts] # X points
+double y[npts] # Y points
+double z[npts] # Z points
+double w[npts] # Weights
+double r[npts] # Residuals
+int npts # Number of points
+int fixedorder # Fixed order?
+
+int i, j, newreject
+double low_cut, high_cut
+include "ecffit.com"
+
+begin
+ # Return if rejection is not desired.
+ nreject = 0
+ if (niterate == 0 || (low == 0. && high == 0.))
+ return
+
+ # Reject points.
+ do i = 1, niterate {
+ if (low > 0.)
+ low_cut = -low * rms
+ else
+ low_cut = -MAX_REAL
+ if (high > 0.)
+ high_cut = high * rms
+ else
+ high_cut = MAX_REAL
+
+ newreject = 0
+ do j = 1, npts {
+ if (w[j] == 0.)
+ next
+ if ((r[j] > high_cut) || (r[j] < low_cut)) {
+ w[j] = 0.
+ newreject = newreject + 1
+ }
+ }
+
+ if (newreject == 0)
+ break
+
+ call ecf_solve (ecf, x, y, z, w, r, npts, fixedorder)
+ nreject = nreject + newreject
+ }
+end
diff --git a/noao/onedspec/ecidentify/ecffit/ecfrms.x b/noao/onedspec/ecidentify/ecffit/ecfrms.x
new file mode 100644
index 00000000..1140dc29
--- /dev/null
+++ b/noao/onedspec/ecidentify/ecffit/ecfrms.x
@@ -0,0 +1,26 @@
+# ECF_RMS -- Compute the rms with deleted points ignored.
+
+double procedure ecf_rms (r, w, npts)
+
+double r[npts] # Residuals
+double w[npts] # Weights
+int npts # Number of points
+
+int i, n
+double rms
+
+begin
+ n = 0
+ rms = 0.
+ do i = 1, npts {
+ if (w[i] == 0.)
+ next
+ n = n + 1
+ rms = rms + r[i] * r[i]
+ }
+ if (n > 0)
+ rms = sqrt (rms / n)
+ else
+ rms = INDEFD
+ return (rms)
+end
diff --git a/noao/onedspec/ecidentify/ecffit/ecfset.x b/noao/onedspec/ecidentify/ecffit/ecfset.x
new file mode 100644
index 00000000..4b6402b1
--- /dev/null
+++ b/noao/onedspec/ecidentify/ecffit/ecfset.x
@@ -0,0 +1,92 @@
+# ECF_SETS -- Set the values of string valued fitting parameters.
+
+procedure ecf_sets (param, str)
+
+char param[ARB] # Parameter to be set
+char str[ARB] # String value
+
+char temp[10]
+int i, strdic()
+include "ecffit.com"
+
+begin
+ i = strdic (param, temp, 10, "|function|")
+ switch (i) {
+ case 1:
+ i = strdic (str, str, SZ_FNAME, "|chebyshev|legendre|")
+ if (i == 0)
+ call error (0, "Unknown function type")
+ call strcpy (str, function, SZ_LINE)
+ gstype = i
+ default:
+ call error (0, "ecf_sets: Unknown parameter")
+ }
+end
+
+
+# ECF_SETI -- Set the values of integer valued fitting parameters.
+
+procedure ecf_seti (param, ival)
+
+char param[ARB] # Parameter to be set
+int ival # Integer value
+
+int i, strdic()
+include "ecffit.com"
+
+begin
+ i = strdic (param, ecfstr, SZ_LINE,
+ "|slope|offset|xorder|yorder|xtype|ytype|niterate|")
+ switch (i) {
+ case 1:
+ slope = ival
+ case 2:
+ offset = ival
+ case 3:
+ xorder = ival
+ case 4:
+ yorder = ival
+ case 5:
+ xtype = ival
+ case 6:
+ ytype = ival
+ case 7:
+ niterate = max (0, ival)
+ default:
+ call error (0, "ecf_seti: Unknown parameter")
+ }
+end
+
+
+# ECF_SETD -- Set the values of double valued fitting parameters.
+
+procedure ecf_setd (param, dval)
+
+char param[ARB] # Parameter to be set
+double dval # Double value
+
+int i, strdic()
+include "ecffit.com"
+
+begin
+ i = strdic (param, ecfstr, SZ_LINE,
+ "|xmin|xmax|ymin|ymax|shift|low|high|")
+ switch (i) {
+ case 1:
+ xmin = dval
+ case 2:
+ xmax = dval
+ case 3:
+ ymin = dval
+ case 4:
+ ymax = dval
+ case 5:
+ shift = dval
+ case 6:
+ low = max (0.D0, dval)
+ case 7:
+ high = max (0.D0, dval)
+ default:
+ call error (0, "ecf_setd: Unknown parameter")
+ }
+end
diff --git a/noao/onedspec/ecidentify/ecffit/ecfshift.x b/noao/onedspec/ecidentify/ecffit/ecfshift.x
new file mode 100644
index 00000000..75655703
--- /dev/null
+++ b/noao/onedspec/ecidentify/ecffit/ecfshift.x
@@ -0,0 +1,55 @@
+# ECF_GSHIFT -- Return the shift for the given order.
+
+double procedure ecf_gshift (ecf, order)
+
+pointer ecf # GSURFIT pointer
+int order # User order
+
+include "ecffit.com"
+
+begin
+ return (shift / (slope * order + offset))
+end
+
+
+# ECF_PSHIFT -- Put the shift for the given order.
+
+procedure ecf_pshift (ecf, order, shft)
+
+pointer ecf # GSURFIT pointer
+int order # User order
+double shft # Shift at given order
+
+include "ecffit.com"
+
+begin
+ shift = shft * (slope * order + offset)
+end
+
+
+procedure ecf_vector (ecf, order, x, fit, npts)
+
+pointer ecf # GSURFIT pointer
+int order # Order
+double x[npts] # X points
+double fit[npts] # Fitted points
+int npts # Number of points
+
+double yval
+pointer sp, y
+
+include "ecffit.com"
+
+begin
+ call smark (sp)
+ call salloc (y, npts, TY_DOUBLE)
+
+ yval = slope * order + offset
+ call amovkd (yval, Memd[y], npts)
+ call dgsvector (ecf, x, Memd[y], fit, npts)
+ call adivkd (fit, yval, fit, npts)
+ if (shift != 0.)
+ call aaddkd (fit, shift / yval, fit, npts)
+
+ call sfree (sp)
+end
diff --git a/noao/onedspec/ecidentify/ecffit/ecfsolve.x b/noao/onedspec/ecidentify/ecffit/ecfsolve.x
new file mode 100644
index 00000000..1c844e76
--- /dev/null
+++ b/noao/onedspec/ecidentify/ecffit/ecfsolve.x
@@ -0,0 +1,196 @@
+include <mach.h>
+include <math/gsurfit.h>
+
+define ECFTYPES "|chebyshev|legendre|" # Fit types
+
+
+# ECF_SOLVE -- Fit
+#
+# f(x, slope*y+offset) = (y+slope*offset)*z
+#
+# with offset minimizing the RMS.
+
+procedure ecf_solve (ecf, x, y, z, w, r, npts, fixedorder)
+
+pointer ecf # GSURFIT pointer
+double x[npts] # X points
+double y[npts] # Y points
+double z[npts] # Z points
+double w[npts] # Weights
+double r[npts] # Residuals
+int npts # Number of points
+int fixedorder # Fixed order?
+
+int i, j, k, err
+double ya, yb, newrms, ecf_rms()
+pointer sp, y1, ecf1
+errchk ecf_solve1
+include "ecffit.com"
+define fit_ 99
+
+begin
+ if (fixedorder == YES) {
+ call ecf_solve1 (ecf, x, y, z, w, r, npts)
+ return
+ }
+
+ call smark (sp)
+ call salloc (y1, npts, TY_DOUBLE)
+
+ # Determine if the orders are reversed.
+ j = 1
+ k = 1
+ do i = 1, npts {
+ if (z[i] < z[j])
+ j = i
+ if (z[i] > z[k])
+ k = i
+ }
+ if (y[j] >= y[k]) {
+ slope = 1
+ offset = max (offset, int(1. - ymin))
+ } else {
+ slope = -1
+ offset = max (offset, int(1. + ymax))
+ }
+
+ call dgsfree (ecf)
+ shift = 0.
+
+ rms = MAX_DOUBLE
+ j = 1
+ k = 0
+
+ for (i=offset;;i=i+j) {
+ if (slope == 1) {
+ ya = i + ymin
+ yb = i + ymax
+ } else {
+ ya = i - ymax
+ yb = i - ymin
+ }
+ if (ya < 1.)
+ break
+
+ call altmd (y, Memd[y1], npts, double(slope), double(i))
+ call amuld (Memd[y1], z, r, npts)
+
+fit_ call dgsinit (ecf1, gstype, xorder, yorder, YES, xmin, xmax, ya, yb)
+ call dgsfit (ecf1, x, Memd[y1], r, w, npts, WTS_USER, err)
+
+ if (err != OK) {
+ if (xorder > 2 || yorder > 2) {
+ call dgsfree (ecf)
+ xorder = max (2, xorder - 1)
+ yorder = max (2, yorder - 1)
+ goto fit_
+ }
+
+ switch (err) {
+ case SINGULAR:
+ call dgsfree (ecf)
+ ecf = ecf1
+ call eprintf ("Singular solution\n")
+ case NO_DEG_FREEDOM:
+ call sfree (sp)
+ call error (0, "No degrees of freedom")
+ }
+ }
+
+ call dgsvector (ecf1, x, Memd[y1], r, npts)
+ call adivd (r, Memd[y1], r, npts)
+ call asubd (z, r, r, npts)
+
+ newrms = ecf_rms (r, w, npts)
+ k = k + 1
+
+ if (newrms / rms < 0.999) {
+ call dgsfree (ecf)
+ ecf = ecf1
+ offset = i
+ rms = newrms
+ } else {
+ call dgsfree (ecf1)
+ if (k > 2)
+ break
+ i = offset
+ j = -j
+ }
+ }
+
+ call altmd (y, Memd[y1], npts, double(slope), double(offset))
+ call dgsvector (ecf, x, Memd[y1], r, npts)
+ call adivd (r, Memd[y1], r, npts)
+ call asubd (z, r, r, npts)
+
+ call sfree (sp)
+
+end
+
+
+# ECF_SOLVE1 -- Fit f(x, y+offset) = (y+offset)*z with offset fixed.
+
+procedure ecf_solve1 (ecf, x, y, z, w, r, npts)
+
+pointer ecf # GSURFIT pointer
+double x[npts] # X points
+double y[npts] # Y points
+double z[npts] # Z points
+double w[npts] # Weights
+double r[npts] # Residuals
+int npts # Number of points
+
+int err
+pointer sp, y1
+double ya, yb, ecf_rms()
+include "ecffit.com"
+define fit_ 99
+
+begin
+ call smark (sp)
+ call salloc (y1, npts, TY_DOUBLE)
+
+ call dgsfree (ecf)
+ shift = 0.
+
+ if (slope == 1) {
+ offset = max (offset, int(1. - ymin))
+ ya = offset + ymin
+ yb = offset + ymax
+ } else {
+ offset = max (offset, int(1. + ymax))
+ ya = offset - ymax
+ yb = offset - ymin
+ }
+
+ call altmd (y, Memd[y1], npts, double (slope), double (offset))
+ call amuld (Memd[y1], z, r, npts)
+
+fit_ call dgsinit (ecf, gstype, xorder, yorder, YES, xmin, xmax,
+ min (ya, yb), max (ya, yb))
+ call dgsfit (ecf, x, Memd[y1], r, w, npts, WTS_USER, err)
+
+ if (err != OK) {
+ if (xorder > 2 || yorder > 2) {
+ call dgsfree (ecf)
+ xorder = max (2, xorder - 1)
+ yorder = max (2, yorder - 1)
+ goto fit_
+ }
+
+ switch (err) {
+ case SINGULAR:
+ call eprintf ("Singular solution\n")
+ case NO_DEG_FREEDOM:
+ call sfree (sp)
+ call error (0, "No degrees of freedom")
+ }
+ }
+
+ call dgsvector (ecf, x, Memd[y1], r, npts)
+ call adivd (r, Memd[y1], r, npts)
+ call asubd (z, r, r, npts)
+ rms = ecf_rms (r, w, npts)
+
+ call sfree (sp)
+end
diff --git a/noao/onedspec/ecidentify/ecffit/ecftitle.x b/noao/onedspec/ecidentify/ecffit/ecftitle.x
new file mode 100644
index 00000000..3b754f31
--- /dev/null
+++ b/noao/onedspec/ecidentify/ecffit/ecftitle.x
@@ -0,0 +1,48 @@
+include <pkg/gtools.h>
+
+# ECF_TITLE -- Set the GTOOLS parameter string.
+
+procedure ecf_title (gt)
+
+pointer gt # GTOOLS pointer
+
+include "ecffit.com"
+
+begin
+ call sprintf (ecfstr, SZ_LINE,
+ "Function=%s, xorder=%d, yorder=%d, slope=%d, offset=%d, rms=%6g")
+ call pargstr (function)
+ call pargi (xorder)
+ call pargi (yorder)
+ call pargi (slope)
+ call pargi (offset)
+ call pargd (rms)
+ call gt_sets (gt, GTPARAMS, ecfstr)
+ call gt_sets (gt, GTTITLE, "Echelle Dispersion Function Fitting")
+
+ switch (xtype) {
+ case 'p':
+ call gt_sets (gt, GTXLABEL, "Pixel")
+ case 'o':
+ call gt_sets (gt, GTXLABEL, "Order")
+ case 'w':
+ call gt_sets (gt, GTXLABEL, "Wavelength")
+ case 'r':
+ call gt_sets (gt, GTXLABEL, "Residual")
+ case 'v':
+ call gt_sets (gt, GTXLABEL, "Velocity")
+ }
+
+ switch (ytype) {
+ case 'p':
+ call gt_sets (gt, GTYLABEL, "Pixel")
+ case 'o':
+ call gt_sets (gt, GTYLABEL, "Order")
+ case 'w':
+ call gt_sets (gt, GTYLABEL, "Wavelength")
+ case 'r':
+ call gt_sets (gt, GTYLABEL, "Residual")
+ case 'v':
+ call gt_sets (gt, GTYLABEL, "Velocity")
+ }
+end
diff --git a/noao/onedspec/ecidentify/ecffit/mkpkg b/noao/onedspec/ecidentify/ecffit/mkpkg
new file mode 100644
index 00000000..40324cb8
--- /dev/null
+++ b/noao/onedspec/ecidentify/ecffit/mkpkg
@@ -0,0 +1,21 @@
+# Echelle Dispersion Fitting Package
+
+$checkout libpkg.a ../../
+$update libpkg.a
+$checkin libpkg.a ../../
+$exit
+
+libpkg.a:
+ ecfcolon.x ecffit.com <error.h> <gset.h>
+ ecfeval.x ecffit.com
+ ecffit.x ecffit.com <error.h> <pkg/gtools.h>
+ ecfgdata.x ecffit.com <pkg/gtools.h>
+ ecfget.x ecffit.com
+ ecfgraph.x <gset.h> <mach.h> <pkg/gtools.h>
+ ecfnearest.x <gset.h> <mach.h> <pkg/gtools.h>
+ ecfreject.x ecffit.com <mach.h>
+ ecfrms.x
+ ecfset.x ecffit.com
+ ecfsolve.x ecffit.com <mach.h> <math/gsurfit.h>
+ ecftitle.x ecffit.com <pkg/gtools.h>
+ ;