aboutsummaryrefslogtreecommitdiff
path: root/noao/twodspec/apextract
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/twodspec/apextract
downloadiraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz
Initial commit
Diffstat (limited to 'noao/twodspec/apextract')
-rw-r--r--noao/twodspec/apextract/Revisions1558
-rw-r--r--noao/twodspec/apextract/apall.par96
-rw-r--r--noao/twodspec/apextract/apall1.par117
-rw-r--r--noao/twodspec/apextract/apalloc.x34
-rw-r--r--noao/twodspec/apextract/apanswer.x121
-rw-r--r--noao/twodspec/apextract/apcenter.x26
-rw-r--r--noao/twodspec/apextract/apcolon.x384
-rw-r--r--noao/twodspec/apextract/apcopy.x28
-rw-r--r--noao/twodspec/apextract/apcveval.x19
-rw-r--r--noao/twodspec/apextract/apcvset.x47
-rw-r--r--noao/twodspec/apextract/apdb.x314
-rw-r--r--noao/twodspec/apextract/apdebug.par156
-rw-r--r--noao/twodspec/apextract/apdefault.par14
-rw-r--r--noao/twodspec/apextract/apdefault.x42
-rw-r--r--noao/twodspec/apextract/apdelete.x23
-rw-r--r--noao/twodspec/apextract/apdemos/apdemo1.cl14
-rw-r--r--noao/twodspec/apextract/apdemos/apdemo1.dat14
-rw-r--r--noao/twodspec/apextract/apdemos/apdemos.cl17
-rw-r--r--noao/twodspec/apextract/apdemos/apdemos.men3
-rw-r--r--noao/twodspec/apextract/apdemos/apdemosdb/aplast111
-rw-r--r--noao/twodspec/apextract/apedit.key74
-rw-r--r--noao/twodspec/apextract/apedit.par17
-rw-r--r--noao/twodspec/apextract/apedit.x604
-rw-r--r--noao/twodspec/apextract/apertures.h32
-rw-r--r--noao/twodspec/apextract/apextract.cl33
-rw-r--r--noao/twodspec/apextract/apextract.hd27
-rw-r--r--noao/twodspec/apextract/apextract.men23
-rw-r--r--noao/twodspec/apextract/apextract.par8
-rw-r--r--noao/twodspec/apextract/apextract.x1834
-rw-r--r--noao/twodspec/apextract/apfind.par18
-rw-r--r--noao/twodspec/apextract/apfind.x132
-rw-r--r--noao/twodspec/apextract/apfindnew.x83
-rw-r--r--noao/twodspec/apextract/apfit.par30
-rw-r--r--noao/twodspec/apextract/apfit.x737
-rw-r--r--noao/twodspec/apextract/apfit1.par118
-rw-r--r--noao/twodspec/apextract/apflat1.par117
-rw-r--r--noao/twodspec/apextract/apflatten.par37
-rw-r--r--noao/twodspec/apextract/apgetdata.x99
-rw-r--r--noao/twodspec/apextract/apgetim.x73
-rw-r--r--noao/twodspec/apextract/apgmark.x126
-rw-r--r--noao/twodspec/apextract/apgraph.x145
-rw-r--r--noao/twodspec/apextract/apgscur.x28
-rw-r--r--noao/twodspec/apextract/apicset.x84
-rw-r--r--noao/twodspec/apextract/apids.x401
-rw-r--r--noao/twodspec/apextract/apimmap.x48
-rw-r--r--noao/twodspec/apextract/apinfo.x96
-rw-r--r--noao/twodspec/apextract/apio.x144
-rw-r--r--noao/twodspec/apextract/apmask.par19
-rw-r--r--noao/twodspec/apextract/apmask.x155
-rw-r--r--noao/twodspec/apextract/apmw.x280
-rw-r--r--noao/twodspec/apextract/apnearest.x75
-rw-r--r--noao/twodspec/apextract/apnoise.key14
-rw-r--r--noao/twodspec/apextract/apnoise.par30
-rw-r--r--noao/twodspec/apextract/apnoise.x256
-rw-r--r--noao/twodspec/apextract/apnoise1.par118
-rw-r--r--noao/twodspec/apextract/apnorm1.par118
-rw-r--r--noao/twodspec/apextract/apnormalize.par41
-rw-r--r--noao/twodspec/apextract/apparams.dat68
-rw-r--r--noao/twodspec/apextract/apparams.h92
-rw-r--r--noao/twodspec/apextract/apparams.par117
-rw-r--r--noao/twodspec/apextract/apparams.x95
-rw-r--r--noao/twodspec/apextract/appars.x261
-rw-r--r--noao/twodspec/apextract/apprint.x34
-rw-r--r--noao/twodspec/apextract/approfile.x765
-rw-r--r--noao/twodspec/apextract/aprecenter.par17
-rw-r--r--noao/twodspec/apextract/aprecenter.x166
-rw-r--r--noao/twodspec/apextract/apresize.par21
-rw-r--r--noao/twodspec/apextract/apresize.x142
-rw-r--r--noao/twodspec/apextract/apscat1.par11
-rw-r--r--noao/twodspec/apextract/apscat2.par10
-rw-r--r--noao/twodspec/apextract/apscatter.par25
-rw-r--r--noao/twodspec/apextract/apscatter.x662
-rw-r--r--noao/twodspec/apextract/apselect.x40
-rw-r--r--noao/twodspec/apextract/apshow.x46
-rw-r--r--noao/twodspec/apextract/apskyeval.x368
-rw-r--r--noao/twodspec/apextract/apsort.x55
-rw-r--r--noao/twodspec/apextract/apsum.par34
-rw-r--r--noao/twodspec/apextract/aptrace.par27
-rw-r--r--noao/twodspec/apextract/aptrace.x669
-rw-r--r--noao/twodspec/apextract/apupdate.x44
-rw-r--r--noao/twodspec/apextract/apvalues.x32
-rw-r--r--noao/twodspec/apextract/apvariance.x420
-rw-r--r--noao/twodspec/apextract/apwidth.cl59
-rw-r--r--noao/twodspec/apextract/apylevel.x103
-rw-r--r--noao/twodspec/apextract/doc/apall.hlp557
-rw-r--r--noao/twodspec/apextract/doc/apbackground.hlp79
-rw-r--r--noao/twodspec/apextract/doc/apdefault.hlp95
-rw-r--r--noao/twodspec/apextract/doc/apedit.hlp374
-rw-r--r--noao/twodspec/apextract/doc/apextract.hlp365
-rw-r--r--noao/twodspec/apextract/doc/apextractsys.hlp415
-rw-r--r--noao/twodspec/apextract/doc/apextras.hlp61
-rw-r--r--noao/twodspec/apextract/doc/apfind.hlp180
-rw-r--r--noao/twodspec/apextract/doc/apfit.hlp263
-rw-r--r--noao/twodspec/apextract/doc/apflatten.hlp304
-rw-r--r--noao/twodspec/apextract/doc/apmask.hlp123
-rw-r--r--noao/twodspec/apextract/doc/apnoise.hlp231
-rw-r--r--noao/twodspec/apextract/doc/apnormalize.hlp324
-rw-r--r--noao/twodspec/apextract/doc/approfiles.hlp131
-rw-r--r--noao/twodspec/apextract/doc/aprecenter.hlp148
-rw-r--r--noao/twodspec/apextract/doc/apresize.hlp201
-rw-r--r--noao/twodspec/apextract/doc/apscatter.hlp253
-rw-r--r--noao/twodspec/apextract/doc/apsum.hlp402
-rw-r--r--noao/twodspec/apextract/doc/aptrace.hlp354
-rw-r--r--noao/twodspec/apextract/doc/apvariance.hlp159
-rw-r--r--noao/twodspec/apextract/doc/dictionary282
-rw-r--r--noao/twodspec/apextract/doc/old/Tutorial.hlp278
-rw-r--r--noao/twodspec/apextract/doc/old/apextract.ms725
-rw-r--r--noao/twodspec/apextract/doc/old/apextract1.ms811
-rw-r--r--noao/twodspec/apextract/doc/old/apextract2.ms14
-rw-r--r--noao/twodspec/apextract/doc/revisions.v3.ms522
-rw-r--r--noao/twodspec/apextract/mkpkg76
-rw-r--r--noao/twodspec/apextract/peaks.x313
-rw-r--r--noao/twodspec/apextract/t_apall.x576
-rw-r--r--noao/twodspec/apextract/x_apextract.x15
114 files changed, 22426 insertions, 0 deletions
diff --git a/noao/twodspec/apextract/Revisions b/noao/twodspec/apextract/Revisions
new file mode 100644
index 00000000..3ffe9058
--- /dev/null
+++ b/noao/twodspec/apextract/Revisions
@@ -0,0 +1,1558 @@
+.help revisions Jun88 noao.twodspec.apextract
+.nf
+
+approfile.x
+ When an aperture goes off the edge of an image there was an error
+ which allowed the imio data buffer from the image to go out of bounds.
+ (3/12/13, MJF)
+
+aptrace.x
+ The line1/line2 variables weren't being initialized to zero in the
+ ap_ctrace() procedure. This woule lead to old values from a previous
+ run of the task being reused. (2/6/13, MJF)
+
+=======
+V2.16.1
+=======
+
+approfile.x
+ Fixed a bug in the Marsh algorithm causing segfaults on 64-bit
+ platforms (Buglog 583) (3/5/12, Valdes)
+
+apall.par
+ Changed the default for maxsep from 1000 to 100000. This is because
+ the default is when the user doesn't want to skip apertures and it is
+ strange when the id jumps in the (rare) case that two apertures are
+ marked with a separation of more than 1000. (2/17/09, Valdes)
+
+apedit.x
+ The 's' key now works on the current aperture rather than the nearest.
+ (10/7/08, Valdes)
+
+apcolon.x
+ The "all" mode was missing with :center. (10/7/08, Valdes)
+
+apall1.par
+apfit1.par
+apnoise1.par
+apnorm1.par
+apscat1.par
+apparams.dat
+ When the apertures parameter was added in 1996 the :apertures and
+ :parameters commands were broken because of missing references in
+ the associated hidden psets. (10/7/08, Valdes)
+
+=======
+V2.14.1
+=======
+
+========
+V2.12.2a
+========
+
+apextract.x
+ When using APFIT to output the difference the IMIO buffer which was
+ assumed to be static was invalidated because of I/O needed to create
+ the difference. A special case was added to handle this case.
+ (7/7/04, Valdes)
+
+apcveval.x +
+apedit.x
+apextract.x
+apfind.x
+apfindnew.x
+apfit.x
+apgmark.x
+apgscur.x
+apmask.x
+apnoise.x
+apprint.x
+approfile.x
+aprecenter.x
+apresize.x
+apskyeval.x
+apupdate.x
+apvalues.x
+apvariance.x
+apnearest.x
+apscatter.x
+aptrace.x
+mkpkg
+ Added an interface routine to CVEVAL to avoid calling it with
+ independent variables outside the range of the fit. The fit range
+ may be short because of tracing problems. So the profile shift
+ is now extended from the end points of the fitted range.
+ (5/21/04, Valdes)
+
+apupdate.x
+apdefault.x
+apfind.x
+aptrace.x
+apedit.x
+apcolon.x
+ Modified to check for inappropriate INDEF values in the "lower"
+ and "upper" aperture settings. (3/26/04, Valdes)
+
+=======
+V2.12.2
+=======
+
+apextract.x
+ The edge weighting interpolation buffer space, interpbuf, was
+ increased by one pixel. This makes the data buffer wider so that
+ interpolation avoids using boundary extension except in cases where the
+ aperture actually approaches the image edge. Note that this change
+ results in an improvement in the extracted spectra over the previous
+ release where wraparound boundary extension was used. This also means
+ extractions will not be identical between the versions.
+ (1/23/04, Valdes)
+
+apextract.x
+ The new routine ap_asifit was not correct. (1/22/04, Valdes)
+
+apextract.x
+approfile.x
+apvariance.x
+ A problem related to the change of 10/21/03 is when the trace goes
+ far outside the data buffer. This could result in the number of points
+ specified for asifit being too small for the interpolation function.
+ An interface routine, ap_asifit, was added to do all the checks related
+ to using asifit for evaluating the edge pixels. (12/10/03, Valdes)
+
+===========
+V2.12.2BETA
+===========
+
+apextract.x
+ The output name based on the input name for multiextension images
+ produces a multiextension output with the same extension description.
+ (12/3/03, Valdes)
+
+apgetim.x
+ 1. Restored ability to use image sections which was lost in the change
+ on 7/13/98 for V2.11.2.
+ 2. Support for multiextension data was added. This consists of using
+ a standard name based on EXTNAME and EXTVER and without the
+ file type extension. Note that this means that image names specified
+ by index will be converted to extension name and extension version.
+ (12/3/03, Valdes)
+
+apextract.x
+approfile.x
+apvariance.x
+ The call to asifit was specifying too many points to fit, a whole line
+ in the data buffer, because the data vector may be offset from the first
+ column of the data buffer. This could cause a segmentation violation.
+ (10/21/03, Valdes)
+
+
+apwidth.cl
+ Script to compute aperture widths from database. This was written
+ for a user and is saved here though it is not currently defined by
+ default. (12/2/02, Valdes)
+
+apflat1.par
+ The indirect reference needs to be spelled out without abbreviation to
+ be "apflatten" instead of "apflat". (11/18/02, Valdes)
+
+=======
+V2.12.1
+=======
+
+apextract.x
+approfile.x
+apvariance.x
+ Modified to handle edge pixels by interpolation. (6/19/02, Valdes)
+
+=====
+V2.12
+=====
+
+apgraph.x
+apgmark.x
+ When there is just one aperture the background regions are marked
+ in apedit and in plotfile output. (9/21/01, Valdes)
+
+doc/apall.hlp
+ The help page was indicating the extra information output was the
+ variance rather than the sigma. (8/19/00, Valdes)
+
+apextract.x
+ The checking for the maximum number of apertures that fit in the allocated
+ memory (the "do j = i, napsex" loop) was incorrect because i was used
+ instead of the loop index j. (3/20/00, Valdes)
+
+=========
+V2.11.3p1
+=========
+=======
+V2.11.3
+=======
+
+approfile.x
+ In the previous change to the weights in the Horne algorithm
+ the behavior when all data is rejected (say because the background
+ is set wrong and all data is below the background) the weights
+ would be set to MAX_REAL/10 which would cause CVFIT to fail.
+ (3/13/00, Valdes)
+
+apall1.par
+apdebug.par
+apfit1.par
+apnoise1.par
+apnorm1.par
+apparams.par
+ Reduced the polysep parameter. (1/26/00, Valdes)
+
+apextractbak.x -
+mkpkg
+ Removed this second old copy which was accidentally introduced into
+ mkpkg as well resulting in multiple copies of the same procedures
+ in the library in V2.11.3beta. (12/9/99, Valdes)
+
+doc/apflatten.hlp
+ Removed extraneous parameters not actually in task parameter set.
+ (10/21/99, Valdes)
+
+mkpkg
+ Added missing dependencies. (10/11/99, Valdes)
+
+=======
+V2.11.2
+=======
+
+apextract.x
+ Added a keyword SUBAP when using echelle output with subapertures.
+ (3/26/99, Valdes)
+
+apflatten.par
+apflat1.par
+ Removed background subtraction as an option. (12/11/98, Valdes)
+
+apskyeval.x
+ If the background sample region does not have explicit regions then
+ the xmin/xmax region is used for the background. (12/11/98, Valdes)
+
+apfit.x
+ Added errchk for ic_fit and ic_gfit. (12/8/98, Valdes)
+
+apflat1.par
+ Reduced the polysep because it can go wrong. (12/8/98, Valdes)
+
+apextract.x
+ Added check to fix cases with the lower and upper aperture limits
+ are reversed.
+ (7/13/98, Valdes)
+
+apgetim.x
+ Changed to call xtools routine that strips extensions.
+ (7/13/98, Valdes)
+
+approfile.x
+ In the Horne algorithm the weights for rejected points were set to zero
+ to eliminate them from the fit. But if large regions are rejected
+ this leaves the fit unconstrained and can lead to bad results. A
+ change was made to set the weights for the rejected points to 1/10
+ of the minimum weight for the good data.
+ (2/6/98, Valdes)
+
+apextract.x
+ For "echelle" format with "extras" the header was not setup properly
+ resulting in WCSDIM=2 instead of 3. (2/6/98, Valdes)
+
+apids.x
+ 1. Fix bug in IDS structure which pointed outside of allocated memory.
+ 2. Variables ra/dec in ap_gids were being used both as pointers and
+ double. The ra/dec pointer usage was removed.
+ 3. The realloc step at the end of ap_gids had the wrong check so it
+ would never be done.
+ (1/13/98, Valdes)
+
+=======
+V2.11.1
+=======
+=====
+V2.11
+=====
+
+doc/apsum.hlp
+doc/apsum.hlp
+ Added missing task name in revisions section. (4/22/97, Valdes)
+
+apextract.x
+ Removed calls to impl from inside amove in order to error check them.
+ (1/24/97, Valdes)
+
+t_apall.x
+ 1. Added errchk for ap_dbwrite.
+ 2. Made writing the aplast file optional.
+ 3. It is a warning if the plot file can't be written.
+ (1/24/97, Valdes)
+
+apextract.x
+ The step where the data is multplied by the gain was multiplying
+ outside the data if dispaxis=1. If the there are enough apertures
+ and the aperture widths decrease then it is possible to get
+ mulitplications of gain**naps which can cause a floating overflow.
+ This was fixed. (11/12/96, Valdes)
+
+apertures.h
+t_apall.x
+aptrace.x
+apresize.x
+apalloc.x
+apextract.x
+apselect.x
+aprecenter.x
+apall.par
+apall1.par
+apfit1.par
+apflat1.par
+apnorm1.par
+apparams.par
+apnoise1.par
+apdebug.par
+apfit.par
+apflatten.par
+apmask.par
+apnoise.par
+apnormalize.par
+apresize.par
+apscatter.par
+apsum.par
+aptrace.par
+apedit.par
+apfind.par
+aprecenter.par
+mkpkg
+doc/apextract.hlp
+doc/apextras.hlp
+doc/apedit.hlp
+doc/apall.hlp
+doc/apfind.hlp
+doc/apresize.hlp
+doc/apsum.hlp
+doc/aptrace.hlp
+doc/apfit.hlp
+doc/apflatten.hlp
+doc/apmask.hlp
+doc/apnoise.hlp
+doc/apnormalize.hlp
+doc/aprecenter.hlp
+doc/apscatter.hlp
+ Added a new parameter "apertures" to select a subset of the apertures
+ to resize, recenter, trace, extract, etc. The parameter "apertures"
+ which applied to the recentering was changed to "aprecenter".
+ (9/5/96, Valdes)
+
+apedit.key
+ Alphabetized the summary command lists. (9/3/96, Valdes)
+
+apextract.x
+ 1. Onedspec output format is now allowed when nsubaps is greater than 1.
+ 2. Echelle format outputs all orders for a each subapertures in
+ separate files.
+ (4/3/96, Valdes)
+
+apmw.x
+apextract.x
+ The WCS for strip extraction was wrong. (1/31/96, Valdes)
+
+apmw.x
+ An error in computing the WCS transformation now prints a more informative
+ message indicating the final extracted spectrum will be in pixel units.
+ (1/4/96, Valdes)
+
+apids.x
+apedit.x
+ Changed the behavior of the 'i' and 'o' keys with regard to the beam
+ numbers. These keys will now assign a beam number from the apid table
+ for the selected aperture as well as all other apertures. Previously
+ the beam number was not changed which resulted in a new aperture
+ number with a beam number that did not agree with the apid table.
+ (10/27/95, Valdes)
+
+doc/apextras.hlp +
+apextract.men
+apextract.hd
+ Added a help topic on the "extras" information. (9/5/95, Valdes)
+
+apimmap.x
+ If the image header dispersion axis is unreasonable a warning is
+ printed and the "dispaxis" parameter is used instead. (8/2/95, Valdes)
+
+apids.x
+apmw.x
+doc/apall.hlp
+doc/apdefault.hlp
+doc/apedit.hlp
+doc/apfind.hlp
+ Modified to allow aperture ID table to be from an image header
+ under the keywords SLFIBnnn. The extracted image will have
+ these keywords deleted. (7/25/95, Valdes)
+
+=======
+V2.10.4
+=======
+
+apscatter.x
+ When not smoothing along the dispersion there was a bug that when
+ the number of points being fit across the disperision changed
+ ICFIT was not reset causing an error "Range descriptor undefined".
+ The routine now reset the "new" flag when the number of points
+ changes. (5/3/95, Valdes)
+
+t_apall.x
+ Using the same input and output image name in APSCATTER was still
+ not right. (2/24/95, Valdes)
+
+apscatter.x
+ Made the output image datatype be at least real. (2/23/95, Valdes)
+
+apextract.x
+ For normalization the weights were not forced causing the gain to
+ default to 0. The change of 12/31/94 also fixed this by setting the
+ gain to 1. The file was touched but not changed. (1/27/95, Valdes)
+
+apextract.x
+apskyeval.x
+ Made the query for the readnoise only occur if needed. Previously
+ the query was made in the sky step even if the sky error estimate
+ was not needed. (12/31/94, Valdes)
+
+apedit.x
+ Needed to set clobber and review options so they are queried during
+ interactive extraction. (10/28/94, Valdes)
+
+apimmap.x
+apgetim.x
+apgetdata.x
+apextract.x
+apmw.x
+ 1. If a 3D image is given then a warning is printed and the first plane
+ is used and the other planes are ignored.
+ 2. Various fixes to allow image sections to be used.
+ (10/12/94, Valdes)
+
+aptrace.x
+ An uninitialized memory problem was fixed. (9/19/94, Valdes/Zarate)
+
+apicset.x
+ Fixed type mismatch in min/max function calls. (6/13/94, Valdes/Zarate)
+
+apextract.x
+ Changed BANDID name for raw spectrum to "raw". (5/3/94, Valdes)
+
+apvariance.x
+doc/apvariance.hlp
+doc/apall.hlp
+doc/apsum.hlp
+ The correction to bring the weighted and unweighted total fluxes to the
+ same value (called the bias factor) can produce odd values in special
+ cases; such as slitlets where only part of the image contains real
+ spectrum. This could result in variance spectra with flux scaling
+ errors to the extreme of a negative (inverted) spectrum. The bias
+ factor is now logged. If the two total fluxes differ by more than a
+ factor of 2 a warning (which always appears on the standard output) is
+ given with the fluxes and the bias factor. If the bias factor is
+ negative a warning is given and the bias factor is ignored.
+ (5/1/94, Valdes)
+
+doc/aptrace.hlp
+ Fixed typo in description of Legendre basis functions. (4/1/94, Valdes)
+
+apextract.x
+doc/apextract.hlp
+ Added output BANDID keywords to document the various output data.
+ (2/4/94, Valdes)
+
+apnoise.x +
+apnoise1.par +
+apnoise.par +
+apnoise.key +
+doc/apnoise.hlp +
+apextract.x
+t_apall.x
+x_apextract.x
+apextract.hd
+apextract.men
+apextract.cl
+mkpkg
+ A new task for computing the noise sigma as a function of data value
+ was added. This allows checking the noise model parameter and
+ can be used as a diagnostic of the profile modeling. (8/28/93, Valdes)
+
+apfit.x
+apextract.x
+ There were some additional problems with gain parameter dependencies
+ in the difference, fit, and normalization output functions.
+ (8/27/93, Valdes)
+
+apgetdata.x
+aptrace.x
+apedit.par
+apfind.par
+apfit.par
+apflatten.par
+apmask.par
+apnormalize.par
+aprecenter.par
+apresize.par
+apscatter.par
+apsum.par
+aptrace.par
+apall.par
+apall.hlp
+apedit.hlp
+apfind.hlp
+apflatten.hlp
+apmask.hlp
+apfit.hlp
+apnormalize.hlp
+aprecenter.hlp
+apresize.hlp
+apscatter.hlp
+apsum.hlp
+aptrace.hlp
+ The nsum parameter may be negative to select a median rather than
+ a sum of lines/columns. The parameter files had to be modified to
+ remove the minimum range limit and the help files modified to
+ document the new option. (8/10/93, Valdes)
+
+===========
+V2.10.3beta
+===========
+
+doc/apall.hlp
+doc/apsum.hlp
+ The format parameter description was added. (6/24/93, Valdes)
+
+apfind.x
+apfindnew.x
+ Removed the threshold in peak finding requiring peaks to be above zero.
+ This works with the change to center1d to allow finding of apertures
+ when the data is negative. (5/5/93, Valdes)
+
+apfit.x
+ Added CCDMEAN=1. to output image in the normalization, flattening routines.
+ (4/16/93, Valdes)
+
+apextract.par
+*.par
+apgetim.x
+ Moved the "dispaxis" parameter to a package paraemter.
+ (3/8/93, Valdes)
+
+approfile.x
+ The profile was not cleared when saturated pixels are found. This
+ could cause NaNs to get into the data with the result that
+ cvfit could produce garbage.
+ (3/4/93, Valdes)
+
+debug.par
+apparams.par
+apnorm1.par
+apflat1.par
+apfit1.par
+apall1.par
+ 1. Changed the default "fit2d" polynomial parameters to polyorder=10,
+ polysep=0.95.
+ 2. Changed the default "niterate" from 2 to 5.
+ (3/3/93, Valdes)
+
+approfile.x
+doc/approfiles.hlp
+ For the "fit1d" algorithm I doubled the order it uses to fit
+ parallel to the disperison. The order is still computed based
+ on the tilt of the spectrum and the order used for the tracing
+ but now that number is doubled. (2/26/93, Valdes)
+
+apscatter.x
+ Revised the algorithm to keep the cross-dispersion fits in memory
+ rather than writing them to disk as an image. This speeds things
+ up in the case of slow I/O. (2/23/93, Valdes)
+
+t_apall.x
+apscatter.x
+ 1. The temporary file name was not being passed to apscatter by
+ t_apall resulting in use of the name ".imh" which is hidden.
+ 2. Increased the column buffering size from 512*100 to 500000.
+ (2/5/93, Valdes)
+
+apextract.x
+ imaccf was being used as a boolean when it should be an int.
+ (12/13/92, Valdes)
+
+debug.par
+ A DPAR parameter file for use with debugging. (1/12/92, Valdes)
+
+apmw.x
+apextract.x
+ Rewrote this to allow extractions of an arbitrary number of apertures.
+ Previously this was limited by MWCS. The output format is now
+ EQUISPEC. (1/12/92, Valdes)
+
+aprecenter.x
+ This routine was incorrectly selecting the apertures to be used.
+ is_in_range (Memi[ranges], i) --> is_in_range (Memi[ranges], AP_ID(aps[i]))
+ (1/8/93, Valdes and Hill)
+
+doc/apbackground.hlp
+ In responding to a concern about the 'b' key showing a fit even though
+ the background type was "median" I added a paragraph explaining this.
+ (1/8/93, Valdes)
+
+t_apall.x
+ The dispersion smoothing was turned off in noninteractive mode regardless
+ of the task parameter. This has been fixed.
+ (12/8/92, Valdes)
+
+t_apall.x
+ Added error check for ap_plot.
+ (10/14/92, Valdes)
+
+apextract.x
+ 1. When the dispersion axis is 1 the data buffer may contain garbage
+ because of using a malloc and because not all of this buffer is
+ necessarily used. Later the multiplication by the gain can cause
+ an arithmetic exception. The mallocs were replaced by callocs.
+ 2. Added errchks for the impl[123]r routines.
+ (9/10/92, Valdes)
+
+mkpkg
+apextract.x
+apmw.x +
+ 1. Separated out the MWCS routines into another file.
+ 2. Added an apmw_saveim procedure to produce simple 1D format as is done
+ in the ONEDSPEC package.
+ (8/24/92, Valdes)
+
+apskyeval.x
+ When doing the fitted background variable roundoff among machines led
+ to using different background points and, hence, gave noticibly different
+ results. The background points are now rounded to the nearest 1000th of
+ a pixel which will produce the same background points on all machines.
+ (8/19/92, Valdes)
+
+apnorm1.x
+ Added missing t_nlost parameter. (8/10/92, Valdes)
+
+aptrace.x
+ There was an incorrect order in checking for failed traces which ends
+ up referencing uninitialized memory. This bug has been there for a
+ long time (V2.8-V2.10) but only showed up during testing on the
+ SGI port. (7/31/92, Valdes)
+
+The following set of changes concern the treatment of the background sample
+regions and min/max fitting limits. There was also a change in ICFIT
+to check the min/max fitting limits and increase them if the sample region
+is extended beyond the initial fitting limits.
+
+--------
+
+apdefault.x
+ Now calls AP_ICSET with the image limits rather than the aperture
+ limits as required by the change to that routine. (7/30/92, Valdes)
+
+apedit.x
+ 1. The default aperture is reset after a colon command just in case
+ one of the default aperture parameters has changed. This is
+ slightly inefficient but the alternative is a more complex
+ AP_COLON to determine if a parameter relates to the default
+ aperture.
+ 2. Now calls AP_ICSET after fitting to apply the constraint that the
+ fitting limits pass under the aperture. (7/30/92, Valdes)
+
+apicset.x
+ 1. The input background limits for a new aperture (called
+ by AP_DEFAULT) are now the maximum limits defined by the image size
+ rather than the minimum limits defined by the aperture.
+ 2. If a null default sample is given it is mapped to "*".
+ 3. A sample with "*" will map to the maximum limits.
+ 4. Allow the input and output pointers to be the same in order
+ for the constraint that the fitting region pass under the
+ aperture can be applied. (7/30/92, Valdes)
+
+--------
+
+doc/apall.hlp doc/apsum.hlp doc/apbackground.hlp
+ The documentation of the "median" and "minimum" options for the
+ background parameter needed to be added. (7/14/92, Valdes)
+
+apextract.x
+ The profile array needed to be corrected for the gain. This makes a
+ difference for the output formats that use the fitted profile
+ (tasks APFLATTEN, APFIT: formats fit, ratio, diff, flat).
+ (7/9/92, Valdes)
+
+apfit1.par
+ Was missing t_nlost. (7/9/92, Valdes)
+
+apparams.par
+apnorm1.par
+apflat1.par
+apfit1.par
+apall1.par
+ Replace prompt pfiT with pfit as it should be. (7/9/92, Valdes)
+
+=======
+V2.10.2
+=======
+
+apextract.x
+ The WCS for the 3D images was changed to produce a WCSDIM of 3.
+ (6/30/92, Valdes)
+
+=======
+V2.10.1
+=======
+
+=======
+V2.10.0
+=======
+
+apextract.x
+ 1. The axis array which was set by a data statement was actually
+ modified in the routine causing an improper WCS type to be
+ set.
+ 2. If no coordinate label and/or units are found they are now set based
+ on DC-FLAG. Before calibrated long slit spectra ended up with the
+ right wavelength coordinates but a label of Pixel and no units.
+ (5/20/92, Valdes)
+
+apall1.par
+apparams.par
+apfit1.par
+apflat1.par
+apnorm1.par
+ The e_profile prompt contained a new line. This was removed.
+ (5/18/92, Valdes)
+
+doc/apexv210.ms +
+doc/revisions.v3.ms -
+ Revisions summary document. (5/11/92, Valdes)
+
+apcolon.x
+apedit.key
+doc/apedit.hlp
+ Added t_nlost to the list of colon commands. (5/11/92, Valdes)
+
+apgetim.x
+ Added the qp and pl extensions to those stripped. (5/8/92, Valdes)
+
+apextract.x
+ Added error checking such that if there is a problem with reading the
+ input image WCS and warning is printed and pixel coordinates are set
+ in the output image. (5/8/92, Valdes)
+
+=====
+V2.10
+=====
+
+apextract.x
+ For a single aperture using MULTISPEC WCS a dummy axis mapping was added
+ to make the image appear to be the first line of a parent 2D image.
+ (4/27/92, Valdes)
+
+approfile.x
+ Added a maximum order for the aphorne fitting function. (4/24/92, Valdes)
+
+apextract.x
+ Added a error check trap to clean up and free memory in case of an
+ error. (4/24/92, Valdes)
+
+t_apall.x
+apdb.x
+apedit.x
+apcolon.x
+apfind.x
+apfindnew.x
+apertures.h
+ Made the number of apertures dynamic. There is no longer a maximum
+ number of apertures allowed. (3/18/92, Valdes)
+
+t_apall.x
+ Length of format string declared as SZ_FNAME but used as SZ_LINE.
+ Change declaration to SZ_LINE. (3/12/92, MJF)
+
+apextract.x
+ Now the output extension is added only if the output name is the
+ same as the input name. Thus, if someone used <image>.ms as an
+ output name they won't get <image>.ms.ms. (2/12/92, Valdes)
+
+apvariance.x
+apskyeval.x
+approfile.x
+apextract.x
+appars.x
+ Trapped errors from getting the read noise and gain from the image header
+ to produce a meaningful warning message. (2/10/92, Valdes)
+
+apedit.x
+apfind.x
+t_apall.x
+apids.x
+ 1. Added code to ignore negative beam numbers during extraction.
+ 2. Negative beam numbers are only generated if an explicit assignment
+ is made in the aperture id table or with 'j'; i.e. beam numbers
+ generated by adding or subtracting will not have a negative beam.
+ (2/10/92, Valdes)
+
+apids.x
+apedit.x
+ Modified to not allow apertures numbers < 1. (1/22/92, Valdes)
+
+t_apall.x
+x_apextract.x
+ Added new entry point, apslitproc, for the slit processing tasks.
+ (1/15/92, Valdes)
+
+apfind.x
+apall.par
+apfind.par
+ If nfind < 0 then the specified number of evenly spaced apertures are
+ defined. (1/14/92, Valdes)
+
+apextract.x
+apsum.par
+apnormalize.par
+apflatten.par
+apfit.par
+apall.par
+apparams.par
+apnorm1.par
+apflat1.par
+apfit1.par
+apall1.par
+doc/apsum.hlp
+doc/approfiles.hlp
+doc/apnormalize.hlp
+doc/apflatten.hlp
+doc/apfit.hlp
+doc/apall.hlp
+ 1. Replaced the "maxtilt" criteria for choosing the profile fitting
+ algorithm with an explicit "pfit" parameter.
+ 2. The parameter files were modified to remove "maxtilt", add
+ "pfit", and change the default "polyorder" parameter for the
+ fit2d algorithm from 4 to 6.
+ 3. The "pfit" parameter is redirected from the hidden parameter files
+ to the user parameter files allowing the users to select the profile
+ fitting algorithm.
+ (1/8/92, Valdes)
+
+t_apall.x
+apdb.x
+ 1. Added special strings for the reference parameter. If the reference
+ parameter is "OLD" then only input images with existing database
+ entries are processed. If the reference is "NEW" then only input
+ images without existing databse entries are processed.
+ 2. Added a new procedure, ap_dbaccess, to simply check for the presence
+ of a database file. This is used for the above change.
+ (1/2/92, Valdes)
+
+aptrace.x
+apall.par
+aptrace.par
+apparams.par
+apall1.par
+doc/apall.hlp
+doc/aptrace.hlp
+ A new parameter has been added to set the number of steps which may
+ be lost during tracing. (9/5/91, Valdes)
+
+apextract.x
+ Changed ap_setdisp to ap_wcs. This routine uses MWCS and sets the
+ WCS to multispec. (8/29/91, Valdes)
+
+apextract.x
+ Modified so that profile image is used in place of input image for
+ determining the profile and eliminated the use of a disk profile file.
+ This is inefficient if the same profile image is used for many input
+ images but it is much easier for the user to understand.
+ (8/27/91, Valdes)
+
+apvariance.x
+ The subaperture extraction did not work because of a typo.
+ (8/27/91, Valdes)
+
+apextract.x
+ The profile image capability had several bugs which were fixed.
+ (8/27/91, Valdes)
+
+approfile.x
+ Fixed another division by zero problem in ap_horne. (8/27/91, Valdes)
+
+approfile.x
+ Failed to clear profile in the case the spectrum was negative.
+ (5/30/91, Valdes)
+
+apertures.h
+ Increased the maximum number of aperture from 100 to 1000.
+ (4/29/91, Valdes)
+
+apdefault.x
+apicset.x
+ The default aperture was setting the background fitting range to
+ the full image range rather than range covered by the sample region.
+ This could cause singular solution errors in some cases.
+ (3/27/91, Valdes)
+
+apfind.x
+ Allowed still finding the specified number if some apertures (up to
+ 2) fail for some reason such as too near the edge. This is done by
+ setting the number of candidates to nfind+2. (3/26/91, Valdes)
+
+aprecenter.x
+doc/aprecenter.hlp
+ When using the shift option the shift is now the median (including
+ averaging of central 2 shifts for even number of peaks) instead of
+ the average. (3/26/91, Valdes)
+
+appars.x
+apall1.par
+apfit1.par
+apflat1.par
+apnorm1.par
+apparams.par
+ In order to allow writing to redirected parameters rather than overwrite
+ the redirection string a kluge was added using the prompt string.
+ The apput procedures check the prompt string for the first character
+ ">" and if present write to the parameter given in the rest of the
+ string. All the hidden parameter files with redirected parameters
+ had to be changes. (3/26/91, Valdes)
+
+apextract.par
+apall.par apall1.par
+apsum.par apdefault.par apparams.par
+apfit.par apfit1.par
+apflatten.par apflatten1.par
+apnormalize.par apnorm1.par
+ 1. Moved format parameter from package parameters to
+ APALL and APSUM.
+ 2. Moved dispaxis parameter from package parameters to APDEFAULT.
+ 3. Added new background types.
+ (3/21/91, Valdes)
+
+t_apall.x
+ Allow scattered light correction to be run by APSCRIPT.
+ (3/21/91, Valdes)
+
+apscatter.x
+ Moved CLIO call for anssmooth out of loop to a single call using a
+ procedure variable.
+ (3/21/91, Valdes)
+
+apextract.x
+apskyeval.x
+ Aded new background functions median and minimum.
+ (3/21/91, Valdes)
+
+=================================
+V3 of APEXTRACT Installed 8/23/90
+=================================
+
+apextract$exsum.x
+ Added a test for the existence of output images before extractions and
+ a query to select whether to clobber spectra or not. (8/9/89, Valdes)
+
+apextract$exmvsum.x
+apextract$exfit.x
+ 1. The moving average for profile images did not work correctly. It
+ subtracted the line moving out of the moving average but failed to
+ add in the line moving into the average. This caused the profile
+ to depart more and more from the data as the extraction procedes
+ through the image.
+ 2. The moving average for profile images actually used naverage + 1
+ instead of naverage becuase in this case the line being extract is
+ also included in the average.
+ 3. The fitting of the model to the data had a funny behavior when the
+ model had negative values and variance weight was used. The
+ negative values are now excluded from the fitting calculation in
+ this case. Note that the model is supposed to not contain negative
+ values. Also note that if variance weighting is not used then the
+ negative values are used in straight least-squares fitting.
+ (8/8/89, Valdes)
+
+apextract$apicset.x
+apextract$apedit.x
+apextract$apupdate.x
+ The region over which the background fitting is defined has been extended
+ to require overlapping the aperture. (7/31/89, Valdes)
+
+apextract$apcolon.x
+ Added gdeactivate/greactivate calls when using EPARAM. (6/14/89, Valdes)
+
+apextract$apextract.x
+ If reference apertures are used without change (no recenter, edit, or
+ retrace) then the apertures were not written to the database. This has
+ been changed to write (or query if interactive) the apertures if
+ dbwrite=yes. (5/19/89, Valdes)
+
+apextract$exio.h
+apextract$exio.x
+apextract$exsum.x
+ 1. The maximum number of simultaneous extractions was increased from
+ 20 to 50.
+ 2. The amount of buffering used for column access (dispaxis=1) was
+ increased from 100K pixels to 1M chars. (5/12/89, Valdes)
+
+apextract$doc/apsum.hlp
+ Added a sentence about the proper alignment of echelle spectra.
+ (5/8/89, Valdes)
+
+apextract$t_apscatter.x +
+apextract$apscatter.par +
+apextract$apscat1.par +
+apextract$apscat2.par +
+apextract$doc/apscatter.hlp +
+apextract$mkpkg
+apextract$x_apextract.x
+apextract$apextract.cl
+apextract$apextract.men
+apextract$apextract.hd
+imred$echelle/apscatter.par +
+imred$echelle/apscat1.par +
+imred$echelle/apscat2.par +
+imred$echelle/echelle.cl
+imred$echelle/echelle.men
+ Added a new task, APSCATTER, to fit and subtract scattered light.
+ It includes two hidden psets, APSCAT1 and APSCAT2. (3/3/89, Valdes)
+
+apextract$apnormalize.par
+imred$echelle/apnormalize.par
+ Input image parameter name needed to be changed from "images" to "input".
+ (2/28/89, Valdes)
+
+apextract$exio.x
+ Added errchk for imgeti related to getting DISPAXIS keyword which
+ might be missing. (2/28/89, Valdes)
+
+apextract$exsum.x
+ Changed usage of CRPIX keyword to real from integer. (1/25/89, Valdes)
+
+apextract$apgmark.x
+ The size of the aperture labels now decreases with increasing number
+ of apertures. (1/24/89, Valdes)
+
+apextract$t_apnorm.x
+apextract$apnormalize.par
+imred$echelle/apnormalize.par
+apextract$doc/apnormalize.hlp
+ Changed parameter names "lowreject" to "low_reject" and "highreject"
+ to "high_reject" to be consistent with other ICFIT tasks.
+ (1/24/89, Valdes)
+
+apextract$aprecenter.x
+ The progress information was not using the verbose parameter.
+ (1/23/89, Valdes)
+
+apextract$apedit.x
+ Fixed bug causing 'i' info to only be visibly momentarily.
+ (12/16/88 Valdes)
+
+apextract$t_apnorm.x
+ When fitting the normalization spectrum interactively any deleted
+ points would be remembered in the following apertures. Deleted points
+ are now cleared after interactive fitting. (12/15/88 Valdes)
+
+apextract$apedit.x
+ Fixed a minor bug in the 's' option (center + wx --> wx) (12/15/88 Valdes)
+
+apextract$*.x
+apextract$apio.par
+apextract$doc/apio.hlp
+ Removed the beep option. (12/8/88 Valdes)
+
+apextract$exgmodaps.x
+ The temporary apertures array and number of apertures were not being
+ initialized correctly causing a segmentation violation every time
+ the program was run. Added an n = 0 statement and initialized all the
+ pointers to NULL. (10/13/88 Davis)
+
+apextract$exmvsum.x
+ When cleaning and using a moving average the replacement of the bad pixel
+ in a data profile back in the moving average was in error leading to
+ bad results and possible memory corruption. (10/9/88 Valdes)
+
+apextract$exfit.x
+apextract$exmvsum.x
+ 1. The sigma clipping test now uses the variance relation for testing the
+ residuals.
+ 2. A bug was causing the length of the profile image to be incorrectly
+ referenced leading to an out of bounds error.
+
+apextract$apedit.x
+apextract$exapsum.x
+ 1. After doing a ":line" new apertures were defined with the old line
+ as the aperture center. This made tracing fail.
+ Now after changing the line the default aperture is updated and
+ the apeture center is explicitly set every time.
+ 2. In a rare circumstance a divide by zero error occured for the fitted
+ background. This is now checked. (7/19/88 Valdes)
+
+noao$lib/scr/apedit.key
+apextract$apedit.x
+ 1. Deleted a reference to :nfind in the cursor help.
+ 2. After deleting a background defintion it was no longer possible
+ to define a new one. Now an attempt to define backgrounds
+ after they have been deleted is initialized to the default again.
+ (7/1/88 Valdes)
+
+apextract$exsum.x
+ Fixed a bug in blocking overwriting of existing echelle format spectra.
+ Fixed a minor bug in writing the aperture info to the header of a 1D
+ format sky spectrum. (6/16/88 Valdes)
+
+apextract$apgmark.x
+ Labels are not written outside of graph range. (5/20/88 Valdes)
+
+apextract$apedit.x
+apextract$exgraph.x
+noao$lib/scr/apedit.key
+ Added 'I' interrupt. (4/20/88 Valdes)
+
+apextract$exio.x
+ EX_UNMAP when using column access was free a buffer supplied by
+ IMIO causing a memory corruption error on VMS. (3/30/88)
+
+apextract$exgmodaps.x
+ Model apertures where not being match up correctly resulting in a
+ warning message. (3/22/88 Valdes)
+
+apextract$exsum.x
+apextract$exstrip.x
+apextract$exrecen.x
+ Added iferr statements for asifit. Without this the task crashed
+ when an aperture went off the edge. (3/10/88 Valdes)
+
+apextract$* Major changes:
+ o Use profile template image
+ o Don't interpolate data profile before cleaning
+ o New background option
+ o Integrate apertures
+ o Restructure code
+ o And much more
+ (3/1/88 Valdes)
+
+==============
+APEXTRACT V2.0
+==============
+
+apextract$excextract.x -
+apextract$exlextract.x -
+ Removed these unused procedures. (1/5/88 Valdes)
+
+apextract$excstrip.x
+apextract$exlstrip.x
+ Free curfit pointer if ic_fit returns an error. (1/5/88 Valdes)
+
+apextract$excsum.x
+apextract$exlsum.x
+ Set background to zero if ic_fit returns an error. (1/5/88 Valdes)
+
+ Original:
+ iferr (call ic_fit (AP_IC(aps[i]), cv, Memr[x],
+ Memr[bufin], Memr[w], ncols, YES, YES, YES, YES))
+ ;
+
+ New:
+ iferr {
+ call ic_fit (AP_IC(aps[i]), cv, Memr[x],
+ Memr[bufin], Memr[w], ncols, YES, YES, YES, YES)
+ call ex_apbkg (cv, ncols, center, low, high,
+ skyout[line,i])
+ } then
+ skyout[line,i] = 0.
+
+apextract$exapsum.x
+ Added check for no data in sum. (1/5/88 Valdes)
+
+ In procedure ex_apsum:
+ a = max (0.5, center + lower)
+ b = min (npts + 0.5, center + upper)
+
+ if (a >= b) { <-- ADD
+ sum = 0. <-- ADD
+ return <-- ADD
+ }
+
+ In procedure ex_apbkg:
+ a = max (0.5, center + lower)
+ b = min (npts + 0.5, center + upper)
+
+ if (a >= b) { <-- ADD
+ bkg = 0. <-- ADD
+ return <-- ADD
+ }
+
+apextract$apnormalize.x
+ There was no error checking on ap_dbread which caused misleading errors
+ (apio package not found). This was fixed by updating the logic to be the
+ same as in apextract.x. A quick fix for outside sites is to add an
+ errchk for ap_dbread. (12/18/87 Valdes)
+
+apextract$apedit.x
+apextract$apgscur.x
+ When first entering APEDIT with apertures defined the first attempt to
+ point the cursur at the first aperture uses an indefinite y value since
+ no cursor read has yet taken place. The choices are to set it to some
+ arbitrary value, some percentage level on screen, or do nothing. I
+ chose to do nothing. Thus, the cursor will not point at the current
+ aperture in this case but it will leave the cursor position unchanged.
+ (12/17/87 Valdes)
+
+apextract$apio.par
+apextract$exsum.x
+apextract$exoutsum.x
+apextract$apedit.x
+ Added new parameter "format" to APIO pset. Added new output formats for
+ echelle and multispectra data consisting of a single 2D image. Added new
+ information in header. Old format is called "onedspec".
+
+ Removed debugging print statement. When it was put in I don't know.
+ (12/17/87 Valdes)
+
+apextract$apextract.x
+ An error was introduced with the change of 11/9/87 such that the error
+ when a database file does not exists was no longer being trapped. This
+ was intended for reference images but was not intended for creating new
+ database files. An iferr was added.
+
+apextract$t_apnormalize.x
+apextract$trtrace.x
+apextract$exstrip.x
+apextract$exsum.x
+ ERRCHK declarations for IMGETI were added to detect a missing DISPAXIS.
+ Failing to catch this error caused misleading error messages and
+ other fatal errors. (11/9/87 Valdes)
+
+apextract$apextract.x
+apextract$apdb.x
+ An error reading apertures for a specified reference image is now
+ printed instead of assuming there are no reference apertures.
+ (11/9/87 Valdes)
+
+apextract$exfit.x
+ Changed the variance formula from
+ V = v0 + v1 * abs (S + B)
+ to
+ V = v0 + v1 * max (0, S + B) if v0 > 0
+ V = v1 * max (1, S + B) if v0 = 0
+ (11/9/87 Valdes; see also 8/6/87)
+
+apextract$t_apnormalize.x
+ When normalizing more than 20 apertures some of the apertures
+ were being lost in the output image. This was fixed to only
+ fill between the apertures on the first set of apertures.
+
+ Normalizing when DISPAXIS=1 did not work. There were a number of
+ errors. This task was never tested with data in this orientation.
+ (9/22/87 Valdes)
+
+apextract$exfit.x
+apextract$apsum.par
+apextract$apstrip.par
+apextract$doc/apsum.hlp
+apextract$doc/apstrip.hlp
+ When computing the variance for doing variance weighting the
+ intensity could be negative. An absolute value was added to
+ correct this.
+
+ Make defaults for naverage=100 and nclean=2 because people have
+ been using inadequate number of lines for low signal-to-noise
+ data and because of interpolation even an 1 pixel cosmic ray
+ expands to two pixels. (8/6/87 Valdes)
+
+====
+V2.5
+====
+
+apextract$apio.par
+apextract$apio.x
+apextract$t_apnormalize.x
+apextract$exsum.x
+apextract$exstrip.x
+apextract$apfindnew.x
+apextract$apfind.x
+apextract$apextract.x
+apextract$apedit.x
+apextract$trtrace.x
+apextract$trltrace.x
+apextract$trctrace.x
+apextract$exgraph.x
+apextract$doc/apio.hlp
+ Valdes, May 19, 1987
+ 1. Added the parameter "verbose" to the APIO pset to allow turning off
+ log information to the terminal.
+ 2. Made changes to minimize switching between text and graphics mode.
+ With verbose=no there should be essentially no mode switching. This
+ was done for terminals in which such switches is either annoying
+ or slow.
+
+apextract$mkpkg
+apextract$apcvset.x
+apextract$t_apnormalize.x
+apextract$trtrace.x
+apextract$exsum.x
+apextract$exstrip.x
+apextract$apgetdata.x
+apextract$apimmap.x +
+ Valdes, April 24, 1987
+ 1. Protection against using an image which is not 2 dimensional was added.
+
+apextract$apedit.x
+apextract$apextract.x
+apextract$apsum.par
+apextract$exapsum.x
+apextract$excsum.x
+apextract$exgprofs.x
+apextract$exlsum.x
+apextract$exoutsum.x
+apextract$exsum.x
+apextract$doc/apsum.hlp
+ Valdes, April 11, 1987
+ 1. Added additional option to APSUM to output the subtracted sky
+ background spectra when doing background subtraction.
+
+apextract$apextract.hd
+apextract$apextract.men
+apextract$apextract.par
+apextract$apgetim.x
+apextract$apnormalize.par
+apextract$mkpkg
+apextract$t_apnormalize.x +
+apextract$x_apextract.x
+apextract$doc/apnormalize.hlp +
+ Valdes, April 3, 1987
+ 1. New task APNORMALIZE installed.
+
+apextract$*x
+ Valdes, February 17, 1987
+ 1. Required GIO changes.
+
+apextract$apio.h
+apextract$exgraph.x
+apextract$apio.x
+apextract$excextract.x
+apextract$apextract.tar
+apextract$trltrace.x
+apextract$trctrace.x
+apextract$exlextract.x
+apextract$applot.x
+apextract$apedit.x
+ Valdes, February 13, 1987
+ 1. I've made a number of modifications to the APEXTRACT package to
+ correct problems in the way graphics and text are mixed. The
+ main change was to make the graphics open very local to the
+ procedure doing the graphics. Previously the graphics device
+ was opened at the beginning of the logical task and remained
+ open until the end. This was done since the integrated nature
+ of the package has many procedures which may do graphics. This
+ has the bad side effects that for the first graphics open of
+ the process the terminal enters graphics mode (graphics screen
+ on SUN and clear screen on VT640) well before any graphics is
+ performed and text I/O is a problem. Putting GOPEN and GCLOSE
+ immediately around the code that does graphics fixed almost all
+ the problems. The only time that text output is now done when
+ the graphics terminal is open is for '?' and ':show' type of
+ commands. The only remaining problem is the page wait problem
+ associated with '?' occuring before a cursor read rather than
+ immediately after the text output causing the last written
+ status line to become confused with the page wait prompt.
+
+apextract$apfind.par
+ Valdes, February 12, 1987
+ 1. The parameter apfind.nfind was changed back to hidden in order
+ for apsum to work in the background. Note the PSET mechanism
+ would fix this by allowing nfind to be specified on the command
+ line.
+
+apextract$apio.par
+ Valdes, February 9, 1987
+ 1. New users rarely look at or know about the log files produced by
+ the package tasks. These files (particularly graphics) take up
+ a lot of space. Therefore the default is now not to log
+ text or graphics output.
+
+apextract$apedit.x
+apextract$apsort.x
+apextract$exapsum.x
+apextract$trltrace.x
+apextract$trctrace.x
+apextract$doc/apedit.hlp
+noao$lib/scr/apedit.key
+ Valdes, February 2, 1987
+ 1. Added a new edit option, 'o', to reorder the aperture id and beam
+ numbers sequentially. This is useful after apertures have been
+ deleted and added interactively.
+ 2. If the aperture went completely off the image (ie there is no
+ overlap of even part of the aperture with the image) a random value
+ was given the aperture sum because the value was not intialize to
+ zero. It is now initialize to zero.
+ 3. There is now a requirement that more than three points be traced
+ before a trace will be fit.
+
+apextract$trltrace.x
+apextract$trctrace.x
+apextract$apgetdata.x
+ Valdes, January 30, 1987
+ 1. The middle line (default) was not calculated correctly.
+ 2. The tracing would sometimes run beyond the end of the image. The
+ value of this traced point is suspect. It was found because there
+ would be a point off the end of the ICFIT graph which was set to
+ be the size of the image.
+ 3. Just in case a traced point is right at the edge I made the default
+ window for fitting the trace extend half a step beyond the edges
+ of the image.
+
+apextract$exsum.x
+apextract$exstrip.x
+ Valdes, January 30, 1987
+ 1. Skip Schaller (Steward) reported a problem with running out of memory
+ with an input list of 20 images. Also when the user deleted input
+ images after they were processed but before the list was finished
+ (to reduce memory) the memory was not actually freed until the process
+ actually finished. I found that the input images
+ where not being closed! (Sorry about this really stupid error.)
+ This may not be all the problem but it is probable since IMIO
+ maintains large buffers.
+
+apextract$apcolon.x
+ Valdes, January 15, 1987
+ 1. Replaced dictionary string and numeric case by macros for readability.
+
+apextract$apfind.par
+ Valdes, December 19, 1986
+ 1. Change the default NFIND parameter in APFIND to auto mode.
+
+apextract$apnearest.x
+ Valdes, December 12, 1986
+ 1. It is possible for more than one aperture to be equidistant from
+ the cursor, particularly when more than one aperture is defined for
+ the same feature. This is ambiguous for those commands which operate on
+ the nearest aperture. The modification will query the user if it
+ is found that there is more than one aperture at the same distance
+ from the cursor.
+
+apextract$peaks.x
+ Valdes, October 10, 1986
+ 1. VMS adjustable array dimension error found. Replaced declaration
+ dimension by ARB since the passed dimension value may be zero.
+
+apextract$*
+ Valdes, September 16, 1986
+ 1. A new version of the package has been installed. It is very
+ different from the old version. The user parameter files must
+ be unlearned.
+
+====================
+New Package Released
+====================
+
+apextract$: Valdes, July 19, 1986
+ 1. APEDIT and TRACE modified to include a detection threshold parameter
+ for profile centering.
+ 2. The help pages were updated.
+
+apextract$apedit.x, apvalue.x: Valdes, July 17, 1986
+ 1. A bug was found that appears if you edit the apertures of a
+ previously traced image. The center moves with use of 'l' or
+ 'u'. This is due to an inconsistency between whether the aperture
+ center is before or after the traced shift is added. Changes
+ to APVALUE.X and the calls to it in APEDIT.X fix this.
+
+apextract$: Valdes, July 15, 1986
+ 1. TRACE had a bug when trying to specify an explicit starting
+ line to edit and trace from. This was fixed.
+ 2. EXCEXTRACT.X, EXLEXTRACT.X, and EXGPROFS.X were modified to
+ check for errors from background fitting. This arose when
+ trying to get the background for a spectrum which has gone
+ off the edge of the image.
+
+apextract$apedit.x, apsort.x : Valdes, July 9, 1986
+ 1. When changing the aperture number the apertures are sorted and
+ then the wrong aperture could become the current aperture if
+ another aperture exists with the same aperture number. This was
+ fixed so that the sorting returns the correct current aperture
+ after sorting. Also apindex.x is no longer needed.
+
+apextract$apedit.x: Valdes, July 7, 1986
+ 1. The 'd' delete key now does nothing if no apertures are defined.
+ Previously it would cause a failure of the task.
+
+apextract$apedit.x: Valdes, July 7, 1986
+ 1. Added redraw and window commands.
+ 2. Help page and '?' menu updated.
+
+apextract$apedit.x: Valdes, July 3, 1986
+ 1. APEDIT modified to use new ICFIT package.
+
+apextract$apgetim.x: Valdes, July 1, 1986
+ 1. New procedure to strip the image extension. This is necessary
+ to create proper database files and to avoid having two legal
+ names for images in the database.
+
+apextract$exapstrip.x: Valdes, July 1, 1986
+ 1. Simple strip extraction without profile modeling interpolated
+ the data so that the lower edge of the aperture was centered
+ on the first pixel. This is inconsistent with the other extractions
+ which put the center of the aperture at the center of a pixel.
+ This has been fixed.
+
+apextract: Valdes, June 30, 1986:
+ 1. TRACE was not correctly initializing the new ICFIT package.
+ In particular the task parameters "function" and "order" had no
+ effect and when multiple files were used the last set parameters
+ were not retained. Changes to t_trace.x, trctrace.x, trltrace.x.
+
+=====================================
+STScI Pre-release and SUN 2.3 Release
+=====================================
+
+apextract: Valdes, June 20, 1986:
+ 1. New APEXTRACT installed. This version includes background
+ subtraction and new ICFIT.
+
+apextract: Valdes, June 2, 1986
+ 1. Another round of name changes. EDITAPS -> APEDIT,
+ EXTRACT1 -> SUMEXTRACT, EXTRACT2 -> STRIPEXTRACT.
+
+apextract: Valdes, May 16, 1986
+ 1. Renamed APDEFINE to EDITAPS.
+ 2. Moved parameters used in editing the apertures from EXTRACT1 and
+ EXTRACT2. These are now obtained from EDITAPS regardless of which
+ task calls apedit.
+ 3. Added parameters "cradius", "cwidth", "ctype", "lower", and "upper"
+ to EDITAPS. The first parameters control profile centering and the
+ last parameters set the default aperture limits.
+ 1. Added new keys. 'c' center current aperture of profile near the cursor.
+ 'm' mark and center aperture on profile near the cursor. 's' shift
+ the center of the current aperture to the cursor position. The change
+ allows centering of profiles using CENTER1D.
+
+apextract$extract.x: Valdes, May 13, 1986
+ 1. EXTRACT has been broken up into two tasks; EXTRACT1 and EXTRACT2.
+ EXTRACT1 extracts weighted summed 1D spectra. EXTRACT2 extracts
+ 2D apertures corrected for shifts across the dispersion.
+
+apextract: Valdes, April 23, 1986
+ 1. Modified EXTRACT to only warn about an existing output image.
+ This allows adding a new aperture without needing to delete
+ old apertures or reextract previous extractions.
+
+apextract: Valdes, April 21, 1986
+ 1. All procedures which pass the number of current apertures as an
+ argument and then dimension the array with this number
+ were modified by dimensioning the array as dimension
+ APS_MAXAPS or ARB. This was done because the number of apertures
+ might be zero. This is a fatal error on VMS/VAX though not on UNIX/VAX.
+
+apextract: Valdes, March 27, 1986
+ 1. Modified EXTRACT (exsum.x and exwt.x) to update the dispersion image
+ header parameters. In particular if the input dispersion axis is 2
+ then the header parameters must be reset to dispersion axis 1.
+
+===========
+Release 2.2
+===========
+.endhelp
diff --git a/noao/twodspec/apextract/apall.par b/noao/twodspec/apextract/apall.par
new file mode 100644
index 00000000..7c97a920
--- /dev/null
+++ b/noao/twodspec/apextract/apall.par
@@ -0,0 +1,96 @@
+# APALL
+
+input,s,a,,,,List of input images
+output,s,h,"",,,List of output spectra
+apertures,s,h,"",,,Apertures
+format,s,h,"multispec","onedspec|multispec|echelle|strip",,Extracted spectra format
+references,s,h,"",,,List of aperture reference images
+profiles,s,h,"",,,"List of aperture profile images
+"
+interactive,b,h,yes,,,Run task interactively?
+find,b,h,yes,,,Find apertures?
+recenter,b,h,yes,,,Recenter apertures?
+resize,b,h,yes,,,Resize apertures?
+edit,b,h,yes,,,Edit apertures?
+trace,b,h,yes,,,Trace apertures?
+fittrace,b,h,yes,,,Fit the traced points interactively?
+extract,b,h,yes,,,Extract spectra?
+extras,b,h,yes,,,"Extract sky, sigma, etc.?"
+review,b,h,yes,,,"Review extractions?
+"
+line,i,h,INDEF,1,,Dispersion line
+nsum,i,h,10,,,"Number of dispersion lines to sum or median
+
+# DEFAULT APERTURE PARAMETERS
+"
+lower,r,h,-5,,,Lower aperture limit relative to center
+upper,r,h,5,,,Upper aperture limit relative to center
+apidtable,s,h,"",,,"Aperture ID table (optional)
+
+# DEFAULT BACKGROUND PARAMETERS
+"
+b_function,s,h,"chebyshev","chebyshev|legendre|spline1|spline3",,Background function
+b_order,i,h,1,1,,Background function order
+b_sample,s,h,"-10:-6,6:10",,,Background sample regions
+b_naverage,i,h,-3,,,Background average or median
+b_niterate,i,h,0,0,,Background rejection iterations
+b_low_reject,r,h,3.,0.,,Background lower rejection sigma
+b_high_reject,r,h,3.,0.,,Background upper rejection sigma
+b_grow,r,h,0.,0.,,"Background rejection growing radius
+
+# APERTURE CENTERING PARAMETERS
+"
+width,r,h,5.,0.,,Profile centering width
+radius,r,h,10.,,,Profile centering radius
+threshold,r,h,0.,0.,,"Detection threshold for profile centering
+
+# AUTOMATIC FINDING AND ORDERING PARAMETERS
+"
+nfind,i,q,,,,Number of apertures to be found automatically
+minsep,r,h,5.,1.,,Minimum separation between spectra
+maxsep,r,h,100000.,1.,,Maximum separation between spectra
+order,s,h,"increasing","increasing|decreasing",,"Order of apertures
+
+# RECENTERING PARAMETERS
+"
+aprecenter,s,h,"",,,Apertures for recentering calculation
+npeaks,r,h,INDEF,0.,,Select brightest peaks
+shift,b,h,yes,,,"Use average shift instead of recentering?
+
+# RESIZING PARAMETERS
+"
+llimit,r,h,INDEF,,,Lower aperture limit relative to center
+ulimit,r,h,INDEF,,,Upper aperture limit relative to center
+ylevel,r,h,0.1,,,Fraction of peak or intensity for automatic width
+peak,b,h,yes,,,Is ylevel a fraction of the peak?
+bkg,b,h,yes,,,"Subtract background in automatic width?"
+r_grow,r,h,0.,,,"Grow limits by this factor"
+avglimits,b,h,no,,,"Average limits over all apertures?
+
+# TRACING PARAMETERS
+"
+t_nsum,i,h,10,1,,Number of dispersion lines to sum
+t_step,i,h,10,1,,Tracing step
+t_nlost,i,h,3,1,,Number of consecutive times profile is lost before quitting
+t_function,s,h,"legendre","chebyshev|legendre|spline1|spline3",,Trace fitting function
+t_order,i,h,2,1,,Trace fitting function order
+t_sample,s,h,"*",,,Trace sample regions
+t_naverage,i,h,1,,,Trace average or median
+t_niterate,i,h,0,0,,Trace rejection iterations
+t_low_reject,r,h,3.,0.,,Trace lower rejection sigma
+t_high_reject,r,h,3.,0.,,Trace upper rejection sigma
+t_grow,r,h,0.,0.,,"Trace rejection growing radius
+
+# EXTRACTION PARAMETERS
+"
+background,s,h,"none","none|average|median|minimum|fit",,Background to subtract
+skybox,i,h,1,1,,Box car smoothing length for sky
+weights,s,h,"none","none|variance",,Extraction weights (none|variance)
+pfit,s,h,"fit1d","fit1d|fit2d",,Profile fitting type (fit1d|fit2d)
+clean,b,h,no,,,Detect and replace bad pixels?
+saturation,r,h,INDEF,1.,,Saturation level
+readnoise,s,h,"0.",,,Read out noise sigma (photons)
+gain,s,h,"1.",,,Photon gain (photons/data number)
+lsigma,r,h,4,0,,Lower rejection threshold
+usigma,r,h,4,0,,Upper rejection threshold
+nsubaps,i,h,1,1,,Number of subapertures per aperture
diff --git a/noao/twodspec/apextract/apall1.par b/noao/twodspec/apextract/apall1.par
new file mode 100644
index 00000000..12a28b32
--- /dev/null
+++ b/noao/twodspec/apextract/apall1.par
@@ -0,0 +1,117 @@
+# OUTPUT PARAMETERS
+
+apertures,s,h,)apall.apertures,,,>apall.apertures
+format,s,h,)apall.format,,,>apall.format
+extras,b,h,)apall.extras,,,>apall.extras
+dbwrite,s,h,yes,,,Write to database?
+initialize,b,h,yes,,,Initialize answers?
+verbose,b,h,)_.verbose,,,"Verbose output?
+
+# DEFAULT APERTURE PARAMETERS
+"
+lower,r,h,)apall.lower,,,>apall.lower
+upper,r,h,)apall.upper,,,>apall.upper
+apidtable,s,h,)apall.apidtable,,,">apall.apidtable
+
+# DEFAULT BACKGROUND PARAMETERS
+"
+b_function,s,h,)apall.b_function,,,>apall.b_function
+b_order,i,h,)apall.b_order,,,>apall.b_order
+b_sample,s,h,)apall.b_sample,,,>apall.b_sample
+b_naverage,i,h,)apall.b_naverage,,,>apall.b_naverage
+b_niterate,i,h,)apall.b_niterate,,,>apall.b_niterate
+b_low_reject,r,h,)apall.b_low_reject,,,>apall.b_low_reject
+b_high_reject,r,h,)apall.b_high_reject,,,>apall.b_high_reject
+b_grow,r,h,)apall.b_grow,,,">apall.b_grow
+
+# APERTURE CENTERING PARAMETERS
+"
+width,r,h,)apall.width,,,>apall.width
+radius,r,h,)apall.radius,,,>apall.radius
+threshold,r,h,)apall.threshold,,,">apall.threshold
+
+# AUTOMATIC FINDING AND ORDERING PARAMETERS
+"
+nfind,i,h,)apall.nfind,,,>apall.nfind
+minsep,r,h,)apall.minsep,,,>apall.minsep
+maxsep,r,h,)apall.maxsep,,,>apall.maxsep
+order,s,h,)apall.order,,,">apall.order
+
+# RECENTERING PARAMETERS
+"
+aprecenter,s,h,)apall.aprecenter,,,>apall.aprecenter
+npeaks,r,h,)apall.npeaks,,,>apall.npeaks
+shift,b,h,)apall.shift,,,">apall.shift
+
+# RESIZING PARAMETERS
+"
+llimit,r,h,)apall.llimit,,,>apall.llimit
+ulimit,r,h,)apall.ulimit,,,>apall.ulimit
+ylevel,r,h,)apall.ylevel,,,>apall.ylevel
+peak,b,h,)apall.peak,,,>apall.peak
+bkg,b,h,)apall.bkg,,,>apall.bkg
+r_grow,r,h,)apall.r_grow,,,>apall.r_grow
+avglimits,b,h,)apall.avglimits,,,">apall.avglimits
+
+# EDITING PARAMETERS
+"
+e_output,s,q,,,,Output spectra rootname
+e_profiles,s,q,,,,Profile reference image
+
+# TRACING PARAMETERS
+t_nsum,i,h,)apall.t_nsum,,,>apall.t_nsum
+t_step,i,h,)apall.t_step,,,>apall.t_step
+t_nlost,i,h,)apall.t_nlost,,,>apall.t_nlost
+t_width,r,h,)apall.width,,,>apall.width
+t_function,s,h,)apall.t_function,,,>apall.t_function
+t_order,i,h,)apall.t_order,,,>apall.t_order
+t_sample,s,h,)apall.t_sample,,,>apall.t_sample
+t_naverage,i,h,)apall.t_naverage,,,>apall.t_naverage
+t_niterate,i,h,)apall.t_niterate,,,>apall.t_niterate
+t_low_reject,r,h,)apall.t_low_reject,,,>apall.t_low_reject
+t_high_reject,r,h,)apall.t_high_reject,,,>apall.t_high_reject
+t_grow,r,h,)apall.t_grow,,,">apall.t_grow
+
+# EXTRACTION PARAMETERS
+"
+background,s,h,)apall.background,,,>apall.background
+skybox,i,h,)apall.skybox,,,>apall.skybox
+weights,s,h,)apall.weights,,,>apall.weights
+pfit,s,h,)apall.pfit,,,>apall.pfit
+clean,b,h,)apall.clean,,,>apall.clean
+nclean,r,h,0.5,,,Maximum number of pixels to clean
+niterate,i,h,5,0,,Number of profile fitting iterations
+saturation,r,h,)apall.saturation,,,>apall.saturation
+readnoise,s,h,)apall.readnoise,,,>apall.readnoise
+gain,s,h,)apall.gain,,,>apall.gain
+lsigma,r,h,)apall.lsigma,,,>apall.lsigma
+usigma,r,h,)apall.usigma,,,>apall.usigma
+polysep,r,h,0.90,0.1,0.95,Marsh algorithm polynomial spacing
+polyorder,i,h,10,1,,Marsh algorithm polynomial order
+nsubaps,i,h,)apall.nsubaps,,,">apall.nsubaps
+
+# ANSWER PARAMETERS
+"
+ansclobber,s,h,"no",,," "
+ansclobber1,s,h,"no",,," "
+ansdbwrite,s,h,"yes",,," "
+ansdbwrite1,s,h,"yes",,," "
+ansedit,s,h,"yes",,," "
+ansextract,s,h,"yes",,," "
+ansfind,s,h,"yes",,," "
+ansfit,s,h,"yes",,," "
+ansfitscatter,s,h,"yes",,," "
+ansfitsmooth,s,h,"yes",,," "
+ansfitspec,s,h,"yes",,," "
+ansfitspec1,s,h,"yes",,," "
+ansfittrace,s,h,"yes",,," "
+ansfittrace1,s,h,"yes",,," "
+ansflat,s,h,"yes",,," "
+ansnorm,s,h,"yes",,," "
+ansrecenter,s,h,"yes",,," "
+ansresize,s,h,"yes",,," "
+ansreview,s,h,"yes",,," "
+ansreview1,s,h,"yes",,," "
+ansscat,s,h,"yes",,," "
+anssmooth,s,h,"yes",,," "
+anstrace,s,h,"yes",,," "
diff --git a/noao/twodspec/apextract/apalloc.x b/noao/twodspec/apextract/apalloc.x
new file mode 100644
index 00000000..086db650
--- /dev/null
+++ b/noao/twodspec/apextract/apalloc.x
@@ -0,0 +1,34 @@
+include "apertures.h"
+
+# AP_ALLOC -- Allocate and initialize an aperture structure.
+
+procedure ap_alloc (ap)
+
+pointer ap # Aperture
+
+begin
+ call calloc (ap, AP_LEN, TY_STRUCT)
+ AP_TITLE(ap) = NULL
+ AP_CV(ap) = NULL
+ AP_IC(ap) = NULL
+ AP_SELECT(ap) = YES
+end
+
+
+# AP_FREE -- Free an aperture structure and related CURFIT structures.
+
+procedure ap_free (ap)
+
+pointer ap # Aperture
+
+begin
+ if (ap != NULL) {
+ if (AP_TITLE(ap) != NULL)
+ call mfree (AP_TITLE(ap), TY_CHAR)
+ if (AP_CV(ap) != NULL)
+ call cvfree (AP_CV(ap))
+ if (AP_IC(ap) != NULL)
+ call ic_closer (AP_IC(ap))
+ call mfree (ap, TY_STRUCT)
+ }
+end
diff --git a/noao/twodspec/apextract/apanswer.x b/noao/twodspec/apextract/apanswer.x
new file mode 100644
index 00000000..0077af4a
--- /dev/null
+++ b/noao/twodspec/apextract/apanswer.x
@@ -0,0 +1,121 @@
+define ANSWERS "|no|yes|NO|YES|"
+
+
+# AP_ANSWER -- Prompt the user (if needed) and return bool based
+# on 4-valued response
+
+bool procedure ap_answer (param, prompt)
+
+char param[ARB] # Parameter name
+char prompt[ARB] # Prompt to be issued
+
+char word[3]
+int i, apgwrd()
+pointer pmode
+
+begin
+ i = apgwrd (param, word, 3, ANSWERS)
+ switch (i) {
+ case 3:
+ return (false)
+ case 4:
+ return (true)
+ default:
+ call malloc (pmode, SZ_LINE, TY_CHAR)
+ call sprintf (Memc[pmode], SZ_LINE, "%s.p_mode")
+ call pargstr (param)
+ call appstr (Memc[pmode], "q")
+ repeat {
+ call eprintf (prompt)
+ call flush (STDERR)
+ ifnoerr (i = apgwrd (param, word, 3, ANSWERS))
+ break
+ }
+ call appstr (param, word)
+ call appstr (Memc[pmode], "h")
+ call mfree (pmode, TY_CHAR)
+ }
+
+ switch (i) {
+ case 1, 3:
+ return (false)
+ case 2, 4:
+ return (true)
+ }
+end
+
+
+# APGANSB -- Convert 4-valued parameter to bool
+
+bool procedure apgansb (param)
+
+char param[ARB] # Parameter name
+
+char word[3]
+int apgwrd()
+
+begin
+ switch (apgwrd (param, word, 3, ANSWERS)) {
+ case 1, 3:
+ return (false)
+ default:
+ return (true)
+ }
+end
+
+
+# APGANS -- Convert 4-value parameter to bool except "no" is true.
+
+bool procedure apgans (param)
+
+char param[ARB] # Parameter name
+
+char word[3]
+pointer pmode
+bool streq()
+
+begin
+ call malloc (pmode, SZ_LINE, TY_CHAR)
+ call sprintf (Memc[pmode], SZ_LINE, "%s.p_mode")
+ call pargstr (param)
+ call apgstr (Memc[pmode], word, 3)
+ if (word[1] != 'h')
+ call appstr (Memc[pmode], "h")
+ call mfree (pmode, TY_CHAR)
+ call apgstr (param, word, 3)
+ return (!streq (word, "NO"))
+end
+
+
+# APPANS -- Put 4-valued parameter based on interactive parameter.
+
+procedure appans (param, ival, nival)
+
+char param[ARB] # Parameter
+bool ival # Interactive value
+bool nival # Noninteractive value
+
+char word[3]
+pointer pmode
+bool clgetb()
+
+begin
+ call malloc (pmode, SZ_LINE, TY_CHAR)
+ call sprintf (Memc[pmode], SZ_LINE, "%s.p_mode")
+ call pargstr (param)
+ call apgstr (Memc[pmode], word, 3)
+ if (word[1] != 'h')
+ call appstr (Memc[pmode], "h")
+ call mfree (pmode, TY_CHAR)
+ if (clgetb ("interactive")) {
+ if (ival)
+ call appstr (param, "yes")
+ else
+ call appstr (param, "NO")
+ } else {
+ if (nival)
+ call appstr (param, "YES")
+ else
+ call appstr (param, "NO")
+ }
+end
diff --git a/noao/twodspec/apextract/apcenter.x b/noao/twodspec/apextract/apcenter.x
new file mode 100644
index 00000000..88f089d1
--- /dev/null
+++ b/noao/twodspec/apextract/apcenter.x
@@ -0,0 +1,26 @@
+include <pkg/center1d.h>
+
+# AP_CENTER -- Locate the center of an emission profile. This is done
+# using the CENTER1D algorithm. The procedure gets the centering
+# parameters using CL queries. If the center is not found because of the
+# RADIUS or THRESHOLD centering criteria then INDEF is returned.
+
+real procedure ap_center (x, data, npts)
+
+real x # Initial guess
+real data[npts] # Data
+int npts # Number of data points
+
+real width # Centering width
+real radius # Centering radius
+real threshold # Detection threshold
+
+real apgetr(), center1d()
+
+begin
+ width = apgetr ("width")
+ radius = apgetr ("radius")
+ threshold = apgetr ("threshold")
+
+ return (center1d (x, data, npts, width, EMISSION, radius, threshold))
+end
diff --git a/noao/twodspec/apextract/apcolon.x b/noao/twodspec/apextract/apcolon.x
new file mode 100644
index 00000000..9e910a95
--- /dev/null
+++ b/noao/twodspec/apextract/apcolon.x
@@ -0,0 +1,384 @@
+include <gset.h>
+include <imhdr.h>
+include <error.h>
+include "apertures.h"
+
+# List of colon commands.
+define CMDS "|show|parameters|database|logfile|plotfile|read|write|image\
+ |line|nsum|center|lower|upper|title\
+ |extras,b|apidtable,s|b_function,s|b_order,i|b_sample,s\
+ |b_naverage,i|b_niterate,i|b_low_reject,r|b_high_reject,r|b_grow,r\
+ |minsep,r|maxsep,r|order,s|apertures,s|npeaks,r|shift,b|llimit,r\
+ |ulimit,r|ylevel,r|peak,b|bkg,b|r_grow,r|avglimits,b|width,r|radius,r\
+ |threshold,r|t_nsum,i|t_step,i|t_width,r|t_function,s|t_order,i\
+ |t_sample,s|t_naverage,i|t_niterate,i|t_low_reject,r|t_high_reject,r\
+ |t_grow,r|nsubaps,i|background,s|skybox,i|clean,b|saturation,r\
+ |weights,s|readnoise,s|gain,s|lsigma,r|usigma,r|t_nlost,i|"
+
+define SHOW 1 # Show apertures
+define PARAMS 2 # Show parameters
+define DATABASE 3 # Database
+define LOGFILE 4 # Logfile
+define PLOTFILE 5 # Plotfile
+define READ 6 # Read aperture database entry
+define WRITE 7 # Write aperture database entry
+define IMAGE 8 # Image being edited
+define LINE 9 # Set image line to display
+define NSUM 10 # Set number of image lines to sum for display
+define CENTER 11 # Set aperture center
+define LOWER 12 # Set aperture lower limit
+define UPPER 13 # Set aperture upper limit
+define APTITLE 14 # Set aperture title
+
+
+# AP_COLON -- Process colon commands. The colon commands may be abbreviated.
+# Optional arguments determine either the output or the value of a parameter.
+# Changes are signaled to the calling task with the flags NEWGRAPH, NEWIM,
+# and NEWDATA. This task does CLIO including CLCMDW commands.
+
+procedure ap_colon (cmd, im, gp, apdef, aps, naps, current, image, line,
+ nsum, all, newgraph, newim, newdata, statline)
+
+char cmd[ARB] # Colon command
+pointer im # IMIO pointer
+pointer gp # GIO pointer
+pointer apdef # Default aperture
+pointer aps # Aperture pointers
+int naps # Number of apertures
+int current # Current aperture
+char image[SZ_FNAME] # Image name
+int line # Dispersion line
+int nsum # Number of lines to sum
+int all # All switch
+int newgraph # New graph flag
+int newim # New image flag
+int newdata # New data flag
+int statline # Status line used?
+
+bool bval
+int i, j, ival, apid, apbeam
+real center, low, high, rval
+pointer sp, wrd, str
+
+bool strne(), apgetb()
+real apgetr()
+int nscan(), strdic(), imaccess(), apgeti(), stridxs()
+errchk ap_apertures, ap_show, ap_params, ap_dbread, ap_dbwrite, ap_openio
+
+define done_ 99
+
+begin
+ call smark (sp)
+ call salloc (wrd, SZ_LINE, TY_CHAR)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ # Scan the command string for the first word which may be abbreviated.
+ call sscan (cmd)
+ call gargwrd (Memc[wrd], SZ_LINE)
+ i = strdic (Memc[wrd], Memc[wrd], SZ_LINE, CMDS)
+ if (i == 0) {
+ call printf ("Unrecognized or ambiguous command\007")
+ statline = YES
+ call sfree (sp)
+ return
+ }
+ j = stridxs (",", Memc[wrd])
+
+ if (j == 0) {
+ switch (i) {
+ case SHOW: # :show - Show aperture list
+ call gargwrd (cmd, SZ_LINE)
+ if (nscan() == 1) {
+ call gdeactivate (gp, AW_CLEAR)
+ call ap_show ("STDOUT", Memi[aps], naps)
+ call greactivate (gp, AW_PAUSE)
+ } else {
+ iferr (call ap_show (cmd, Memi[aps], naps)) {
+ call erract (EA_WARN)
+ statline = YES
+ }
+ }
+ case PARAMS: # :parameters - Show parameters
+ call gargwrd (cmd, SZ_LINE)
+ if (nscan() == 1) {
+ call mktemp ("junk", cmd, SZ_LINE)
+ iferr (call ap_params (cmd, image, line, nsum)) {
+ call gdeactivate (gp, AW_CLEAR)
+ call ap_params ("STDOUT", image, line, nsum)
+ call greactivate (gp, AW_PAUSE)
+ } else {
+ call gpagefile (gp, cmd, ":parameters")
+ call delete (cmd)
+ }
+ } else {
+ iferr (call ap_params (cmd, image, line, nsum)) {
+ call erract (EA_WARN)
+ statline = YES
+ }
+ }
+ case DATABASE: # :database - Database name
+ call gargwrd (cmd, SZ_LINE)
+ if (nscan() == 1) {
+ call clgstr ("database", cmd, SZ_LINE)
+ call printf ("database %s")
+ call pargstr (cmd)
+ statline = YES
+ } else
+ call clpstr ("database", cmd)
+ case LOGFILE: # :logfile - Logfile name
+ call gargwrd (cmd, SZ_LINE)
+ if (nscan() == 1) {
+ call clgstr ("logfile", cmd, SZ_LINE)
+ call printf ("logfile %s")
+ call pargstr (cmd)
+ statline = YES
+ } else
+ call clpstr ("logfile", cmd)
+ case PLOTFILE: # :plotfile - Plotfile name
+ call gargwrd (cmd, SZ_LINE)
+ if (nscan() == 1) {
+ call clgstr ("plotfile", cmd, SZ_LINE)
+ call printf ("plotfile %s")
+ call pargstr (cmd)
+ statline = YES
+ } else
+ call clpstr ("plotfile", cmd)
+ case READ: # :read - Read database entry
+ iferr {
+ call gargwrd (cmd, SZ_LINE)
+ if (nscan() == 1)
+ call ap_dbread (image, aps, naps)
+ else {
+ call xt_stripwhite (cmd)
+ if (cmd[1] == EOS)
+ call ap_dbread (image, aps, naps)
+ else {
+ call ap_dbread (cmd, aps, naps)
+ call appstr ("ansdbwrite1", "yes")
+ }
+ }
+ } then {
+ call erract (EA_WARN)
+ statline = YES
+ }
+ current = min (1, naps)
+ newgraph = YES
+ case WRITE: # :write - Write database entry
+ iferr {
+ call gargwrd (cmd, SZ_LINE)
+ if (nscan() == 1)
+ call ap_dbwrite (image, aps, naps)
+ else {
+ call xt_stripwhite (cmd)
+ if (cmd[1] == EOS)
+ call ap_dbwrite (image, aps, naps)
+ else {
+ call ap_dbwrite (cmd, aps, naps)
+ call appstr ("ansdbwrite1", "yes")
+ }
+ }
+ } then {
+ call erract (EA_WARN)
+ statline = YES
+ }
+ case IMAGE: # :image - Define a new image
+ call gargwrd (cmd, SZ_LINE)
+ if (nscan() == 1) {
+ call printf ("image %s")
+ call pargstr (image)
+ statline = YES
+ } else {
+ call xt_stripwhite (cmd)
+ if ((cmd[1] != EOS) && (strne (cmd, image))) {
+ if (imaccess (cmd, READ_ONLY) == YES)
+ newim = YES
+ else {
+ call eprintf (
+ "WARNING: Can't read image %s")
+ call pargstr (cmd)
+ statline = YES
+ }
+ }
+ }
+ case LINE: # :line - Image line or column
+ call gargi (ival)
+ if (nscan() < 2) {
+ call printf ("line %d")
+ call pargi (line)
+ statline = YES
+ } else if (ival != line) {
+ call strcpy (image, cmd, SZ_LINE)
+ line = ival
+ newdata = YES
+ }
+ case NSUM: # :nsum - Number of image lines or columns to sum
+ call gargi (ival)
+ if (nscan() < 2) {
+ call printf ("nsum %d")
+ call pargi (nsum)
+ statline = YES
+ } else if (ival != nsum) {
+ call strcpy (image, cmd, SZ_LINE)
+ nsum = ival
+ newdata = YES
+ }
+ case CENTER: # :center - Set aperture center
+ if (current == 0)
+ goto done_
+ call gargr (rval)
+ if (nscan() == 1) {
+ call ap_values (current, Memi[aps], line, apid,
+ apbeam, center, low, high)
+ call printf ("center %g")
+ call pargr (center)
+ statline = YES
+ } else if (all == NO) {
+ call ap_values (current, Memi[aps], line, apid,
+ apbeam, center, low, high)
+ iferr (call ap_update (gp, Memi[aps+current-1], line, apid,
+ apbeam, rval, low, high)) {
+ call erract (EA_WARN)
+ statline = YES
+ }
+ } else {
+ call ap_values (current, Memi[aps], line, apid,
+ apbeam, center, low, high)
+ rval = rval - center
+ do i = 1, naps {
+ call ap_values (i, Memi[aps], line, apid,
+ apbeam, center, low, high)
+ center = center + rval
+ iferr (call ap_update (gp, Memi[aps+i-1], line, apid,
+ apbeam, center, low, high)) {
+ call erract (EA_WARN)
+ statline = YES
+ }
+ }
+ }
+ case LOWER: # :lower - Set lower aperture limit
+ if (current == 0)
+ goto done_
+ call gargr (rval)
+ if (nscan() == 1) {
+ call ap_values (current, Memi[aps], line, apid,
+ apbeam, center, low, high)
+ call printf ("low %g")
+ call pargr (low)
+ statline = YES
+ } else if (all == NO) {
+ call ap_values (current, Memi[aps], line, apid,
+ apbeam, center, low, high)
+ iferr (call ap_update (gp, Memi[aps+current-1], line, apid,
+ apbeam, center, rval, high)) {
+ call erract (EA_WARN)
+ statline = YES
+ }
+ } else {
+ do i = 1, naps {
+ call ap_values (i, Memi[aps], line, apid,
+ apbeam, center, low, high)
+ iferr (call ap_update (gp, Memi[aps+i-1], line, apid,
+ apbeam, center, rval, high))
+ call erract (EA_WARN) {
+ statline = YES
+ }
+ }
+ }
+ case UPPER: # :upper - Set upper aperture limit
+ if (current == 0)
+ goto done_
+ call gargr (rval)
+ if (nscan() == 1) {
+ call ap_values (current, Memi[aps], line, apid,
+ apbeam, center, low, high)
+ call printf ("high %g")
+ call pargr (high)
+ statline = YES
+ } else if (all == NO) {
+ call ap_values (current, Memi[aps], line, apid,
+ apbeam, center, low, high)
+ iferr (call ap_update (gp, Memi[aps+current-1], line, apid,
+ apbeam, center, low, rval)) {
+ call erract (EA_WARN)
+ statline = YES
+ }
+ } else {
+ do i = 1, naps {
+ call ap_values (i, Memi[aps], line, apid,
+ apbeam, center, low, high)
+ iferr (call ap_update (gp, Memi[aps+i-1], line, apid,
+ apbeam, center, low, rval)) {
+ call erract (EA_WARN)
+ statline = YES
+ }
+ }
+ }
+ case APTITLE:
+ if (current == 0)
+ goto done_
+ call gargwrd (Memc[wrd], SZ_LINE)
+ if (nscan() == 1) {
+ call printf ("title %s")
+ if (AP_TITLE(Memi[aps+current-1]) != NULL)
+ call pargstr (Memc[AP_TITLE(Memi[aps+current-1])])
+ else
+ call pargstr ("[NONE]")
+ statline = YES
+ } else {
+ call reset_scan ()
+ call gargwrd (Memc[str], SZ_LINE)
+ call gargstr (Memc[str], SZ_LINE)
+ if (AP_TITLE(Memi[aps+current-1]) == NULL)
+ call malloc (AP_TITLE(Memi[aps+current-1]), SZ_APTITLE,
+ TY_CHAR)
+ call strcpy (Memc[str+1],
+ Memc[AP_TITLE(Memi[aps+current-1])], SZ_APTITLE)
+ }
+ }
+
+ } else {
+ Memc[wrd+j-1] = EOS
+ switch (Memc[wrd+j]) {
+ case 'b':
+ call gargb (bval)
+ if (nscan() < 2) {
+ call printf ("%s %b")
+ call pargstr (Memc[wrd])
+ call pargb (apgetb (Memc[wrd]))
+ statline = YES
+ } else
+ call apputb (Memc[wrd], bval)
+ case 'i':
+ call gargi (ival)
+ if (nscan() < 2) {
+ call printf ("%s %d")
+ call pargstr (Memc[wrd])
+ call pargi (apgeti (Memc[wrd]))
+ statline = YES
+ } else
+ call apputi (Memc[wrd], ival)
+ case 'r':
+ call gargr (rval)
+ if (nscan() < 2) {
+ call printf ("%s %g")
+ call pargstr (Memc[wrd])
+ call pargr (apgetr (Memc[wrd]))
+ statline = YES
+ } else
+ call apputr (Memc[wrd], rval)
+ case 's':
+ call gargwrd (Memc[str], SZ_LINE)
+ if (nscan() < 2) {
+ call apgstr (Memc[wrd], Memc[str], SZ_LINE)
+ call printf ("%s %s")
+ call pargstr (Memc[wrd])
+ call pargstr (Memc[str])
+ statline = YES
+ } else
+ call appstr (Memc[wrd], Memc[str])
+ }
+ }
+
+done_ call sfree (sp)
+
+end
diff --git a/noao/twodspec/apextract/apcopy.x b/noao/twodspec/apextract/apcopy.x
new file mode 100644
index 00000000..e697bf88
--- /dev/null
+++ b/noao/twodspec/apextract/apcopy.x
@@ -0,0 +1,28 @@
+include "apertures.h"
+
+# AP_COPY -- Make a copy of an aperture.
+# The title is not copied.
+
+procedure ap_copy (apin, apout)
+
+pointer apin # Aperture to copy
+pointer apout # New copy
+
+int i
+
+begin
+ # Allocate memory, transfer the aperture parameters, and call procedures
+ # which copy the offset curve and background parameters.
+ call ap_alloc (apout)
+ AP_ID(apout) = AP_ID(apin)
+ AP_BEAM(apout) = AP_BEAM(apin)
+ AP_AXIS(apout) = AP_AXIS(apin)
+ do i = 1, 2 {
+ AP_CEN(apout, i) = AP_CEN(apin, i)
+ AP_LOW(apout, i) = AP_LOW(apin, i)
+ AP_HIGH(apout, i) = AP_HIGH(apin, i)
+ }
+ call ap_cvset (apin, apout)
+ call ic_open (AP_IC(apout))
+ call ic_copy (AP_IC(apin), AP_IC(apout))
+end
diff --git a/noao/twodspec/apextract/apcveval.x b/noao/twodspec/apextract/apcveval.x
new file mode 100644
index 00000000..09e5beb5
--- /dev/null
+++ b/noao/twodspec/apextract/apcveval.x
@@ -0,0 +1,19 @@
+include <math/curfit.h>
+
+# AP_CVEVAL -- Interface to CVEVAL that avoids extrapolation.
+# This is necessary because if the tracing was truncated due to loss
+# of the profile the trace limits will be smaller than the image axis.
+# In the longer term the aperture limits along the dispersion should be
+# used to limit the extent of the spectrum.
+
+real procedure ap_cveval (cv, x)
+
+pointer cv #I CURFIT pointer
+real x #I Point to be evaluated.
+
+real x1, cvstatr(), cveval()
+
+begin
+ x1 = min (max (x, cvstatr(cv,CVXMIN)), cvstatr(cv,CVXMAX))
+ return (cveval (cv, x1))
+end
diff --git a/noao/twodspec/apextract/apcvset.x b/noao/twodspec/apextract/apcvset.x
new file mode 100644
index 00000000..656187d5
--- /dev/null
+++ b/noao/twodspec/apextract/apcvset.x
@@ -0,0 +1,47 @@
+include <math/curfit.h>
+include "apertures.h"
+
+# AP_CVSET -- Set the trace curve.
+# If the input template aperture is NULL then the output trace curve
+# is set to a constant zero otherwise a copy from the input template
+# aperture is made.
+
+procedure ap_cvset (apin, apout)
+
+pointer apin # Input template aperture
+pointer apout # Output aperture
+
+int apaxis, dispaxis, ncoeffs
+real a, b, c[1]
+pointer sp, coeffs
+
+int cvstati()
+
+begin
+ if (AP_CV(apout) != NULL)
+ call cvfree (AP_CV(apout))
+
+ if (apin == NULL) {
+ # Determine the aperture and alternate axes.
+ apaxis = AP_AXIS(apout)
+ dispaxis = mod (apaxis, 2) + 1
+
+ # Determine the limits over which the curve is defined.
+ a = AP_CEN(apout, dispaxis) + AP_LOW(apout, dispaxis)
+ b = AP_CEN(apout, dispaxis) + AP_HIGH(apout, dispaxis)
+ if (a == b)
+ b = b + 1
+
+ # Set the curve to a legendre polynomial of order 1 and value 0.
+ c[1] = 0.
+ call cvset (AP_CV(apout), LEGENDRE, a, b, c, 1)
+ } else {
+ # Use a SAVE and RESTORE to copy the CURFIT data.
+ call smark (sp)
+ ncoeffs = cvstati (AP_CV(apin), CVNSAVE)
+ call salloc (coeffs, ncoeffs, TY_REAL)
+ call cvsave (AP_CV(apin), Memr[coeffs])
+ call cvrestore (AP_CV(apout), Memr[coeffs])
+ call sfree (sp)
+ }
+end
diff --git a/noao/twodspec/apextract/apdb.x b/noao/twodspec/apextract/apdb.x
new file mode 100644
index 00000000..8bfb5244
--- /dev/null
+++ b/noao/twodspec/apextract/apdb.x
@@ -0,0 +1,314 @@
+include <math/curfit.h>
+include <pkg/dttext.h>
+include "apertures.h"
+
+# AP_DBWRITE -- Write aperture data to the database. The database is obtained
+# with a CL query.
+
+procedure ap_dbwrite (image, aps, naps)
+
+char image[ARB] # Image
+pointer aps # Apertures
+int naps
+
+int i, j, ncoeffs
+pointer sp, database, str, dt, coeffs, ap
+
+int cvstati(), ic_geti()
+real ic_getr()
+bool strne()
+pointer dtmap1()
+
+errchk dtmap1
+
+begin
+ # Set the aperture database file name and map as a NEW_FILE.
+ # The file name is "ap" appended with the image name with the
+ # special image section characters replaced by '_'.
+ # The reason for making image sections separate database
+ # files rather than combining all database entries for an image
+ # in one file is that then previous entries can be deleted
+ # by using NEW_FILE mode which deletes any existing database
+ # file before writing out the new apertures.
+
+ call smark (sp)
+ call salloc (database, SZ_FNAME, TY_CHAR)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ call clgstr ("database", Memc[database], SZ_FNAME)
+ if ((Memc[database] == EOS) || (image[1] == EOS)) {
+ call sfree (sp)
+ return
+ }
+
+ # Map the database file name replacing special characters with '_'.
+ call sprintf (Memc[str], SZ_LINE, "ap%s")
+ call pargstr (image)
+ for (i=str; Memc[i] != EOS; i = i + 1)
+ switch (Memc[i]) {
+ case '[', ':', ',',']','*',' ', '/':
+ Memc[i] = '_'
+ }
+ dt = dtmap1 (Memc[database], Memc[str], NEW_FILE)
+
+ # Write aperture entries for all apertures.
+ for (j = 0; j < naps; j = j + 1) {
+ ap = Memi[aps+j]
+
+ call dtptime (dt)
+ call dtput (dt, "begin\taperture %s %d %g %g\n")
+ call pargstr (image)
+ call pargi (AP_ID(ap))
+ call pargr (AP_CEN(ap, 1))
+ call pargr (AP_CEN(ap, 2))
+ if (AP_TITLE(ap) != NULL) {
+ call dtput (dt, "\ttitle\t%s\n")
+ call pargstr (Memc[AP_TITLE(ap)])
+ }
+ call dtput (dt, "\timage\t%s\n")
+ call pargstr (image)
+ call dtput (dt, "\taperture\t%d\n")
+ call pargi (AP_ID(ap))
+ call dtput (dt, "\tbeam\t%d\n")
+ call pargi (AP_BEAM(ap))
+ call dtput (dt, "\tcenter\t%g %g\n")
+ call pargr (AP_CEN(ap, 1))
+ call pargr (AP_CEN(ap, 2))
+ call dtput (dt, "\tlow\t%g %g\n")
+ call pargr (AP_LOW(ap, 1))
+ call pargr (AP_LOW(ap, 2))
+ call dtput (dt, "\thigh\t%g %g\n")
+ call pargr (AP_HIGH(ap, 1))
+ call pargr (AP_HIGH(ap, 2))
+ if (AP_IC(ap) != NULL) {
+ call dtput (dt, "\tbackground\n")
+ call dtput (dt, "\t\txmin %g\n")
+ call pargr (ic_getr (AP_IC(ap), "xmin"))
+ call dtput (dt, "\t\txmax %g\n")
+ call pargr (ic_getr (AP_IC(ap), "xmax"))
+ call dtput (dt, "\t\tfunction %s\n")
+ call ic_gstr (AP_IC(ap), "function", Memc[str], SZ_LINE)
+ call pargstr (Memc[str])
+ call dtput (dt, "\t\torder %d\n")
+ call pargi (ic_geti (AP_IC(ap), "order"))
+ call dtput (dt, "\t\tsample %s\n")
+ call ic_gstr (AP_IC(ap), "sample", Memc[str], SZ_LINE)
+ call pargstr (Memc[str])
+ call dtput (dt, "\t\tnaverage %d\n")
+ call pargi (ic_geti (AP_IC(ap), "naverage"))
+ call dtput (dt, "\t\tniterate %d\n")
+ call pargi (ic_geti (AP_IC(ap), "niterate"))
+ call dtput (dt, "\t\tlow_reject %g\n")
+ call pargr (ic_getr (AP_IC(ap), "low"))
+ call dtput (dt, "\t\thigh_reject %g\n")
+ call pargr (ic_getr (AP_IC(ap), "high"))
+ call dtput (dt, "\t\tgrow %g\n")
+ call pargr (ic_getr (AP_IC(ap), "grow"))
+ }
+
+ # Write out the curve.
+ call dtput (dt, "\taxis\t%d\n")
+ call pargi (AP_AXIS(ap))
+ ncoeffs = cvstati (AP_CV(ap), CVNSAVE)
+ call malloc (coeffs, ncoeffs, TY_REAL)
+ call cvsave (AP_CV(ap), Memr[coeffs])
+ call dtput (dt, "\tcurve\t%d\n")
+ call pargi (ncoeffs)
+ do i = 1, ncoeffs {
+ call dtput (dt, "\t\t%g\n")
+ call pargr (Memr[coeffs+i-1])
+ }
+ call mfree (coeffs, TY_REAL)
+
+ call dtput (dt, "\n")
+ }
+ call dtunmap (dt)
+
+ # Log the write operation unless the output file is "last".
+ if (strne (image, "last")) {
+ call sprintf (Memc[str], SZ_LINE,
+ "DATABASE - %d apertures for %s written to %s")
+ call pargi (naps)
+ call pargstr (image)
+ call pargstr (Memc[database])
+ call ap_log (Memc[str], YES, YES, NO)
+ call appstr ("ansdbwrite1", "no")
+ }
+
+ call sfree (sp)
+end
+
+
+# AP_DBREAD - Get aperture information from the database.
+# If no apertures are found then the input apertures are unchanged.
+# The database is obtained with a CL query.
+
+procedure ap_dbread (image, aps, naps)
+
+char image[ARB] # Image
+pointer aps # Apertures
+int naps # Number of apertures
+
+int i, j, n, ncoeffs
+pointer sp, database, str, ap, dt, coeffs
+
+bool strne()
+int dtgeti()
+real dtgetr()
+pointer dtmap1()
+
+errchk dtmap1
+
+begin
+ # Return if the database or image are undefined.
+ call smark (sp)
+ call salloc (database, SZ_FNAME, TY_CHAR)
+ call clgstr ("database", Memc[database], SZ_FNAME)
+
+ if ((Memc[database] == EOS) || (image[1] == EOS)) {
+ call sfree (sp)
+ return
+ }
+
+ # Set the aperture database file name and map it.
+ # The file name is "ap" appended with the image name with the
+ # special image section characters replaced by '_'.
+ call salloc (str, SZ_LINE, TY_CHAR)
+ call sprintf (Memc[str], SZ_LINE, "ap%s")
+ call pargstr (image)
+ for (i=str; Memc[i] != EOS; i = i + 1)
+ switch (Memc[i]) {
+ case '[', ':', ',',']','*',' ', '/':
+ Memc[i] = '_'
+ }
+
+ # If an error occurs return the error.
+ dt = dtmap1 (Memc[database], Memc[str], READ_ONLY)
+
+ # Read through the database finding records matching the input image.
+ n = naps
+ naps = 0
+ do i = 1, DT_NRECS(dt) {
+
+ call dtgstr (dt, i, "image", Memc[str], SZ_LINE)
+ if (strne (Memc[str], image))
+ next
+
+ # If an aperture is found delete any input apertures.
+ if (naps == 0)
+ for (j = 0; j < n; j = j + 1)
+ call ap_free (Memi[aps+j])
+
+ if (mod (naps, 100) == 0)
+ call realloc (aps, naps+100, TY_POINTER)
+
+ call ap_alloc (ap)
+ ifnoerr (call dtgstr (dt, i, "title", Memc[str], SZ_LINE)) {
+ call malloc (AP_TITLE(ap), SZ_APTITLE, TY_CHAR)
+ call strcpy (Memc[str], Memc[AP_TITLE(ap)], SZ_APTITLE)
+ }
+ AP_ID(ap) = dtgeti (dt, i, "aperture")
+ iferr (AP_BEAM(ap) = dtgeti (dt, i, "beam"))
+ AP_BEAM(ap) = AP_ID(ap)
+ call dtgstr (dt, i, "center", Memc[str], SZ_LINE)
+ call sscan (Memc[str])
+ call gargr (AP_CEN(ap, 1))
+ call gargr (AP_CEN(ap, 2))
+ call dtgstr (dt, i, "low", Memc[str], SZ_LINE)
+ call sscan (Memc[str])
+ call gargr (AP_LOW(ap, 1))
+ call gargr (AP_LOW(ap, 2))
+ call dtgstr (dt, i, "high", Memc[str], SZ_LINE)
+ call sscan (Memc[str])
+ call gargr (AP_HIGH(ap, 1))
+ call gargr (AP_HIGH(ap, 2))
+ ifnoerr (call dtgstr (dt, i, "background", Memc[str], SZ_LINE)) {
+ call ic_open (AP_IC(ap))
+ call ic_putr (AP_IC(ap), "xmin", dtgetr (dt, i, "xmin"))
+ call ic_putr (AP_IC(ap), "xmax", dtgetr (dt, i, "xmax"))
+ call dtgstr (dt, i, "function", Memc[str], SZ_LINE)
+ call ic_pstr (AP_IC(ap), "function", Memc[str])
+ call ic_puti (AP_IC(ap), "order", dtgeti (dt, i, "order"))
+ call dtgstr (dt, i, "sample", Memc[str], SZ_LINE)
+ call ic_pstr (AP_IC(ap), "sample", Memc[str])
+ call ic_puti (AP_IC(ap), "naverage", dtgeti (dt, i, "naverage"))
+ call ic_puti (AP_IC(ap), "niterate", dtgeti (dt, i, "niterate"))
+ call ic_putr (AP_IC(ap), "low", dtgetr (dt, i, "low_reject"))
+ call ic_putr (AP_IC(ap), "high", dtgetr (dt, i, "high_reject"))
+ call ic_putr (AP_IC(ap), "grow", dtgetr (dt, i, "grow"))
+ }
+
+ AP_AXIS(ap) = dtgeti (dt, i, "axis")
+ ncoeffs = dtgeti (dt, i, "curve")
+ call malloc (coeffs, ncoeffs, TY_REAL)
+ call dtgar (dt, i, "curve", Memr[coeffs], ncoeffs, ncoeffs)
+ call cvrestore (AP_CV(ap), Memr[coeffs])
+ call mfree (coeffs, TY_REAL)
+
+ Memi[aps+naps] = ap
+ naps = naps + 1
+ }
+ call dtunmap (dt)
+
+ # Log the read operation.
+ call sprintf (Memc[str], SZ_LINE,
+ "DATABASE - %d apertures read for %s from %s")
+ call pargi (naps)
+ call pargstr (image)
+ call pargstr (Memc[database])
+ call ap_log (Memc[str], YES, YES, NO)
+
+ # If no apertures were found then reset the number to the input value.
+ if (naps == 0)
+ naps = n
+ else
+ call appstr ("ansdbwrite1", "no")
+
+ call sfree (sp)
+end
+
+
+# AP_DBACCESS - Check if a database file can be accessed.
+# This does not check the contents of the file.
+# The database is obtained with a CL query.
+
+int procedure ap_dbaccess (image)
+
+char image[ARB] # Image
+int access # Database file access?
+
+int i
+pointer sp, database, str, dt
+pointer dtmap1()
+errchk dtmap1
+
+begin
+ call smark (sp)
+ call salloc (database, SZ_FNAME, TY_CHAR)
+ call clgstr ("database", Memc[database], SZ_FNAME)
+
+ if ((Memc[database] != EOS) && (image[1] != EOS)) {
+ # Set the aperture database file name and map it.
+ # The file name is "ap" appended with the image name with the
+ # special image section characters replaced by '_'.
+ call salloc (str, SZ_LINE, TY_CHAR)
+ call sprintf (Memc[str], SZ_LINE, "ap%s")
+ call pargstr (image)
+ for (i=str; Memc[i] != EOS; i = i + 1)
+ switch (Memc[i]) {
+ case '[', ':', ',',']','*',' ', '/':
+ Memc[i] = '_'
+ }
+
+ iferr {
+ dt = dtmap1 (Memc[database], Memc[str], READ_ONLY)
+ call dtunmap (dt)
+ access = YES
+ } then
+ access = NO
+ } else
+ access = NO
+
+ call sfree (sp)
+ return (access)
+end
diff --git a/noao/twodspec/apextract/apdebug.par b/noao/twodspec/apextract/apdebug.par
new file mode 100644
index 00000000..6b9fc8f9
--- /dev/null
+++ b/noao/twodspec/apextract/apdebug.par
@@ -0,0 +1,156 @@
+dispaxis = 2
+database = "database"
+verbose = yes
+logfile = "logfile"
+plotfile = " "
+
+apall1.input =
+apall1.nfind =
+apall1.output = ""
+apall1.apertures = ""
+apall1.format = "multispec"
+apall1.references = ""
+apall1.profiles = ""
+apall1.interactive = yes
+apall1.find = yes
+apall1.recenter = no
+apall1.resize = no
+apall1.edit = yes
+apall1.trace = yes
+apall1.fittrace = no
+apall1.extract = yes
+apall1.extras = yes
+apall1.review = no
+apall1.line = INDEF
+apall1.nsum = 10
+apall1.lower = -5.
+apall1.upper = 5.
+apall1.apidtable = ""
+apall1.b_function = "chebyshev"
+apall1.b_order = 1
+apall1.b_sample = "-10:-6,6:10"
+apall1.b_naverage = -3
+apall1.b_niterate = 0
+apall1.b_low_reject = 3.
+apall1.b_high_reject = 3.
+apall1.b_grow = 0.
+apall1.width = 5.
+apall1.radius = 10.
+apall1.threshold = 0.
+apall1.minsep = 5.
+apall1.maxsep = 1000.
+apall1.order = "increasing"
+apall1.aprecenter = ""
+apall1.npeaks = INDEF
+apall1.shift = yes
+apall1.llimit = INDEF
+apall1.ulimit = INDEF
+apall1.ylevel = 0.1
+apall1.peak = yes
+apall1.bkg = yes
+apall1.r_grow = 0.
+apall1.avglimits = no
+apall1.t_nsum = 10
+apall1.t_step = 10
+apall1.t_width = 5.
+apall1.t_nlost = 3
+apall1.t_function = "legendre"
+apall1.t_order = 2
+apall1.t_sample = "*"
+apall1.t_naverage = 1
+apall1.t_niterate = 0
+apall1.t_low_reject = 3.
+apall1.t_high_reject = 3.
+apall1.t_grow = 0.
+apall1.background = "none"
+apall1.skybox = 1
+apall1.weights = "none"
+apall1.pfit = "fit1d"
+apall1.clean = no
+apall1.saturation = INDEF
+apall1.readnoise = "0."
+apall1.gain = "1."
+apall1.lsigma = 4.
+apall1.usigma = 4.
+apall1.nsubaps = 1
+
+apall1.e_output =
+apall1.e_profiles =
+apall1.dbwrite = "yes"
+apall1.initialize = yes
+apall1.nclean = 0.5
+apall1.niterate = 5
+apall1.polysep = 0.90
+apall1.polyorder = 10
+
+apall1.ansclobber = "no"
+apall1.ansclobber1 = "no"
+apall1.ansdbwrite = "yes"
+apall1.ansdbwrite1 = "yes"
+apall1.ansedit = "yes"
+apall1.ansextract = "yes"
+apall1.ansfind = "yes"
+apall1.ansfit = "yes"
+apall1.ansfitscatter = "yes"
+apall1.ansfitsmooth = "yes"
+apall1.ansfitspec = "yes"
+apall1.ansfitspec1 = "yes"
+apall1.ansfittrace = "yes"
+apall1.ansfittrace1 = "yes"
+apall1.ansflat = "yes"
+apall1.ansnorm = "yes"
+apall1.ansrecenter = "yes"
+apall1.ansresize = "yes"
+apall1.ansreview = "yes"
+apall1.ansreview1 = "yes"
+apall1.ansscat = "yes"
+apall1.anssmooth = "yes"
+apall1.anstrace = "yes"
+
+apall1.ansclobber.p_mode = "h"
+apall1.ansclobber1.p_mode = "h"
+apall1.ansdbwrite.p_mode = "h"
+apall1.ansdbwrite1.p_mode = "h"
+apall1.ansedit.p_mode = "h"
+apall1.ansextract.p_mode = "h"
+apall1.ansfind.p_mode = "h"
+apall1.ansfit.p_mode = "h"
+apall1.ansfitscatter.p_mode = "h"
+apall1.ansfitsmooth.p_mode = "h"
+apall1.ansfitspec.p_mode = "h"
+apall1.ansfitspec1.p_mode = "h"
+apall1.ansfittrace.p_mode = "h"
+apall1.ansfittrace1.p_mode = "h"
+apall1.ansflat.p_mode = "h"
+apall1.ansnorm.p_mode = "h"
+apall1.ansrecenter.p_mode = "h"
+apall1.ansresize.p_mode = "h"
+apall1.ansreview.p_mode = "h"
+apall1.ansreview1.p_mode = "h"
+apall1.ansscat.p_mode = "h"
+apall1.anssmooth.p_mode = "h"
+apall1.anstrace.p_mode = "h"
+
+apall1.ansclobber.p_prompt = "h"
+apall1.ansclobber1.p_prompt = "h"
+apall1.ansdbwrite.p_prompt = "h"
+apall1.ansdbwrite1.p_prompt = "h"
+apall1.ansedit.p_prompt = "h"
+apall1.ansextract.p_prompt = "h"
+apall1.ansfind.p_prompt = "h"
+apall1.ansfit.p_prompt = "h"
+apall1.ansfitscatter.p_prompt = "h"
+apall1.ansfitsmooth.p_prompt = "h"
+apall1.ansfitspec.p_prompt = "h"
+apall1.ansfitspec1.p_prompt = "h"
+apall1.ansfittrace.p_prompt = "h"
+apall1.ansfittrace1.p_prompt = "h"
+apall1.ansflat.p_prompt = "h"
+apall1.ansnorm.p_prompt = "h"
+apall1.ansrecenter.p_prompt = "h"
+apall1.ansresize.p_prompt = "h"
+apall1.ansreview.p_prompt = "h"
+apall1.ansreview1.p_prompt = "h"
+apall1.ansscat.p_prompt = "h"
+apall1.anssmooth.p_prompt = "h"
+apall1.anstrace.p_prompt = "h"
diff --git a/noao/twodspec/apextract/apdefault.par b/noao/twodspec/apextract/apdefault.par
new file mode 100644
index 00000000..7868197c
--- /dev/null
+++ b/noao/twodspec/apextract/apdefault.par
@@ -0,0 +1,14 @@
+# APDEFAULT
+
+lower,r,h,-5.,,,Lower aperture limit relative to center
+upper,r,h,5.,,,Upper aperture limit relative to center
+apidtable,s,h,"",,,"Aperture ID table
+"
+b_function,s,h,"chebyshev","chebyshev|legendre|spline1|spline3",,Background function
+b_order,i,h,1,1,,Background function order
+b_sample,s,h,"-10:-6,6:10",,,Background sample regions
+b_naverage,i,h,-3,,,Background average or median
+b_niterate,i,h,0,0,,Background rejection iterations
+b_low_reject,r,h,3.,0.,,Background lower rejection sigma
+b_high_reject,r,h,3.,0.,,Background upper rejection sigma
+b_grow,r,h,0.,0.,,Background rejection growing radius
diff --git a/noao/twodspec/apextract/apdefault.x b/noao/twodspec/apextract/apdefault.x
new file mode 100644
index 00000000..bea10f7c
--- /dev/null
+++ b/noao/twodspec/apextract/apdefault.x
@@ -0,0 +1,42 @@
+include <imhdr.h>
+include "apertures.h"
+
+# AP_DEFAULT -- Create a default aperture.
+# The aperture ID, beam, axis, and the aperture center in both dimensions
+# are specified. The aperture limits along the dispersion axis are set to
+# the full size of the image while along the dispersion axis they are queried.
+# The default offset curve is a constant zero curve.
+
+procedure ap_default (im, apid, apbeam, apaxis, apcenter, dispcenter, ap)
+
+pointer im # IMIO pointer
+int apid # Aperture ID
+int apbeam # Aperture beam number
+int apaxis # Aperture axis
+real apcenter # Center along the aperture axis
+real dispcenter # Center along the dispersion axis
+pointer ap # Aperture pointer
+
+int dispaxis
+real apgetr()
+
+begin
+ dispaxis = mod (apaxis, 2) + 1
+
+ call ap_alloc (ap)
+ AP_ID(ap) = apid
+ AP_BEAM(ap) = apbeam
+ AP_AXIS(ap) = apaxis
+ AP_CEN(ap, apaxis) = apcenter
+ AP_LOW(ap, apaxis) = apgetr ("lower")
+ if (IS_INDEFR(AP_LOW(ap,apaxis)))
+ call error (1, "INDEF not allowed (lower)")
+ AP_HIGH(ap, apaxis) = apgetr ("upper")
+ if (IS_INDEFR(AP_HIGH(ap,apaxis)))
+ call error (1, "INDEF not allowed (upper)")
+ AP_CEN(ap, dispaxis) = dispcenter
+ AP_LOW(ap, dispaxis) = 1 - AP_CEN(ap, dispaxis)
+ AP_HIGH(ap, dispaxis) = IM_LEN(im, dispaxis) - AP_CEN(ap, dispaxis)
+ call ap_cvset (NULL, ap)
+ call ap_icset (NULL, ap, IM_LEN(im, apaxis))
+end
diff --git a/noao/twodspec/apextract/apdelete.x b/noao/twodspec/apextract/apdelete.x
new file mode 100644
index 00000000..1956a331
--- /dev/null
+++ b/noao/twodspec/apextract/apdelete.x
@@ -0,0 +1,23 @@
+# AP_DELETE -- Delete the specified aperture and return a new current aperture.
+
+procedure ap_delete (current, aps, naps)
+
+int current # Return current aperture index
+pointer aps[ARB] # Aperture data
+int naps # Number of apertures
+
+int i
+
+begin
+ if (current < 1)
+ return
+
+ call ap_free (aps[current])
+ for (i = current; i < naps; i = i + 1)
+ aps[i] = aps[i+1]
+
+ aps[naps] = NULL
+
+ naps = naps - 1
+ current = min (naps, current)
+end
diff --git a/noao/twodspec/apextract/apdemos/apdemo1.cl b/noao/twodspec/apextract/apdemos/apdemo1.cl
new file mode 100644
index 00000000..04704034
--- /dev/null
+++ b/noao/twodspec/apextract/apdemos/apdemo1.cl
@@ -0,0 +1,14 @@
+# Create demo data if needed.
+artdata
+mkexample ("multifiber", "apdemo", errors=no, verbose=yes, list=no)
+bye
+imdelete ("apdemo.ms.??h", verify=no)
+
+# Set parameters.
+verbose = yes
+logfile = ""
+plotfile = ""
+unlearn apall
+
+# Execute playback.
+stty (playback="apdemos$apdemo1.dat", verify=no, delay=500)
diff --git a/noao/twodspec/apextract/apdemos/apdemo1.dat b/noao/twodspec/apextract/apdemos/apdemo1.dat
new file mode 100644
index 00000000..c718b423
--- /dev/null
+++ b/noao/twodspec/apextract/apdemos/apdemo1.dat
@@ -0,0 +1,14 @@
+\O=NOAO/IRAF V2.10DEVELOP valdes@puppis Tue 13:26:44 31-Jul-90
+\T=gterm
+\G=gterm
+apall\n
+apdemo\n
+\n
+4\n
+\n
+no\n
+\n
+no\n
+no\n
+\n
+no\n
diff --git a/noao/twodspec/apextract/apdemos/apdemos.cl b/noao/twodspec/apextract/apdemos/apdemos.cl
new file mode 100644
index 00000000..3b040ef7
--- /dev/null
+++ b/noao/twodspec/apextract/apdemos/apdemos.cl
@@ -0,0 +1,17 @@
+procedure apdemos (demo)
+
+int demo {prompt="Demo number"}
+
+begin
+ int demonum
+ file demofile
+
+ if ($nargs == 0)
+ type ("apdemos$apdemos.men")
+ demonum = demo
+ demofile = "apdemos$apdemo" // demonum // ".cl"
+ if (access (demofile))
+ cl (< demofile)
+ else
+ error (1, "Invalid demo number " // demonum)
+end
diff --git a/noao/twodspec/apextract/apdemos/apdemos.men b/noao/twodspec/apextract/apdemos/apdemos.men
new file mode 100644
index 00000000..4e0ca6e1
--- /dev/null
+++ b/noao/twodspec/apextract/apdemos/apdemos.men
@@ -0,0 +1,3 @@
+ MENU of APEXTRACT Demonstrations
+
+ 1 - Simple demo of APALL
diff --git a/noao/twodspec/apextract/apdemos/apdemosdb/aplast b/noao/twodspec/apextract/apdemos/apdemosdb/aplast
new file mode 100644
index 00000000..93f85ea9
--- /dev/null
+++ b/noao/twodspec/apextract/apdemos/apdemosdb/aplast
@@ -0,0 +1,111 @@
+# Wed 11:02:05 22-Aug-90
+begin aperture last 1 60.57419 256.
+ image last
+ aperture 1
+ beam 1
+ center 60.57419 256.
+ low -3.111816 -255.
+ high 2.949428 256.
+ background
+ xmin -100.
+ xmax 100.
+ function chebyshev
+ order 1
+ sample -10:-6,6:10
+ naverage -3
+ niterate 0
+ low_reject 3.
+ high_reject 3.
+ grow 0.
+ axis 1
+ curve 6
+ 2.
+ 2.
+ 1.
+ 512.
+ 0.02659256
+ 0.5026957
+
+# Wed 11:02:05 22-Aug-90
+begin aperture last 2 70.70531 256.
+ image last
+ aperture 2
+ beam 2
+ center 70.70531 256.
+ low -2.926423 -255.
+ high 2.899426 256.
+ background
+ xmin -100.
+ xmax 100.
+ function chebyshev
+ order 1
+ sample -10:-6,6:10
+ naverage -3
+ niterate 0
+ low_reject 3.
+ high_reject 3.
+ grow 0.
+ axis 1
+ curve 6
+ 2.
+ 2.
+ 1.
+ 512.
+ -0.002646168
+ 0.5073752
+
+# Wed 11:02:05 22-Aug-90
+begin aperture last 3 80.78613 256.
+ image last
+ aperture 3
+ beam 3
+ center 80.78613 256.
+ low -2.953142 -255.
+ high 2.970872 256.
+ background
+ xmin -100.
+ xmax 100.
+ function chebyshev
+ order 1
+ sample -10:-6,6:10
+ naverage -3
+ niterate 0
+ low_reject 3.
+ high_reject 3.
+ grow 0.
+ axis 1
+ curve 6
+ 2.
+ 2.
+ 1.
+ 512.
+ 0.01349655
+ 0.5075101
+
+# Wed 11:02:05 22-Aug-90
+begin aperture last 4 90.8806 256.
+ image last
+ aperture 4
+ beam 4
+ center 90.8806 256.
+ low -2.823333 -255.
+ high 2.915152 256.
+ background
+ xmin -100.
+ xmax 100.
+ function chebyshev
+ order 1
+ sample -10:-6,6:10
+ naverage -3
+ niterate 0
+ low_reject 3.
+ high_reject 3.
+ grow 0.
+ axis 1
+ curve 6
+ 2.
+ 2.
+ 1.
+ 512.
+ 0.022075
+ 0.5081324
diff --git a/noao/twodspec/apextract/apedit.key b/noao/twodspec/apextract/apedit.key
new file mode 100644
index 00000000..d28a8856
--- /dev/null
+++ b/noao/twodspec/apextract/apedit.key
@@ -0,0 +1,74 @@
+ APEXTRACT CURSOR KEY SUMMARY
+
+? Print help j Set beam number u Set upper limit(s)
+a Toggle all flag l Set lower limit(s) w Window graph
+b Set background(s) m Mark aperture y Y level limit(s)
+c Center aperture(s) n New uncentered ap. z Resize aperture(s)
+d Delete aperture(s) o Order ap. numbers I Interrupt
+e Extract spectra q Quit + Next aperture
+f Find apertures r Redraw graph - Previous aperture
+g Recenter aperture(s) s Shift aperture(s) . Nearest aperture
+i Set aperture ID t Trace aperture(s)
+
+ APEXTRACT COLON COMMAND SUMMARY
+
+:apertures :center :npeaks :show :t_width
+:apidtable :clean :nsubaps :skybox :threshold
+:avglimits :database :nsum :t_function :title
+:b_function :extras :order :t_grow :ulimit
+:b_grow :gain :parameters :t_high_reject :upper
+:b_high_reject :image :peak :t_low_reject :usigma
+:b_low_reject :line :plotfile :t_naverage :weights
+:b_naverage :llimit :r_grow :t_niterate :width
+:b_niterate :logfile :radius :t_nlost :write
+:b_order :lower :read :t_nsum :ylevel
+:b_sample :lsigma :readnoise :t_order
+:background :maxsep :saturation :t_sample
+:bkg :minsep :shift :t_step
+
+ APEXTRACT CURSOR KEYS
+
+? Print help
+a Toggle the ALL flag
+b an Set background fitting parameters
+c an Center aperture(s)
+d an Delete aperture(s)
+e an Extract spectra (see APSUM)
+f Find apertures up to the requested number (see APFIND)
+g an Recenter aperture(s) (see APRECENTER)
+i n Set aperture ID
+j n Set aperture beam number
+l ac Set lower limit of current aperture at cursor position
+m Define and center a new aperture on the profile near the cursor
+n Define a new aperture centered at the cursor
+o n Enter desired aperture number for cursor selected aperture and remaining
+ apertures are reordered using apidtable and maxsep parameters
+ (see APFIND for ordering algorithm)
+q Quit
+r Redraw the graph
+s an Shift the center(s) of the current aperture to the cursor position
+t ac Trace aperture positions (see APTRACE)
+u ac Set upper limit of current aperture at cursor position
+w Window the graph using the window cursor keys
+y an Set aperture limits to intercept the data at the cursor y position
+z an Resize aperture(s) (see APRESIZE)
+. n Select the aperture nearest the cursor to be the current aperture
++ c Select the next aperture (in ID) to be the current aperture
+- c Select the previous aperture (in ID) to be the current aperture
+I Interrupt task immediately. Database information is not saved.
+
+The letter a following the key indicates if all apertures are affected when
+the ALL flag is set. The letter c indicates that the key affects the
+current aperture while the letter n indicates that the key affects the
+aperture whose center is nearest the cursor.
+
+ APEXTRACT COLON COMMANDS
+
+:show [file] Print a list of the apertures (default file is STDOUT)
+:parameters [file] Print current parameter values (default file is STDOUT)
+:read [name] Read apertures from database (default to the current image)
+:write [name] Write apertures to database (default to the current image)
+
+The remaining colon commands are task parameters and print the current
+value if no value is given or reset the current value to that specified.
+Use :parameters to see current parameter values.
diff --git a/noao/twodspec/apextract/apedit.par b/noao/twodspec/apextract/apedit.par
new file mode 100644
index 00000000..8e6c15f5
--- /dev/null
+++ b/noao/twodspec/apextract/apedit.par
@@ -0,0 +1,17 @@
+# APEDIT
+
+input,s,a,,,,List of input images to edit
+apertures,s,h,"",,,Apertures
+references,s,h,"",,,"Reference images
+"
+interactive,b,h,yes,,,Run task interactively?
+find,b,h,no,,,Find apertures?
+recenter,b,h,no,,,Recenter apertures?
+resize,b,h,no,,,Resize apertures?
+edit,b,h,yes,,,"Edit apertures?
+"
+line,i,h,INDEF,1,,Dispersion line
+nsum,i,h,10,,,Number of dispersion lines to sum or median
+width,r,h,5.,0.,,Profile centering width
+radius,r,h,10.,,,Profile centering radius
+threshold,r,h,0.,0.,,Detection threshold for profile centering
diff --git a/noao/twodspec/apextract/apedit.x b/noao/twodspec/apextract/apedit.x
new file mode 100644
index 00000000..e7170e92
--- /dev/null
+++ b/noao/twodspec/apextract/apedit.x
@@ -0,0 +1,604 @@
+include <error.h>
+include <gset.h>
+include <imhdr.h>
+include <mach.h>
+include <pkg/gtools.h>
+include "apertures.h"
+
+define HELP "noao$twodspec/apextract/apedit.key"
+define PROMPT "apextract options"
+
+# Sort flags
+define ORDER "|increasing|decreasing|"
+
+# AP_EDIT -- Define and edit apertures. This is the main interactive
+# procedure for manipulating apertures. The selected dispersion line
+# is graphed with possible summing of neighboring lines and then
+# cursor keys are used to define new apertures or edit existing apertures.
+# Note that the value of line may be changed.
+
+procedure ap_edit (image, line, nsum, aps, naps)
+
+char image[SZ_FNAME] # Image to be edited
+int line # Dispersion line
+int nsum # Number of dispersion lines to sum
+
+pointer aps # Aperture pointers
+int naps # Number of apertures
+
+char cmd[SZ_LINE]
+int i, npts, apaxis, dispaxis, statline
+int current, newgraph, newim, newdata, all, wcs, key, apid, apbeam
+real center, low, high, wx, wy
+bool peak
+pointer im, imdata, title
+pointer sp, x, wts, apdef, gp, gt, ic_gt, cv, str, output, profiles, ids
+
+int gt_gcur(), apgwrd(), scan(), nscan()
+real ap_cveval(), ap_center()
+bool ap_answer()
+pointer gt_init()
+errchk ap_getdata, ap_gopen, ap_default
+
+define new_ 10
+define beep_ 99
+
+begin
+ # Query user.
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+ call sprintf (Memc[str], SZ_LINE, "Edit apertures for %s?")
+ call pargstr (image)
+ if (!ap_answer ("ansedit", Memc[str])) {
+ call sfree (sp)
+ return
+ }
+
+ # Set flags.
+ all = NO
+
+ # Get user aperture ID's
+ call ap_gids (ids)
+
+ # Map the image and get the image data.
+new_ call ap_getdata (image, line, nsum, im, imdata, npts, apaxis, title)
+ newdata = NO
+ newim = NO
+
+ # Allocate additional memory.
+ call salloc (x, npts, TY_REAL)
+ call salloc (wts, npts, TY_REAL)
+ call salloc (output, SZ_FNAME, TY_CHAR)
+ call salloc (profiles, SZ_FNAME, TY_CHAR)
+
+ # Set the default aperture and delete apertures which do not have
+ # the correct aperture axis.
+ call ap_default (im, INDEFI, 1, apaxis, INDEFR, real (line), apdef)
+ dispaxis = mod (apaxis, 2) + 1
+ for (i = naps; i > 0; i = i - 1)
+ if (AP_AXIS(Memi[aps+i-1]) != apaxis)
+ call ap_delete (i, Memi[aps], naps)
+
+ # Set up the graphics.
+ call ap_gopen (gp)
+ gt = gt_init()
+ call gt_sets (gt, GTTITLE, "Define and Edit Apertures")
+ call gt_sets (gt, GTPARAMS, Memc[title])
+
+ # Enter cursor loop.
+ current = min (1, naps)
+ key = 'r'
+ wy = INDEF
+ repeat {
+ statline = NO
+
+ # For those keys affecting the nearest aperture set the current
+ # aperture to be the aperture nearest the cursor.
+ switch (key) {
+ case '.','b','c','d','e','g','i','j','o','t','y','z':
+ # The current aperture is the one nearest the cursor.
+ call ap_nearest (current, line, Memi[aps], naps, wx)
+ }
+
+ # Set the current aperture values.
+ call ap_values (current, Memi[aps], line, apid,
+ apbeam, center, low, high)
+
+ # Select the operation to be performed.
+ switch (key) {
+ case '?': # Print help text.
+ call gpagefile (gp, HELP, PROMPT)
+
+ case ':': # Colon commands.
+ if (cmd[1] == '/')
+ call gt_colon (cmd, gp, gt, newgraph)
+ else {
+ call ap_colon (cmd, im, gp, apdef, aps, naps, current,
+ image, line, nsum, all, newgraph, newim, newdata,
+ statline)
+ if (newim == YES)
+ break
+ if (newdata == YES) {
+ call mfree (imdata, TY_REAL)
+ call mfree (title, TY_CHAR)
+ call imunmap (im)
+ call ap_getdata (image, line, nsum, im, imdata, npts,
+ apaxis, title)
+ call gt_sets (gt, GTPARAMS, Memc[title])
+ newdata = NO
+ newgraph = YES
+ }
+ call ap_free (apdef)
+ iferr (call ap_default (im, INDEFI, 1, apaxis, INDEFR,
+ real (line), apdef))
+ call erract (EA_WARN)
+ }
+
+ case '.': # Select current aperture. This has been done already.
+ ;
+
+ case '+': # Go to next aperture.
+ current = min (naps, current + 1)
+
+ case '-': # Go to last aperture.
+ current = min (naps, max (1, current - 1))
+
+ case 'a': # Toggle all flag
+ if (all == NO)
+ all = YES
+ else
+ all = NO
+
+ case 'b': # Set background fitting parameters.
+ if (current == 0)
+ goto beep_
+
+ do i = 1, npts {
+ Memr[x+i-1] = i - center
+ Memr[wts+i-1] = 1
+ }
+
+ if (ic_gt == NULL) {
+ ic_gt = gt_init()
+ call gt_sets (ic_gt, GTTYPE, "line")
+ wx = max (10., high - low)
+ call gt_setr (ic_gt, GTXMIN, low - 2 * wx)
+ call gt_setr (ic_gt, GTXMAX, high + 2 * wx)
+ }
+
+ call sprintf (Memc[str], SZ_LINE,
+ "Set Background Subtraction for Aperture %d")
+ call pargi (apid)
+ call gt_sets (ic_gt, GTTITLE, Memc[str])
+
+ if (AP_IC(Memi[aps+current-1]) == NULL)
+ call ap_icset (apdef, Memi[aps+current-1], npts)
+
+ call icg_fit (AP_IC(Memi[aps+current-1]), gp, "gcur",
+ ic_gt, cv, Memr[x], Memr[imdata], Memr[wts], npts)
+ call cvfree (cv)
+
+ # Set background limits
+ call ap_icset (Memi[aps+current-1], Memi[aps+current-1], npts)
+
+ if ((naps > 1) && (all == YES))
+ do i = 1, naps
+ if (i != current)
+ call ap_icset (Memi[aps+current-1],
+ Memi[aps+i-1], npts)
+ newgraph = YES
+
+ case 'c': # Center current aperture or all apertures.
+ if (current == 0)
+ goto beep_
+
+ if ((naps == 1) || (all == NO)) {
+ center = ap_center (center, Memr[imdata], npts)
+ if (!IS_INDEF(center))
+ call ap_update (gp, Memi[aps+current-1], line, apid,
+ apbeam, center, low, high)
+ } else {
+ do i = 1, naps {
+ call ap_values (i, Memi[aps], line, apid,
+ apbeam, center, low, high)
+ center = ap_center (center, Memr[imdata], npts)
+ if (!IS_INDEF(center))
+ call ap_update (gp, Memi[aps+i-1], line, apid,
+ apbeam, center, low, high)
+ }
+ }
+
+ case 'd': # Delete apertures
+ if (current == 0)
+ goto beep_
+
+ call gseti (gp, G_PLTYPE, 0)
+ if ((naps == 1) || (all == NO)) {
+ call ap_gmark (gp, line, Memi[aps+current-1], 1)
+ call ap_delete (current, Memi[aps], naps)
+ call ap_gscur (current, gp, line, Memi[aps], wy)
+ call ap_values (current, Memi[aps], line, apid,
+ apbeam, center, low, high)
+ } else {
+ do i = 1, naps {
+ call ap_gmark (gp, line, Memi[aps+i-1], 1)
+ call ap_free (Memi[aps+i-1])
+ }
+ naps = 0
+ current = 0
+ }
+ call gseti (gp, G_PLTYPE, 1)
+
+ case 'e': # Sum extraction
+ if (current == 0)
+ goto beep_
+
+ call imunmap (im)
+ call apgstr ("e_output", Memc[output], SZ_FNAME)
+ call apgstr ("e_profiles", Memc[profiles], SZ_FNAME)
+ call apgstr ("format", Memc[str], SZ_LINE)
+ call appstr ("ansreview", "yes")
+ call appstr ("ansreview1", "yes")
+ call appstr ("ansclobber", "yes")
+ call appstr ("ansclobber1", "yes")
+ if (all == NO)
+ call ap_extract (image, Memc[output],
+ Memc[str], Memc[profiles], Memi[aps+current-1], 1)
+ else
+ call ap_extract (image, Memc[output],
+ Memc[str], Memc[profiles], Memi[aps], naps)
+ call ap_getdata (image, line, nsum, im, imdata, npts, apaxis,
+ title)
+ newgraph = YES
+
+ case 'f': # Find apertures
+ if (current == 0)
+ call ap_findnew (line, Memr[imdata], npts,
+ apdef, aps, naps)
+ else
+ call ap_findnew (line, Memr[imdata], npts,
+ Memi[aps+current-1], aps, naps)
+ call ap_gmark (gp, line, Memi[aps], naps)
+ current = naps
+
+ case 'g': # Apply recenter algorithm.
+ if (current == 0)
+ goto beep_
+
+ call imunmap (im)
+ if (all == NO) {
+ call gseti (gp, G_PLTYPE, 0)
+ call ap_gmark (gp, line, Memi[aps+current-1], 1)
+ call ap_recenter (image, line, nsum,
+ Memi[aps+current-1], 1, YES)
+ call gseti (gp, G_PLTYPE, 1)
+ call ap_gmark (gp, line, Memi[aps+current-1], 1)
+ call ap_values (current, Memi[aps], line, apid,
+ apbeam, center, low, high)
+ } else {
+ call gseti (gp, G_PLTYPE, 0)
+ do i = 1, naps
+ call ap_gmark (gp, line, Memi[aps+i-1], 1)
+ call ap_recenter (image, line, nsum, Memi[aps], naps, YES)
+ call gseti (gp, G_PLTYPE, 1)
+ do i = 1, naps
+ call ap_gmark (gp, line, Memi[aps+i-1], 1)
+ }
+ call ap_getdata (image, line, nsum, im, imdata, npts, apaxis,
+ title)
+
+ case 'i': # Set aperture ID
+ if (current == 0)
+ goto beep_
+
+ repeat {
+ call printf ("Aperture (%d) = ")
+ call pargi (AP_ID(Memi[aps+current-1]))
+ call flush (STDOUT)
+ if (scan () != EOF) {
+ call gargi (apid)
+ if (nscan() == 1) {
+ if (apid < 1) {
+ call printf (
+ "Aperture numbers < 1 are not allowed: ")
+ } else {
+ for (i=1; i<=naps; i=i+1)
+ if (i != current &&
+ apid == AP_ID(Memi[aps+i-1]))
+ break
+ if (i <= naps) {
+ call printf ("Aperture %d already used: ")
+ call pargi (apid)
+ } else {
+ AP_ID(Memi[aps+current-1]) = apid
+ call ap_ids (Memi[aps+current-1], 1, ids)
+ break
+ }
+ }
+ } else
+ break
+ }
+ }
+
+ case 'j': # Set beam number
+ if (current == 0)
+ goto beep_
+
+ repeat {
+ call printf ("Beam (%d) = ")
+ call pargi (AP_BEAM(Memi[aps+current-1]))
+ call flush (STDOUT)
+ if (scan () != EOF) {
+ call gargi (apbeam)
+ if (nscan() == 1) {
+# if (apbeam < 0) {
+# call printf (
+# "Beam numbers < 0 are not allowed: ")
+# } else {
+ if (all == NO)
+ AP_BEAM(Memi[aps+current-1]) = apbeam
+ else
+ do i = 1, naps
+ AP_BEAM(Memi[aps+i-1]) = apbeam
+ break
+# }
+ } else
+ break
+ }
+ }
+
+ case 'l': # Set the low limit.
+ if (current == 0)
+ goto beep_
+
+ wx = wx - center
+ if ((naps == 1) || (all == NO))
+ call ap_update (gp, Memi[aps+current-1], line, apid,
+ apbeam, center, wx, high)
+ else {
+ do i = 1, naps {
+ call ap_values (i, Memi[aps], line, apid,
+ apbeam, center, low, high)
+ call ap_update (gp, Memi[aps+i-1], line, apid,
+ apbeam, center, wx, high)
+ }
+ }
+
+ case 'm', 'n': # Define a new aperture.
+ if (mod (naps, 100) == 0)
+ call realloc (aps, naps+100, TY_POINTER)
+
+ if (key == 'm')
+ wx = ap_center (wx, Memr[imdata], npts)
+
+ if (!IS_INDEF(wx)) {
+ naps = naps + 1
+ if (naps > 1)
+ call ap_copy (Memi[aps+current-1], Memi[aps+naps-1])
+ else
+ call ap_copy (apdef, Memi[aps+naps-1])
+
+ AP_ID(Memi[aps+naps-1]) = INDEFI
+ AP_CEN(Memi[aps+naps-1], apaxis) = wx -
+ ap_cveval (AP_CV(Memi[aps+naps-1]), real (line))
+ AP_CEN(Memi[aps+naps-1], dispaxis) = line
+ AP_LOW(Memi[aps+naps-1], dispaxis) =
+ 1 - AP_CEN(Memi[aps+naps-1], dispaxis)
+ AP_HIGH(Memi[aps+naps-1], dispaxis) = IM_LEN(im, dispaxis) -
+ AP_CEN(Memi[aps+naps-1], dispaxis)
+
+ call ap_icset (Memi[aps+naps-1], Memi[aps+naps-1], npts)
+
+ current = naps
+ i = apgwrd ("order", cmd, SZ_LINE, ORDER)
+ call ap_sort (current, Memi[aps], naps, i)
+ call ap_ids (Memi[aps], naps, ids)
+ call ap_titles (Memi[aps+current-1], 1, ids)
+
+ call ap_values (current, Memi[aps], line, apid,
+ apbeam, center, low, high)
+ call ap_gmark (gp, line, Memi[aps+current-1], 1)
+ }
+
+ case 'o': # Order the aperture and beam numbers
+ if (naps == 0)
+ goto beep_
+
+ do i = 1, naps
+ if (i != current)
+ AP_ID(Memi[aps+i-1]) = INDEFI
+
+ call printf ("Aperture (%d) = ")
+ call pargi (AP_ID(Memi[aps+current-1]))
+ call flush (STDOUT)
+ if (scan () != EOF) {
+ call gargi (apid)
+ if (nscan() == 1) {
+ AP_ID(Memi[aps+current-1]) = apid
+ AP_BEAM(Memi[aps+current-1]) = apid
+ }
+ }
+
+ i = apgwrd ("order", cmd, SZ_LINE, ORDER)
+ call ap_sort (current, Memi[aps], naps, i)
+ call ap_ids (Memi[aps], naps, ids)
+
+ # Reset the titles
+ do i = 1, naps
+ if (AP_TITLE(Memi[aps+i-1]) != NULL)
+ call mfree (AP_TITLE(Memi[aps+i-1]), TY_CHAR)
+ call ap_titles (Memi[aps], naps, ids)
+
+ newgraph = YES
+
+ case 'r': # Redraw the graph.
+ newgraph = YES
+
+ case 's': # Shift apertures
+ if (current == 0)
+ goto beep_
+
+ call printf ("Center aperture %d (no)? ")
+ call pargi (AP_ID(Memi[aps+current-1]))
+ call flush (STDOUT)
+ if (scan () != EOF) {
+ call gargb (peak)
+ if (nscan() == 1 && peak) {
+ wy = ap_center (wx, Memr[imdata], npts)
+ if (!IS_INDEF(wy))
+ wx = wy
+ }
+ }
+
+ if ((naps == 1) || (all == NO))
+ call ap_update (gp, Memi[aps+current-1], line, apid,
+ apbeam, wx, low, high)
+ else {
+ wx = wx - center
+ do i = 1, naps {
+ call ap_values (i, Memi[aps], line, apid,
+ apbeam, center, low, high)
+ call ap_update (gp, Memi[aps+i-1], line, apid,
+ apbeam, center + wx, low, high)
+ }
+ }
+
+ case 't': # Trace.
+ if (current == 0)
+ goto beep_
+
+ call imunmap (im)
+ call appstr ("ansfittrace1", "yes")
+ if (all == NO)
+ call ap_trace (image, line, Memi[aps+current-1], 1, YES)
+ else
+ call ap_trace (image, line, Memi[aps], naps, YES)
+ call ap_getdata (image, line, nsum, im, imdata, npts, apaxis,
+ title)
+ newgraph = YES
+
+ case 'u': # Set the upper limit.
+ if (current == 0)
+ goto beep_
+
+ wx = wx - center
+ if ((naps == 1) || (all == NO))
+ call ap_update (gp, Memi[aps+current-1], line, apid,
+ apbeam, center, low, wx)
+ else {
+ do i = 1, naps {
+ call ap_values (i, Memi[aps], line, apid,
+ apbeam, center, low, high)
+ call ap_update (gp, Memi[aps+i-1], line, apid,
+ apbeam, center, low, wx)
+ }
+ }
+
+ case 'w': # Window the graph.
+ call gt_window (gt, gp, "gcur", newgraph)
+
+ case 'y': # Set aperture limits at the y level.
+ if (current == 0)
+ goto beep_
+
+ if ((naps == 1) || (all == NO)) {
+ low = -npts
+ high = npts
+ call ap_ylevel (Memr[imdata], npts, wy, false, false, 0.,
+ center, low, high)
+ call ap_update (gp, Memi[aps+current-1], line, apid,
+ apbeam, center, low, high)
+ } else {
+ do i = 1, naps {
+ call ap_values (i, Memi[aps], line, apid,
+ apbeam, center, low, high)
+ low = -npts
+ high = npts
+ call ap_ylevel (Memr[imdata], npts, wy, false, false,
+ 0., center, low, high)
+ call ap_update (gp, Memi[aps+i-1], line, apid,
+ apbeam, center, low, high)
+ }
+ }
+
+ case 'z': # Apply resize algorithm.
+ if (current == 0)
+ goto beep_
+
+ call imunmap (im)
+ if (all == NO) {
+ call gseti (gp, G_PLTYPE, 0)
+ call ap_gmark (gp, line, Memi[aps+current-1], 1)
+ call ap_resize (image, line, nsum,
+ Memi[aps+current-1], 1, YES)
+ call gseti (gp, G_PLTYPE, 1)
+ call ap_gmark (gp, line, Memi[aps+current-1], 1)
+ call ap_values (current, Memi[aps], line, apid,
+ apbeam, center, low, high)
+ } else {
+ call gseti (gp, G_PLTYPE, 0)
+ do i = 1, naps
+ call ap_gmark (gp, line, Memi[aps+i-1], 1)
+ call ap_resize (image, line, nsum, Memi[aps], naps, YES)
+ call gseti (gp, G_PLTYPE, 1)
+ do i = 1, naps
+ call ap_gmark (gp, line, Memi[aps+i-1], 1)
+ }
+ call ap_getdata (image, line, nsum, im, imdata, npts, apaxis,
+ title)
+
+ case 'I': # Interrupt
+ call fatal (0, "Interrupt")
+
+ default: # Ring bell for unrecognized commands.
+beep_ call printf ("Invalid or unrecognized command\007")
+ statline = YES
+ }
+
+ # Update the graph if needed.
+ if (newgraph == YES) {
+ call ap_graph (gp, gt, Memr[imdata], npts, line,
+ Memi[aps], naps)
+ newgraph = NO
+ }
+
+ # Set the cursor to the current aperture and print the current
+ # aperture on the status line.
+ call ap_gscur (current, gp, line, Memi[aps], wy)
+ if (statline == NO)
+ call ap_print (current, line, all, Memi[aps])
+
+ } until (gt_gcur ("gcur", wx, wy, wcs, key, cmd, SZ_LINE) == EOF)
+
+ # Log the editing operation.
+ call sprintf (Memc[str], SZ_LINE, "EDIT - %d apertures edited for %s")
+ call pargi (naps)
+ call pargstr (image)
+ call ap_log (Memc[str], YES, NO, NO)
+
+ # Free memory.
+ call ap_fids (ids)
+ call mfree (imdata, TY_REAL)
+ call mfree (title, TY_CHAR)
+ call imunmap (im)
+ call gt_free (gt)
+ call gt_free (ic_gt)
+ call ap_free (apdef)
+
+ # If a new image is desired loop back.
+ if (newim == YES) {
+ call clgstr ("database", Memc[output], SZ_LINE)
+ call sprintf (Memc[str], SZ_LINE,
+ "Write apertures for %s to %s")
+ call pargstr (image)
+ call pargstr (Memc[output])
+ if (ap_answer ("ansdbwrite", Memc[str]))
+ call ap_dbwrite (image, aps, naps)
+ call strcpy (cmd, image, SZ_FNAME)
+ call ap_dbread (image, aps, naps)
+ goto new_
+ }
+
+ call appstr ("ansdbwrite1", "yes")
+ call sfree (sp)
+end
diff --git a/noao/twodspec/apextract/apertures.h b/noao/twodspec/apextract/apertures.h
new file mode 100644
index 00000000..aeb4bd94
--- /dev/null
+++ b/noao/twodspec/apextract/apertures.h
@@ -0,0 +1,32 @@
+# Aperture Definition
+
+# Aperture structure -- The aperture structure consists of an integer
+# identification number, a title, the center of the aperture, the lower
+# and upper limits of the aperture measured relative to the center, the
+# axis for a curve giving an offset relative to the center, the CURFIT
+# pointer describing the curve and an ICFIT pointer for background
+# subtraction. The center and lower and upper limits are pairs of real
+# numbers in the order column value and line value. The edges of the
+# aperture are given by:
+#
+# low column = center column + low column offset + curve (line)
+# high column = center column + high column offset + curve (line)
+# low line = center line + low line offset + curve (column)
+# high line = center line + high line offset + curve (column)
+#
+# The curve is aplied to the column positions if the curve axis is 1 and
+# to the line positions if the curve axis is 2.
+
+define AP_LEN 13 # Length of aperture structure
+define SZ_APTITLE 60 # Length of aperture title
+
+define AP_ID Memi[$1] # Aperture ID
+define AP_TITLE Memi[$1+1] # Pointer to title
+define AP_BEAM Memi[$1+2] # Aperture beam number
+define AP_CEN Memr[P2R($1+3+$2-1)] # Aperture center
+define AP_LOW Memr[P2R($1+5+$2-1)] # Aperture limit
+define AP_HIGH Memr[P2R($1+7+$2-1)] # Aperture limit
+define AP_AXIS Memi[$1+9] # Axis for curve
+define AP_CV Memi[$1+10] # Aperture curve
+define AP_IC Memi[$1+11] # ICFIT pointer
+define AP_SELECT Memi[$1+12] # Aperture selected?
diff --git a/noao/twodspec/apextract/apextract.cl b/noao/twodspec/apextract/apextract.cl
new file mode 100644
index 00000000..035ce189
--- /dev/null
+++ b/noao/twodspec/apextract/apextract.cl
@@ -0,0 +1,33 @@
+#{ APEXTRACT -- Aperture extraction package
+
+package apextract
+
+task apall,
+ apedit,
+ apfind,
+ apfit,
+ apflatten,
+ apmask,
+ apnormalize,
+ aprecenter,
+ apresize,
+ apscatter,
+ apnoise,
+ apsum,
+ aptrace = "apextract$x_apextract.e"
+task apparams = "apextract$apparams.par"
+task apall1 = "apextract$apall1.par"
+task apfit1 = "apextract$apfit1.par"
+task apflat1 = "apextract$apflat1.par"
+task apnorm1 = "apextract$apnorm1.par"
+task apnoise1 = "apextract$apnoise1.par"
+task apdefault = "apextract$apdefault.par"
+task apscat1 = "apextract$apscat1.par"
+task apscat2 = "apextract$apscat2.par"
+
+set apdemos = "apextract$apdemos/"
+task apdemos.pkg = "apdemos$apdemos.cl"
+
+hidetask apparams, apall1, apfit1, apflat1, apnorm1, apscat1, apscat2, apnoise1
+
+clbye
diff --git a/noao/twodspec/apextract/apextract.hd b/noao/twodspec/apextract/apextract.hd
new file mode 100644
index 00000000..ad17623d
--- /dev/null
+++ b/noao/twodspec/apextract/apextract.hd
@@ -0,0 +1,27 @@
+# Help directory for the APEXTRACT package.
+
+$doc = "./doc/"
+
+apall hlp=doc$apall.hlp
+apdefault hlp=doc$apdefault.hlp
+apdemos hlp=doc$apdemos.hlp
+apedit hlp=doc$apedit.hlp
+apfind hlp=doc$apfind.hlp
+apfit hlp=doc$apfit.hlp
+apflatten hlp=doc$apflatten.hlp
+apmask hlp=doc$apmask.hlp
+apnoise hlp=doc$apnoise.hlp
+apnormalize hlp=doc$apnormalize.hlp
+aprecenter hlp=doc$aprecenter.hlp
+apresize hlp=doc$apresize.hlp
+apscatter hlp=doc$apscatter.hlp
+apsum hlp=doc$apsum.hlp
+aptrace hlp=doc$aptrace.hlp
+
+package hlp=doc$apextract.hlp, sys=doc$apextractsys.hlp
+apbackground hlp=doc$apbackground.hlp
+approfiles hlp=doc$approfiles.hlp
+apvariance hlp=doc$apvariance.hlp
+extras hlp=doc$apextras.hlp
+
+revisions sys=Revisions
diff --git a/noao/twodspec/apextract/apextract.men b/noao/twodspec/apextract/apextract.men
new file mode 100644
index 00000000..c0db0005
--- /dev/null
+++ b/noao/twodspec/apextract/apextract.men
@@ -0,0 +1,23 @@
+ apall - Extract 1D spectra (all parameters in one task)
+ apdefault - Set the default aperture parameters and apidtable
+ apdemos - Various tutorial demonstrations
+ apedit - Edit apertures interactively
+ apfind - Automatically find spectra and define apertures
+ apfit - Fit 2D spectra and output the fit, difference, or ratio
+ apflatten - Remove overall spectral and profile shapes from flat fields
+ apnoise - Compute and examine noise characteristics of spectra
+ apmask - Create and IRAF pixel list mask of the apertures
+ apnormalize - Normalize 2D apertures by 1D functions
+ aprecenter - Recenter apertures
+ apresize - Resize apertures
+ apscatter - Fit and subtract scattered light
+ apsum - Extract 1D spectra
+ aptrace - Trace positions of spectra
+
+ ADDITIONAL HELP TOPICS
+
+ apbackground - Background subtraction algorithms
+ approfiles - Profile determination algorithms
+ apvariance - Extractions, variance weighting, cleaning, and noise model
+ extras - Information about the extra information in 3D images
+ package - Package parameters and general description of package
diff --git a/noao/twodspec/apextract/apextract.par b/noao/twodspec/apextract/apextract.par
new file mode 100644
index 00000000..8b153ec8
--- /dev/null
+++ b/noao/twodspec/apextract/apextract.par
@@ -0,0 +1,8 @@
+# APEXTRACT Package
+
+dispaxis,i,h,2,1,2,"Dispersion axis (1=along lines, 2=along columns)"
+database,f,h,"database",,,Database
+verbose,b,h,no,,,Verbose output?
+logfile,s,h,"",,,Text log file
+plotfile,s,h,"",,,Plot file
+version,s,h,"APEXTRACT V3.0: August 1990"
diff --git a/noao/twodspec/apextract/apextract.x b/noao/twodspec/apextract/apextract.x
new file mode 100644
index 00000000..176ab251
--- /dev/null
+++ b/noao/twodspec/apextract/apextract.x
@@ -0,0 +1,1834 @@
+include <error.h>
+include <imhdr.h>
+include <mach.h>
+include <math/iminterp.h>
+include <pkg/gtools.h>
+include "apertures.h"
+
+# Background fitting types
+define BACKGROUND "|none|average|median|minimum|fit|"
+define B_NONE 1
+define B_AVERAGE 2
+define B_MEDIAN 3
+define B_MINIMUM 4
+define B_FIT 5
+
+# Weight types
+define WEIGHTS "|none|variance|"
+define W_NONE 1
+define W_VARIANCE 2
+
+# Profile fitting algorithms
+define P_FIT "|fit1d|fit2d|"
+define P_FIT1D 1
+define P_FIT2D 2
+
+# Output formats
+define FORMATS "|onedspec|multispec|echelle|strip|normalize|flatten\
+ |ratio|difference|fit|noise|"
+define ONEDSPEC 1 # Individual 1D spectra
+define MULTISPEC 2 # Multiple spectra
+define ECHELLE 3 # Echelle spectra
+define STRIP 4 # Strip spectra
+define NORM 5 # Normalized spectra
+define FLAT 6 # Flat spectra
+define RATIO 7 # Ratio of data to model
+define DIFF 8 # Difference of data and model
+define FIT 9 # Model
+define NOISE 10 # Noise calculation
+
+
+# AP_EXTRACT -- Extract spectra by a weighted sum across the apertures.
+#
+# This routine does clobber checks on the output images, manages the I/O
+# from the input image in as big of pieces as possible, and loops through
+# each aperture calling routines to determine the sky, do any fitting and
+# extraction, and output the spectra.
+# The extraction may be either a simple, unweighted extraction
+# which is very fast or a weighted extraction using CCD noise
+# parameters. The weights require dividing out the basic spectrum and
+# smoothing the 2D spectral profile. The general approach of variance
+# weighting is described by K. Horne (PASP V98, P609, 1986). The
+# smoothing has two algorithms, fitting columns or lines parallel to the
+# dispersion axis for nearly aligned spectra or fitting a 2D function
+# using a method given by T. Marsh (PASP V101, P1032, 1989). The profile
+# may also be used to reject cosmic rays by iteration.
+#
+# The extractions require enough memory to get at least one aperture plus
+# background (if needed) into memory. If possible the region containing
+# all the apertures is read into memory. The target maximum amount of
+# memory is set by the maxmimum size returned by BEGMEM and the
+# appropriate working set size is requested. The optimal size can be
+# tuned through BEGMEM, which references a machine dependent include
+# file, if needed. The algorithm should work well (minimize I/O as well
+# as paging) in all cases but very large image formats with highly tilted
+# spectra (where aperture extraction along the image axes is not really
+# appropriate). These memory requirements were chosen to minimize image
+# I/O and because the variance weighted algorithms need to make multiple
+# passes through the image. In principle simple, unweighted extractions
+# with no sky smoothing can be done sequentially but this was not done in
+# order to use nearly the same code for both weighted and unweighted
+# cases.
+#
+# If using variance weighting and a profile image is given then it is used
+# to determine the profile which is then applied to the target image
+# during the final extraction. If the same profile image is used multiple
+# times it would be more efficient to store the profile but then issues
+# of consistency arise. For now this possible feature is not implemented.
+
+procedure ap_extract (input, output, format, profiles, aps, naps)
+
+char input[SZ_FNAME] # Input image
+char output[SZ_FNAME] # Output image (optional root name)
+char format[SZ_LINE] # Output format
+char profiles[SZ_FNAME] # Profile filename (optional)
+pointer aps[ARB] # Apertures
+int naps # Number of apertures
+
+# CL parameters
+int fmt # Output format
+int bkg # Background type
+int weights # Extraction weights
+int pfit # Profile fitting algorithm
+bool clean # Reject cosmic rays?
+real gain # Photon/DN gain
+real rdnoise # Read out noise
+int nsubaps # Number of subapertures
+int interptype # Edge interpolation type
+
+int i, j, k, napsex, aaxis, baxis, namax, na, nb, na1, interpbuf
+int amin, amax, bmin, bmax
+int new_size, old_size, max_size, best_size
+real cmin, cmax, xmin, xmax, shift
+pointer sp, str, bkgstr, wtstr, cleanstr, apsex
+pointer a, b, c, astart, spec, specsky, specsig, raw, profile
+pointer a1, a2, b1, b2, c1, c2, im, pim, ap, cv, ic, dbuf, pbuf, sbuf, svar, ptr
+pointer asi
+
+bool clgetb(), apgetb(), strne()
+int apgeti(), apgwrd(), begmem(), ap_check()
+real apgimr(), ap_cveval(), ic_getr()
+pointer ap_immap(), imgs2r(), imgl2r()
+errchk salloc, malloc, ap_immap, imgs2r, imgl2r, asiinit
+errchk ap_check, ap_skyeval, ap_profile, ap_variance, ap_output, apgimr
+
+begin
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ napsex = 0
+ do i = 1, naps
+ if (AP_SELECT(aps[i]) == YES)
+ napsex = napsex + 1
+ if (napsex == 0) {
+ call sprintf (Memc[str], SZ_LINE,
+ "EXTRACT - No apertures defined for %s")
+ call pargstr (input)
+ call ap_log (Memc[str], YES, NO, YES)
+ call sfree (sp)
+ return
+ }
+
+ call salloc (bkgstr, SZ_FNAME, TY_CHAR)
+ call salloc (wtstr, SZ_FNAME, TY_CHAR)
+ call salloc (cleanstr, SZ_FNAME, TY_CHAR)
+ call salloc (apsex, napsex, TY_POINTER)
+
+ # Select apertures to extract and fix possible limit error.
+ napsex = 0
+ do i = 1, naps {
+ if (AP_LOW(aps[i],1) > AP_HIGH(aps[i],1)) {
+ xmax = AP_LOW(aps[i],1)
+ AP_LOW(aps[i],1) = AP_HIGH(aps[i],1)
+ AP_HIGH(aps[i],1) = xmax
+ }
+ if (AP_LOW(aps[i],2) > AP_HIGH(aps[i],2)) {
+ xmax = AP_LOW(aps[i],2)
+ AP_LOW(aps[i],2) = AP_HIGH(aps[i],2)
+ AP_HIGH(aps[i],2) = xmax
+ }
+ if (AP_SELECT(aps[i]) == NO)
+ next
+ Memi[apsex+napsex] = aps[i]
+ napsex = napsex + 1
+ }
+
+ # Get CL parameters
+ bkg = apgwrd ("background", Memc[bkgstr], SZ_FNAME, BACKGROUND)
+ pfit = apgwrd ("pfit", Memc[str], SZ_LINE, P_FIT)
+ clean = apgetb ("clean")
+ if (clean)
+ call strcpy ("yes", Memc[cleanstr], SZ_FNAME)
+ else
+ call strcpy ("no", Memc[cleanstr], SZ_FNAME)
+ nsubaps = apgeti ("nsubaps")
+ interptype = II_LINEAR
+
+ # Do clobber checking. Return if output exists and not clobbering.
+ call apgstr ("ansclobber", Memc[str], SZ_LINE)
+ call appstr ("ansclobber1", Memc[str])
+ fmt = ap_check (input, output, format, Memi[apsex], napsex, nsubaps)
+ if (fmt == 0) {
+ call sfree (sp)
+ return
+ }
+
+ # Force weights depending on format or cleaning.
+ switch (fmt) {
+ case FLAT, RATIO, DIFF, FIT, NOISE:
+ weights = W_VARIANCE
+ default:
+ if (clean) {
+ call strcpy ("variance", Memc[wtstr], SZ_FNAME)
+ weights = W_VARIANCE
+ } else
+ weights = apgwrd ("weights", Memc[wtstr], SZ_FNAME, WEIGHTS)
+ }
+
+ if (clgetb ("verbose")) {
+ call printf ("Extracting apertures ...\n")
+ call flush (STDOUT)
+ }
+
+ # Open input image and profile image if given. Set axis parameters
+ # where 'a' is the aperture axis across the dispersion and 'b' is
+ # along the dispersion.
+
+ im = ap_immap (input, aaxis, baxis)
+ namax = IM_LEN(im, aaxis)
+ nb = IM_LEN(im, baxis)
+
+ pim = NULL
+ if (strne(profiles,input) && weights==W_VARIANCE && profiles[1]!=EOS) {
+ pim = ap_immap (profiles, i, j)
+ if (i!=aaxis||j!=baxis||IM_LEN(pim,i)!=namax||IM_LEN(pim,j)!=nb) {
+ call imunmap (pim)
+ call imunmap (im)
+ call sfree (sp)
+ call error (1,
+ "Input image and profile image are not compatible")
+ }
+ call sprintf (Memc[str], SZ_LINE,
+ "EXTRACT - Using profile image %s for %s")
+ call pargstr (profiles)
+ call pargstr (input)
+ call ap_log (Memc[str], YES, YES, NO)
+ }
+
+ # Determine limits of apertures for use in defining memory requirements
+ # and I/O.
+
+ call salloc (a, 2 * napsex, TY_INT)
+ call salloc (b, 2 * napsex, TY_INT)
+ call salloc (c, 2 * napsex, TY_REAL)
+ a1 = a - 1
+ a2 = a1 + napsex
+ b1 = b - 1
+ b2 = b1 + napsex
+ c1 = c - 1
+ c2 = c1 + napsex
+
+ # Initialize image interpolator for edge pixel weighting.
+ switch (interptype) {
+ case II_LINEAR:
+ interpbuf = 2
+ case II_POLY3:
+ interpbuf = 3
+ case II_SINC:
+ interpbuf = 16
+ default:
+ interpbuf = 0
+ }
+ if (interptype > 0)
+ call asiinit (asi, interptype)
+ else
+ asi = NULL
+
+ na1 = 0
+ do i = 1, napsex {
+ ap = Memi[apsex+i-1]
+ cv = AP_CV(ap)
+ ic = AP_IC(ap)
+
+ # Dispersion axis limits
+ bmin = min (nb, max (1, nint (AP_CEN(ap,baxis)+AP_LOW(ap,baxis))))
+ bmax = max (1, min (nb, nint (AP_CEN(ap,baxis)+AP_HIGH(ap,baxis))))
+
+ # Aperture axis shifts
+ if (cv != NULL) {
+ cmin = MAX_REAL
+ cmax = -MAX_REAL
+ do j = bmin, bmax {
+ shift = ap_cveval (cv, real (j))
+ cmin = min (cmin, shift)
+ cmax = max (cmax, shift)
+ }
+ } else {
+ cmin = 0.
+ cmax = 0.
+ }
+
+ # Background region limits.
+ xmin = AP_LOW(ap,aaxis)
+ xmax = AP_HIGH(ap,aaxis)
+ if (weights == W_VARIANCE) {
+ xmin = xmin - 2
+ xmax = xmax + 2
+ }
+ xmin = xmin - interpbuf
+ xmax = xmax + interpbuf
+ if (bkg != B_NONE && AP_IC(ap) != NULL) {
+ xmin = min (xmin, ic_getr (ic, "xmin"))
+ xmax = max (xmax, ic_getr (ic, "xmax"))
+ }
+
+ Memi[a1+i] = min (namax, max (1, nint (AP_CEN(ap,aaxis)+xmin+cmin)))
+ Memi[a2+i] = max (1, min (namax, nint (AP_CEN(ap,aaxis)+xmax+cmax)))
+ Memi[b1+i] = bmin
+ Memi[b2+i] = bmax
+ Memr[c1+i] = cmin
+ Memr[c2+i] = cmax
+ }
+ call alimi (Memi[a], 2*napsex, amin, amax)
+ call alimi (Memi[b], 2*napsex, bmin, bmax)
+
+ # The maximum size of the image in memory is 80% of the maximum
+ # working set size returned by begmem or 40% if a profile image
+ # is used. Later I/O may exceed this since at least one
+ # aperture + background is needed in memory.
+
+ new_size = begmem (0, old_size, max_size)
+ namax = (amax - amin + 1)
+ nb = (bmax - bmin + 1)
+ if (pim == NULL)
+ namax = min (namax, int (0.8 * max_size / SZ_REAL / nb))
+ else
+ namax = min (namax, int (0.8 * max_size / SZ_REAL / nb / 2))
+ best_size = 1.2 * namax * nb * SZ_REAL
+ new_size = begmem (best_size, old_size, max_size)
+
+ # Allocate auxilary memory. Some memory is only dependent on the
+ # number of dispersion points and subapertures and is the same for
+ # all apertures. Other memory, such as the sky and profile depend on
+ # the aperture widths and tilts which may vary. The input data is
+ # expected to have the aperture axis along the first dimension. If
+ # the image is in this orientation then the IMIO buffer is used.
+ # Otherwise sequential I/O is used and transposed into the allocated
+ # memory.
+
+ iferr {
+ call salloc (astart, nb, TY_INT)
+ call salloc (spec, nsubaps * nb, TY_REAL)
+ if (weights == W_VARIANCE) {
+ call salloc (raw, nsubaps * nb, TY_REAL)
+ call salloc (specsig, nsubaps * nb, TY_REAL)
+ } else {
+ raw = NULL
+ specsig = NULL
+ }
+ profile = NULL
+ if (aaxis == 2) {
+ call calloc (dbuf, namax * nb, TY_REAL)
+ if (pim != NULL)
+ call calloc (pbuf, namax * nb, TY_REAL)
+ }
+
+ # For variance weighting the computations are done in photon units.
+ if (weights == W_VARIANCE) {
+ gain = apgimr ("gain", im)
+ rdnoise = apgimr ("readnoise", im)
+ } else {
+ gain = 1
+ rdnoise = 0
+ }
+
+ # Loop through each aperture doing the extractions.
+ amax = 0
+ do i = 1, napsex {
+ ap = Memi[apsex+i-1]
+
+ # Check if a new input data buffer is needed. As many apertures
+ # as possible are read at once within the given memory limits
+ # though at least one aperture must be read. Do a transpose if
+ # needed.
+
+ if (Memi[a1+i] < amin || Memi[a2+i] > amax) {
+ amin = Memi[a1+i]
+ amax = Memi[a2+i]
+ do j = i, napsex {
+ amin = min (amin, Memi[a1+j])
+ amax = max (amax, Memi[a2+j])
+ na = amax - amin + 1
+ if (na > namax)
+ break
+ }
+
+ if (aaxis == 1) {
+ if (fmt == DIFF) {
+ call mfree (dbuf, TY_REAL)
+ call malloc (dbuf, na*nb, TY_REAL)
+ call amovr (Memr[imgs2r(im,amin,amax,bmin,bmax)],
+ Memr[dbuf], na*nb)
+ } else
+ dbuf = imgs2r (im, amin, amax, bmin, bmax)
+ } else {
+ if (na > namax) {
+ call mfree (dbuf, TY_REAL)
+ namax = na
+ call calloc (dbuf, namax * nb, TY_REAL)
+ }
+ do j = amin, amax {
+ sbuf = imgl2r (im, j)
+ sbuf = sbuf + bmin - 1
+ ptr = dbuf + j - amin
+ do k = bmin, bmax {
+ Memr[ptr] = Memr[sbuf]
+ sbuf = sbuf + 1
+ ptr = ptr + na
+ }
+ }
+ }
+ if (pim != NULL) {
+ if (aaxis == 1)
+ pbuf = imgs2r (pim, amin, amax, bmin, bmax)
+ else {
+ if (na > namax) {
+ call mfree (pbuf, TY_REAL)
+ namax = na
+ call calloc (pbuf, namax * nb, TY_REAL)
+ }
+ do j = amin, amax {
+ sbuf = imgl2r (pim, j)
+ sbuf = sbuf + bmin - 1
+ ptr = pbuf + j - amin
+ do k = bmin, bmax {
+ Memr[ptr] = Memr[sbuf]
+ sbuf = sbuf + 1
+ ptr = ptr + na
+ }
+ }
+ }
+ }
+ if (weights == W_VARIANCE && gain != 1.) {
+ j = na * nb
+ call amulkr (Memr[dbuf], gain, Memr[dbuf], j)
+ if (pim != NULL)
+ call amulkr (Memr[pbuf], gain, Memr[pbuf], j)
+ }
+ }
+
+ # To minimize memory a variable integer offset is used to
+ # accomodate the aperture tilts. The offsets are stored in
+ # the astart array and the width of any one line determined.
+ # If a stored profile is used it is read and it is ASSUMED to
+ # be valid for the input aperture with the same ID. If no
+ # stored profile is found the profile fitting algorithm
+ # parameter determines whether to fit 1D function along the
+ # image axes (in which case all the profile offsets are the
+ # same) or if the Marsh algorithm for tilted spectra is
+ # used. In the latter the offsets can be adjusted to mimize
+ # memory and a buffer of two pixels around the aperture is
+ # required by the algorithm.
+
+ if (weights == W_NONE) {
+ xmin = AP_CEN(ap,aaxis) + AP_LOW(ap,aaxis)
+ xmax = AP_CEN(ap,aaxis) + AP_HIGH(ap,aaxis)
+ xmin = xmin - interpbuf
+ xmax = xmax + interpbuf
+ na1 = nint (xmax) - nint (xmin) + 1
+ cv = AP_CV(ap)
+ do j = bmin, bmax {
+ shift = ap_cveval (cv, real (j))
+ Memi[astart+j-bmin] = nint (xmin + shift)
+ }
+ } else {
+ if (pfit == P_FIT1D) {
+ xmin = AP_CEN(ap,aaxis) + AP_LOW(ap,aaxis) + Memr[c1+i]
+ xmax = AP_CEN(ap,aaxis) + AP_HIGH(ap,aaxis) + Memr[c2+i]
+ xmin = xmin - interpbuf
+ xmax = xmax + interpbuf
+ na1 = nint (xmax) - nint (xmin) + 1
+ call amovki (nint (xmin), Memi[astart], nb)
+ } else if (pfit == P_FIT2D) {
+ xmin = AP_CEN(ap,aaxis) + AP_LOW(ap,aaxis) - 2
+ xmax = AP_CEN(ap,aaxis) + AP_HIGH(ap,aaxis) + 2
+ xmin = xmin - interpbuf
+ xmax = xmax + interpbuf
+ na1 = nint (xmax) - nint (xmin) + 1
+ cv = AP_CV(ap)
+ do j = bmin, bmax {
+ shift = ap_cveval (cv, real (j))
+ Memi[astart+j-bmin] = nint (xmin + shift)
+ }
+ }
+ }
+
+ # Do the sky or background determination if needed. An array
+ # of the same size as the 2D aperture is returned as well as
+ # a single estimate of the variance in the sky value at each
+ # line based on the fit. If a profile image is used then the
+ # sky is for the profile image and the object sky is
+ # determined later in order to reuse the sky buffers.
+
+ if (bkg != B_NONE && AP_IC(ap) != NULL) {
+ call malloc (sbuf, na1 * nb, TY_REAL)
+ call malloc (svar, nb, TY_REAL)
+ call malloc (specsky, nsubaps * nb, TY_REAL)
+ if (pim == NULL)
+ call ap_skyeval (im, ap, dbuf, na, nb, amin, 1,
+ Memr[sbuf], Memr[svar], Memr[specsky], na1, nb,
+ Memi[astart], 1, nsubaps, rdnoise)
+ else
+ call ap_skyeval (pim, ap, pbuf, na, nb, amin, 1,
+ Memr[sbuf], Memr[svar], Memr[specsky], na1, nb,
+ Memi[astart], 1, nsubaps, rdnoise)
+ } else {
+ sbuf = NULL
+ svar = NULL
+ specsky = NULL
+ }
+
+ # Use a quick sum for unweighted extraction. For weighed
+ # extractions we use either a previously determined profile
+ # or call the profile routine. If desired the profile is
+ # stored for later use. Then the variance weighted
+ # extraction routine is called.
+
+ if (weights == W_NONE)
+ call ap_sum (ap, dbuf, na, nb, amin, 1, sbuf, na1, nb,
+ Memi[astart], 1, Memr[spec], nsubaps, asi)
+ else {
+ call malloc (profile, na1 * nb, TY_REAL)
+ if (pim == NULL)
+ call ap_profile (im, ap, dbuf, na, nb, amin, 1, sbuf,
+ svar, Memr[profile], na1, nb, Memi[astart], 1,
+ asi)
+ else {
+ call ap_profile (pim, ap, pbuf, na, nb, amin, 1, sbuf,
+ svar, Memr[profile], na1, nb, Memi[astart], 1,
+ asi)
+ if (sbuf != NULL)
+ call ap_skyeval (im, ap, dbuf, na, nb, amin, 1,
+ Memr[sbuf], Memr[svar], Memr[specsky], na1, nb,
+ Memi[astart], 1, nsubaps, rdnoise)
+ }
+
+ call ap_variance (im, ap, dbuf, na, nb, amin, 1, sbuf, svar,
+ Memr[profile], na1, nb, Memi[astart], 1, Memr[spec],
+ Memr[raw], Memr[specsig], nsubaps, asi)
+ }
+
+ # Output the extracted spectrum. The extras of sky, sigma,
+ # and unweighted spectrum may also be stored. If the extra
+ # information is not available the pointers will be NULL.
+
+ if (weights == W_VARIANCE && gain != 1.) {
+ call adivkr (Memr[spec], gain, Memr[spec], nb)
+ if (raw != NULL)
+ call adivkr (Memr[raw], gain, Memr[raw], nb)
+ if (specsky != NULL)
+ call adivkr (Memr[specsky], gain, Memr[specsky], nb)
+ if (specsig != NULL)
+ call adivkr (Memr[specsig], gain, Memr[specsig], nb)
+ call amulkr (Memr[profile], gain, Memr[profile], nb*na1)
+ }
+
+ call ap_output (input, output, format, Memc[bkgstr],
+ Memc[wtstr], Memc[cleanstr], gain, im, Memi[apsex], napsex,
+ i, nsubaps, spec, raw, specsky, specsig, dbuf, na, nb, amin,
+ 1, sbuf, profile, na1, nb, Memi[astart], 1)
+
+ call mfree (profile, TY_REAL)
+ call mfree (sbuf, TY_REAL)
+ call mfree (svar, TY_REAL)
+ call mfree (specsky, TY_REAL)
+ }
+
+ # Finish up and restore the working set size.
+ if (asi != NULL)
+ call asifree (asi)
+ if (pim != NULL) {
+ if (aaxis == 2)
+ call mfree (pbuf, TY_REAL)
+ call imunmap (pim)
+ }
+ if (aaxis == 2)
+ call mfree (dbuf, TY_REAL)
+ call imunmap (im)
+ call fixmem (old_size)
+ call sfree (sp)
+
+ } then {
+ call mfree (profile, TY_REAL)
+ call mfree (sbuf, TY_REAL)
+ call mfree (svar, TY_REAL)
+ call mfree (specsky, TY_REAL)
+
+ if (asi != NULL)
+ call asifree (asi)
+ if (pim != NULL) {
+ if (aaxis == 2)
+ call mfree (pbuf, TY_REAL)
+ call imunmap (pim)
+ }
+ if (aaxis == 2)
+ call mfree (dbuf, TY_REAL)
+ call imunmap (im)
+ call fixmem (old_size)
+ call sfree (sp)
+
+ call erract (EA_ERROR)
+ }
+end
+
+
+# AP_CHECK -- Check if output spectra exist. If the user allows clobbering,
+# delete the spectra. Return the format.
+
+int procedure ap_check (input, output, format, aps, naps, nsubaps)
+
+char input[ARB] # Input image name
+char output[ARB] # Output root name
+char format[ARB] # Output format
+pointer aps[naps] # Apertures
+int naps # Number of apertures
+int nsubaps # Number of subapertures
+
+int i, j, fmt
+pointer sp, name, name1, input1, ksection, ans
+
+int strdic(), imaccess(), stridxs()
+bool streq(), ap_answer()
+
+begin
+ call smark (sp)
+ call salloc (name, SZ_LINE, TY_CHAR)
+ call salloc (name1, SZ_LINE, TY_CHAR)
+ call salloc (input1, SZ_LINE, TY_CHAR)
+ call salloc (ksection, SZ_LINE, TY_CHAR)
+ call salloc (ans, SZ_LINE, TY_CHAR)
+
+ fmt = strdic (format, format, SZ_LINE, FORMATS)
+ call imgimage (input, Memc[input1], SZ_LINE)
+
+ switch (fmt) {
+ case MULTISPEC, NORM, FLAT, RATIO, DIFF, FIT:
+ i = stridxs ("[", Memc[input1])
+ if (i > 0) {
+ call strcpy (Memc[input1+i-1], Memc[ksection], SZ_LINE)
+ Memc[input1+i-1] = EOS
+ } else
+ Memc[ksection] = EOS
+ if (output[1] == EOS)
+ call strcpy (Memc[input1], Memc[name], SZ_LINE)
+ else
+ call strcpy (output, Memc[name], SZ_LINE)
+
+ switch (fmt) {
+ case MULTISPEC:
+ if (streq (Memc[input1], Memc[name])) {
+ call strcat (".ms", Memc[name], SZ_LINE)
+ call strcat (Memc[ksection], Memc[name], SZ_LINE)
+ }
+ case NORM:
+ if (streq (Memc[input1], Memc[name])) {
+ call strcat (".norm", Memc[name], SZ_LINE)
+ call strcat (Memc[ksection], Memc[name], SZ_LINE)
+ }
+ case FLAT:
+ if (streq (Memc[input1], Memc[name])) {
+ call strcat (".flat", Memc[name], SZ_LINE)
+ call strcat (Memc[ksection], Memc[name], SZ_LINE)
+ }
+ case RATIO:
+ if (streq (Memc[input1], Memc[name])) {
+ call strcat (".ratio", Memc[name], SZ_LINE)
+ call strcat (Memc[ksection], Memc[name], SZ_LINE)
+ }
+ case DIFF:
+ if (streq (Memc[input1], Memc[name])) {
+ call strcat (".diff", Memc[name], SZ_LINE)
+ call strcat (Memc[ksection], Memc[name], SZ_LINE)
+ }
+ case FIT:
+ if (streq (Memc[input1], Memc[name])) {
+ call strcat (".fit", Memc[name], SZ_LINE)
+ call strcat (Memc[ksection], Memc[name], SZ_LINE)
+ }
+ }
+ if (imaccess (Memc[name], 0) == YES) {
+ call sprintf (Memc[ans], SZ_LINE,
+ "Clobber existing output image %s?")
+ call pargstr (Memc[name])
+ if (ap_answer ("ansclobber1", Memc[ans]))
+ call imdelete (Memc[name])
+ else {
+ call sprintf (Memc[ans], SZ_LINE,
+ "EXTRACT - Output spectrum %s already exists")
+ call pargstr (Memc[name])
+ call ap_log (Memc[ans], YES, NO, YES)
+ fmt = 0
+ }
+ }
+ case ECHELLE:
+ if (output[1] == EOS)
+ call strcpy (Memc[input1], Memc[name], SZ_LINE)
+ else
+ call strcpy (output, Memc[name], SZ_LINE)
+
+ do i = 1, nsubaps {
+ if (nsubaps == 1)
+ call strcpy (Memc[name], Memc[name1], SZ_LINE)
+ else {
+ call sprintf (Memc[name1], SZ_LINE, "%s%0*d")
+ call pargstr (Memc[name])
+ call pargi (int(log10(real(nsubaps)))+1)
+ call pargi (i)
+ }
+ if (streq (Memc[input1], Memc[name])) {
+ call strcat (".ec", Memc[name1], SZ_LINE)
+ call strcat (Memc[ksection], Memc[name1], SZ_LINE)
+ }
+
+ if (imaccess (Memc[name1], 0) == YES) {
+ call sprintf (Memc[ans], SZ_LINE,
+ "Clobber existing output image %s?")
+ call pargstr (Memc[name1])
+ if (ap_answer ("ansclobber1", Memc[ans]))
+ call imdelete (Memc[name1])
+ else {
+ call sprintf (Memc[ans], SZ_LINE,
+ "EXTRACT - Output spectrum %s already exists")
+ call pargstr (Memc[name1])
+ call ap_log (Memc[ans], YES, NO, YES)
+ fmt = 0
+ }
+ }
+ }
+ case ONEDSPEC, STRIP:
+ do i = 1, naps {
+ do j = 1, nsubaps {
+ call sprintf (Memc[name], SZ_LINE, "%s.%0*d")
+ if (output[1] == EOS)
+ call pargstr (Memc[input1])
+ else
+ call pargstr (output)
+ call pargi (int(log10(real(nsubaps)))+4)
+ call pargi (AP_ID(aps[i])+(j-1)*1000)
+ if (imaccess (Memc[name], 0) == YES) {
+ call sprintf (Memc[ans], SZ_LINE,
+ "Clobber existing output image %s?")
+ call pargstr (Memc[name])
+ if (ap_answer ("ansclobber1", Memc[ans]))
+ call imdelete (Memc[name])
+ else {
+ call sprintf (Memc[ans], SZ_LINE,
+ "EXTRACT - Output spectrum %s already exists")
+ call pargstr (Memc[name])
+ call ap_log (Memc[ans], YES, NO, YES)
+ fmt = 0
+ }
+ }
+ }
+ }
+ case NOISE:
+ ;
+ default:
+ call sfree (sp)
+ call error (1, "EXTRACT - Unknown output format")
+ }
+
+ call sfree (sp)
+ return (fmt)
+end
+
+
+# AP_OUTPUT -- Review the extracted spectra and write them to an image.
+# This routine determines the output format and whether to also output sky
+# unweighted, and sigma spectra. The appropriate header keywords have
+# to be added.
+
+procedure ap_output (image, output, format, bkg, wt, clean, gain, in, aps,
+ naps, iap, nsubaps, spec, raw sky, sig, dbuf, nc, nl, c1, l1, sbuf,
+ profile, nx, ny, xs, ys)
+
+char image[ARB] # Input image name
+char output[ARB] # Output root name
+char format[ARB] # Output format
+char bkg[ARB] # Background type
+char wt[ARB] # Weight type
+char clean[ARB] # Clean?
+real gain # Gain
+pointer in # Input IMIO pointer
+pointer aps[naps] # Apertures
+int naps # Number of apertures
+int iap # Aperture
+int nsubaps # Number of subapertures
+pointer spec # Output spectrum
+pointer raw # Output raw spectrum
+pointer sky # Output sky
+pointer sig # Output sigma
+pointer dbuf # Data buffer
+int nc, nl # Size of data buffer
+int c1, l1 # Origin of data buffer
+pointer sbuf # Sky values (NULL if none)
+pointer profile # Profile (NULL if none)
+int nx, ny # Size of sky and profile array
+int xs[ny], ys # Origin of sky and profile array
+
+int fmt # Output format
+bool extras # Include raw spectrum, sky, and sigma
+
+real low, high, step
+int i, k, l, m, apid, apaxis, dispaxis
+pointer sp, str, str1, name, name1, input, ksection
+pointer ap, out, outsave, gt, apmw, buf
+pointer sum2, sum4, nsum
+
+real clgetr()
+int scan(), strdic(), imaccf(), stridxs()
+bool streq(), ap_answer(), apgetb()
+pointer immap(), imgl2r(), impl2r(), impl3r()
+pointer gt_init(), apmw_open()
+errchk immap, impl2r, impl3r, imps2r, ap_strip, ap_pstrip, apmw_open
+errchk ap_fitspec, ap_lnorm, ap_cnorm, ap_lflat, ap_cflat
+
+begin
+ # Allocate string and file name arrays.
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+ call salloc (str1, SZ_LINE, TY_CHAR)
+ call salloc (name, SZ_LINE, TY_CHAR)
+ call salloc (name1, SZ_LINE, TY_CHAR)
+ call salloc (input, SZ_LINE, TY_CHAR)
+ call salloc (ksection, SZ_LINE, TY_CHAR)
+
+ fmt = strdic (format, format, SZ_LINE, FORMATS)
+ extras = apgetb ("extras")
+
+ ap = aps[iap]
+ apaxis = AP_AXIS(ap)
+ dispaxis = mod (apaxis, 2) + 1
+
+ # Set output name.
+ call imgimage (image, Memc[input], SZ_LINE)
+ i = stridxs ("[", Memc[input])
+ if (i > 0) {
+ call strcpy (Memc[input+i-1], Memc[ksection], SZ_LINE)
+ Memc[input+i-1] = EOS
+ i = stridxs ("]", Memc[ksection])
+ call strcpy (",append]", Memc[ksection+i-1], SZ_LINE)
+ } else
+ Memc[ksection] = EOS
+ if (output[1] == EOS)
+ call strcpy (Memc[input], Memc[name], SZ_LINE)
+ else
+ call strcpy (output, Memc[name], SZ_LINE)
+
+ switch (fmt) {
+ case ECHELLE:
+ ;
+ case MULTISPEC:
+ if (streq (Memc[input], Memc[name])) {
+ call strcat (".ms", Memc[name], SZ_LINE)
+ call strcat (Memc[ksection], Memc[name], SZ_LINE)
+ }
+ case NORM:
+ if (streq (Memc[input], Memc[name])) {
+ call strcat (".norm", Memc[name], SZ_LINE)
+ call strcat (Memc[ksection], Memc[name], SZ_LINE)
+ }
+ case FLAT:
+ if (streq (Memc[input], Memc[name])) {
+ call strcat (".flat", Memc[name], SZ_LINE)
+ call strcat (Memc[ksection], Memc[name], SZ_LINE)
+ }
+ case RATIO:
+ if (streq (Memc[input], Memc[name])) {
+ call strcat (".ratio", Memc[name], SZ_LINE)
+ call strcat (Memc[ksection], Memc[name], SZ_LINE)
+ }
+ case DIFF:
+ if (streq (Memc[input], Memc[name])) {
+ call strcat (".diff", Memc[name], SZ_LINE)
+ call strcat (Memc[ksection], Memc[name], SZ_LINE)
+ }
+ case FIT:
+ if (streq (Memc[input], Memc[name])) {
+ call strcat (".fit", Memc[name], SZ_LINE)
+ call strcat (Memc[ksection], Memc[name], SZ_LINE)
+ }
+ case NOISE:
+ Memc[name] = EOS
+ }
+
+
+ # Set the review graph title.
+ call sprintf (Memc[str], SZ_LINE, "%s: %s - Aperture %s")
+ call pargstr (image)
+ call pargstr (IM_TITLE(in))
+ call pargi (AP_ID(ap))
+
+ gt = gt_init ()
+ call gt_sets (gt, GTTITLE, Memc[str])
+
+ # Query the user whether to review the extraction.
+ call sprintf (Memc[str], SZ_LINE,
+ "Review extracted spectrum for aperture %d from %s?")
+ call pargi (AP_ID(ap))
+ call pargstr (image)
+
+ # If reviewing graph the spectrum, do a cursor loop, and allow
+ # the user to skip the output or define a new output image.
+ if (ap_answer ("ansreview1", Memc[str])) {
+ call ap_graph1 (gt, Memr[spec], ny, nsubaps)
+
+ if (fmt == ONEDSPEC && nsubaps == 1) {
+ call printf (
+ "Output image name [use # to skip output] (%s): ")
+ call pargstr (Memc[name])
+ call flush (STDOUT)
+ if (scan() != EOF) {
+ call gargwrd (Memc[str], SZ_LINE)
+ if (Memc[str] == '#') {
+ call gt_free (gt)
+ call sfree (sp)
+ return
+ }
+ if (Memc[str] != EOS)
+ call strcpy (Memc[str], Memc[name], SZ_LINE)
+ }
+ }
+ }
+
+ # Output the image.
+ switch (fmt) {
+ case MULTISPEC:
+ if (iap == 1) {
+ out = immap (Memc[name], NEW_COPY, in)
+
+ IM_PIXTYPE(out) = TY_REAL
+ IM_NDIM(out) = 1
+ IM_LEN(out, 1) = ny
+ IM_LEN(out, 2) = nsubaps * naps
+ IM_LEN(out, 3) = 1
+ if (extras) {
+ if (sky != NULL)
+ IM_LEN(out, 3) = IM_LEN(out, 3) + 1
+ if (raw != NULL)
+ IM_LEN(out, 3) = IM_LEN(out, 3) + 1
+ if (sig != NULL)
+ IM_LEN(out, 3) = IM_LEN(out, 3) + 1
+ }
+ if (IM_LEN(out, 2) > 1)
+ IM_NDIM(out) = 2
+ if (IM_LEN(out, 3) > 1)
+ IM_NDIM(out) = 3
+
+ apmw = apmw_open (in, out, dispaxis, nsubaps*naps, ny)
+
+ # Write BAND IDs.
+ k = 1
+ call sprintf (Memc[str1], SZ_LINE, "BANDID%d")
+ call pargi (k)
+ call sprintf (Memc[str], SZ_LINE,
+ "spectrum - background %s, weights %s, clean %s")
+ call pargstr (bkg)
+ call pargstr (wt)
+ call pargstr (clean)
+ call imastr (out, Memc[str1], Memc[str])
+ k = k + 1
+ if (extras) {
+ if (raw != NULL) {
+ call sprintf (Memc[str1], SZ_LINE, "BANDID%d")
+ call pargi (k)
+ call sprintf (Memc[str], SZ_LINE,
+ "raw - background %s, weights none, clean no")
+ call pargstr (bkg)
+ call imastr (out, Memc[str1], Memc[str])
+ k = k + 1
+ }
+ if (sky != NULL) {
+ call sprintf (Memc[str1], SZ_LINE, "BANDID%d")
+ call pargi (k)
+ call sprintf (Memc[str], SZ_LINE,
+ "background - background %s")
+ call pargstr (bkg)
+ call imastr (out, Memc[str1], Memc[str])
+ k = k + 1
+ }
+ if (sig != NULL) {
+ call sprintf (Memc[str1], SZ_LINE, "BANDID%d")
+ call pargi (k)
+ call sprintf (Memc[str], SZ_LINE,
+ "sigma - background %s, weights %s, clean %s")
+ call pargstr (bkg)
+ call pargstr (wt)
+ call pargstr (clean)
+ call imastr (out, Memc[str1], Memc[str])
+ }
+ }
+
+ do k = 1, naps {
+ low = AP_CEN(aps[k],apaxis) + AP_LOW(aps[k],apaxis)
+ high = AP_CEN(aps[k],apaxis) + AP_HIGH(aps[k],apaxis)
+ step = (high - low) / nsubaps
+ low = low - step
+ do l = 1, nsubaps {
+ apid = AP_ID(aps[k]) + (l - 1) * 1000
+ low = low + step
+ high = low + step
+ call apmw_setap (apmw, (k-1)*nsubaps+l,
+ apid, AP_BEAM(aps[k]), low, high)
+ }
+ }
+ do k = 1, naps {
+ if (AP_TITLE(aps[k]) != NULL) {
+ do l = 1, nsubaps {
+ call sprintf (Memc[str], SZ_LINE, "APID%d")
+ call pargi ((k-1)*nsubaps+l)
+ call imastr (out, Memc[str],
+ Memc[AP_TITLE(aps[k])])
+ }
+ }
+ }
+ }
+
+ do l = 1, nsubaps {
+ k = (iap - 1) * nsubaps + l
+ buf = impl2r (out, k)
+ call amovr (Memr[spec+(l-1)*ny], Memr[buf], ny)
+ if (extras) {
+ m = 2
+ if (raw != NULL) {
+ buf = impl3r (out, k, m)
+ call amovr (Memr[raw+(l-1)*ny], Memr[buf], ny)
+ m = m + 1
+ }
+ if (sky != NULL) {
+ buf = impl3r (out, k, m)
+ call amovr (Memr[sky+(l-1)*ny], Memr[buf], ny)
+ m = m + 1
+ }
+ if (sig != NULL) {
+ buf = impl3r (out, k, m)
+ call amovr (Memr[sig+(l-1)*ny], Memr[buf], ny)
+ m = m + 1
+ }
+ }
+ }
+ if (iap == naps) {
+ call apmw_saveim (apmw, out, fmt)
+ call apmw_close (apmw)
+ call imunmap (out)
+ }
+
+ if (Memc[name] != EOS) {
+ call sprintf (Memc[str], SZ_LINE,
+ "EXTRACT - Aperture %d from %s --> %s")
+ call pargi (AP_ID(ap))
+ call pargstr (image)
+ call pargstr (Memc[name])
+ call ap_log (Memc[str], YES, YES, NO)
+ call ap_plot1 (gt, Memr[spec], ny, nsubaps)
+ }
+
+ case ECHELLE:
+ do l = 1, nsubaps {
+ if (nsubaps == 1)
+ call strcpy (Memc[name], Memc[name1], SZ_LINE)
+ else {
+ call sprintf (Memc[name1], SZ_LINE, "%s%0*d")
+ call pargstr (Memc[name])
+ call pargi (int(log10(real(nsubaps)))+1)
+ call pargi (l)
+ }
+ if (streq (Memc[input], Memc[name])) {
+ call strcat (".ec", Memc[name1], SZ_LINE)
+ call strcat (Memc[ksection], Memc[name1], SZ_LINE)
+ }
+
+ if (iap == 1) {
+ out = immap (Memc[name1], NEW_COPY, in)
+
+ IM_PIXTYPE(out) = TY_REAL
+ IM_NDIM(out) = 1
+ IM_LEN(out, 1) = ny
+ IM_LEN(out, 2) = naps
+ IM_LEN(out, 3) = 1
+ if (extras) {
+ if (sky != NULL)
+ IM_LEN(out, 3) = IM_LEN(out, 3) + 1
+ if (raw != NULL)
+ IM_LEN(out, 3) = IM_LEN(out, 3) + 1
+ if (sig != NULL)
+ IM_LEN(out, 3) = IM_LEN(out, 3) + 1
+ }
+ if (IM_LEN(out, 2) > 1)
+ IM_NDIM(out) = 2
+ if (IM_LEN(out, 3) > 1)
+ IM_NDIM(out) = 3
+
+ apmw = apmw_open (in, out, dispaxis, naps, ny)
+
+ # Write BAND IDs.
+ k = 1
+ call sprintf (Memc[str1], SZ_LINE, "BANDID%d")
+ call pargi (k)
+ call sprintf (Memc[str], SZ_LINE,
+ "spectrum - background %s, weights %s, clean %s")
+ call pargstr (bkg)
+ call pargstr (wt)
+ call pargstr (clean)
+ call imastr (out, Memc[str1], Memc[str])
+ k = k + 1
+ if (extras) {
+ if (raw != NULL) {
+ call sprintf (Memc[str1], SZ_LINE, "BANDID%d")
+ call pargi (k)
+ call sprintf (Memc[str], SZ_LINE,
+ "raw - background %s, weights none, clean no")
+ call pargstr (bkg)
+ call imastr (out, Memc[str1], Memc[str])
+ k = k + 1
+ }
+ if (sky != NULL) {
+ call sprintf (Memc[str1], SZ_LINE, "BANDID%d")
+ call pargi (k)
+ call sprintf (Memc[str], SZ_LINE,
+ "background - background %s")
+ call pargstr (bkg)
+ call imastr (out, Memc[str1], Memc[str])
+ k = k + 1
+ }
+ if (sig != NULL) {
+ call sprintf (Memc[str1], SZ_LINE, "BANDID%d")
+ call pargi (k)
+ call sprintf (Memc[str], SZ_LINE,
+ "sigma - background %s, weights %s, clean %s")
+ call pargstr (bkg)
+ call pargstr (wt)
+ call pargstr (clean)
+ call imastr (out, Memc[str1], Memc[str])
+ }
+ }
+
+ # Write keyword to allow matching by subaperture.
+ if (nsubaps > 1)
+ call imaddi (out, "SUBAP", l)
+
+ do k = 1, naps {
+ low = AP_CEN(aps[k],apaxis) + AP_LOW(aps[k],apaxis)
+ high = AP_CEN(aps[k],apaxis) + AP_HIGH(aps[k],apaxis)
+ step = (high - low) / nsubaps
+ call apmw_setap (apmw, k, AP_ID(aps[k]),
+ AP_BEAM(aps[k]), low+(l-1)*step, low+l*step)
+ }
+ do k = 1, naps {
+ if (AP_TITLE(aps[k]) != NULL) {
+ call sprintf (Memc[str], SZ_LINE, "APID%d")
+ call pargi (k)
+ call imastr (out, Memc[str],
+ Memc[AP_TITLE(aps[k])])
+ }
+ }
+ } else {
+ if (l == 1)
+ out = outsave
+ else
+ out = immap (Memc[name1], READ_WRITE, 0)
+ }
+
+ k = iap
+ buf = impl2r (out, k)
+ call amovr (Memr[spec+(l-1)*ny], Memr[buf], ny)
+ if (extras) {
+ m = 2
+ if (raw != NULL) {
+ buf = impl3r (out, k, m)
+ call amovr (Memr[raw+(l-1)*ny], Memr[buf], ny)
+ m = m + 1
+ }
+ if (sky != NULL) {
+ buf = impl3r (out, k, m)
+ call amovr (Memr[sky+(l-1)*ny], Memr[buf], ny)
+ m = m + 1
+ }
+ if (sig != NULL) {
+ buf = impl3r (out, k, m)
+ call amovr (Memr[sig+(l-1)*ny], Memr[buf], ny)
+ m = m + 1
+ }
+ }
+
+ if (iap == 1) {
+ call apmw_saveim (apmw, out, fmt)
+ call apmw_close (apmw)
+ }
+ if (l != 1 || iap == naps)
+ call imunmap (out)
+ if (l == 1)
+ outsave = out
+
+ if (nsubaps == 1) {
+ call sprintf (Memc[str], SZ_LINE,
+ "EXTRACT - Aperture %d from %s --> %s")
+ call pargi (AP_ID(ap))
+ call pargstr (image)
+ call pargstr (Memc[name1])
+ } else {
+ call sprintf (Memc[str], SZ_LINE,
+ "EXTRACT - Aperture %d-%d from %s --> %s")
+ call pargi (AP_ID(ap))
+ call pargi (l)
+ call pargstr (image)
+ call pargstr (Memc[name1])
+ }
+ call ap_log (Memc[str], YES, YES, NO)
+ }
+
+ call ap_plot1 (gt, Memr[spec], ny, nsubaps)
+
+ case ONEDSPEC:
+ do l = 1, nsubaps {
+ apid = AP_ID(ap) + (l - 1) * 1000
+ low = AP_CEN(ap,apaxis) + AP_LOW(ap,apaxis)
+ high = AP_CEN(ap,apaxis) + AP_HIGH(ap,apaxis)
+ step = (high - low) / nsubaps
+ low = low + (l - 1) * step
+ high = low + step
+
+ call sprintf (Memc[str], SZ_LINE, "%s.%0*d")
+ call pargstr (Memc[name])
+ call pargi (int(log10(real(nsubaps)))+4)
+ call pargi (apid)
+ out = immap (Memc[str], NEW_COPY, in)
+ call sprintf (Memc[str], SZ_LINE,
+ "EXTRACT - Aperture %d from %s --> %s.%0*d")
+ call pargi (apid)
+ call pargstr (image)
+ call pargstr (Memc[name])
+ call pargi (int(log10(real(nsubaps)))+4)
+ call pargi (apid)
+ call ap_log (Memc[str], YES, YES, NO)
+
+ apmw = apmw_open (in, out, dispaxis, 1, ny)
+ call apmw_setap (apmw, 1, apid, AP_BEAM(ap), low, high)
+ if (AP_TITLE(ap) != NULL)
+ call imastr (out, "APID1", Memc[AP_TITLE(ap)])
+
+ IM_PIXTYPE(out) = TY_REAL
+ IM_NDIM(out) = 1
+ IM_LEN(out, 1) = ny
+ IM_LEN(out, 2) = 1
+ IM_LEN(out, 3) = 1
+ if (extras) {
+ if (sky != NULL)
+ IM_LEN(out, 3) = IM_LEN(out, 3) + 1
+ if (raw != NULL)
+ IM_LEN(out, 3) = IM_LEN(out, 3) + 1
+ if (sig != NULL)
+ IM_LEN(out, 3) = IM_LEN(out, 3) + 1
+ }
+ if (IM_LEN(out, 2) > 1)
+ IM_NDIM(out) = 2
+ if (IM_LEN(out, 3) > 1)
+ IM_NDIM(out) = 3
+
+ # Write BAND IDs.
+ k = 1
+ call sprintf (Memc[str1], SZ_LINE, "BANDID%d")
+ call pargi (k)
+ call sprintf (Memc[str], SZ_LINE,
+ "spectrum: background %s, weights %s, clean %s")
+ call pargstr (bkg)
+ call pargstr (wt)
+ call pargstr (clean)
+ call imastr (out, Memc[str1], Memc[str])
+ k = k + 1
+ if (extras) {
+ if (raw != NULL) {
+ call sprintf (Memc[str1], SZ_LINE, "BANDID%d")
+ call pargi (k)
+ call sprintf (Memc[str], SZ_LINE,
+ "spectrum: background %s, weights none, clean no")
+ call pargstr (bkg)
+ call imastr (out, Memc[str1], Memc[str])
+ k = k + 1
+ }
+ if (sky != NULL) {
+ call sprintf (Memc[str1], SZ_LINE, "BANDID%d")
+ call pargi (k)
+ call sprintf (Memc[str], SZ_LINE,
+ "background: background %s")
+ call pargstr (bkg)
+ call imastr (out, Memc[str1], Memc[str])
+ k = k + 1
+ }
+ if (sig != NULL) {
+ call sprintf (Memc[str1], SZ_LINE, "BANDID%d")
+ call pargi (k)
+ call sprintf (Memc[str], SZ_LINE,
+ "sigma - background %s, weights %s, clean %s")
+ call pargstr (bkg)
+ call pargstr (wt)
+ call pargstr (clean)
+ call imastr (out, Memc[str1], Memc[str])
+ }
+ }
+
+ buf = impl2r (out, 1)
+ call amovr (Memr[spec+(l-1)*ny], Memr[buf], ny)
+ if (extras) {
+ m = 2
+ if (raw != NULL) {
+ buf = impl3r (out, 1, m)
+ call amovr (Memr[raw+(l-1)*ny], Memr[buf], ny)
+ m = m + 1
+ }
+ if (sky != NULL) {
+ buf = impl3r (out, 1, m)
+ call amovr (Memr[sky+(l-1)*ny], Memr[buf], ny)
+ m = m + 1
+ }
+ if (sig != NULL) {
+ buf = impl3r (out, 1, m)
+ call amovr (Memr[sig+(l-1)*ny], Memr[buf], ny)
+ m = m + 1
+ }
+ }
+
+ call apmw_saveim (apmw, out, fmt)
+ call apmw_close (apmw)
+ call imunmap (out)
+
+ }
+
+ call ap_plot1 (gt, Memr[spec], ny, nsubaps)
+
+ case STRIP:
+ do l = 1, nsubaps {
+ apid = AP_ID(ap) + (l - 1) * 1000
+ low = AP_CEN(ap,apaxis) + AP_LOW(ap,apaxis)
+ high = AP_CEN(ap,apaxis) + AP_HIGH(ap,apaxis)
+ step = (high - low) / nsubaps
+ low = low + (l - 1) * step
+ high = low + step
+
+ call sprintf (Memc[str], SZ_LINE, "%s.%0*d")
+ call pargstr (Memc[name])
+ call pargi (int(log10(real(nsubaps)))+4)
+ call pargi (apid)
+ out = immap (Memc[str], NEW_COPY, in)
+ call sprintf (Memc[str], SZ_LINE,
+ "EXTRACT - Aperture %d from %s --> %s.%0*d")
+ call pargi (apid)
+ call pargstr (image)
+ call pargstr (Memc[name])
+ call pargi (int(log10(real(nsubaps)))+4)
+ call pargi (apid)
+ call ap_log (Memc[str], YES, YES, NO)
+
+ apmw = apmw_open (in, out, dispaxis, 1, ny)
+ call apmw_setap (apmw, 1, apid, AP_BEAM(ap), low, high)
+ call sprintf (Memc[str], SZ_LINE, "%s - Aperture %d")
+ call pargstr (IM_TITLE(out))
+ call pargi (AP_ID(ap))
+ call strcpy (Memc[str], IM_TITLE(out), SZ_IMTITLE)
+ if (AP_TITLE(ap) != NULL)
+ call imastr (out, "APID1", Memc[AP_TITLE(ap)])
+
+ IM_PIXTYPE(out) = TY_REAL
+ IM_NDIM(out) = 2
+ IM_LEN(out, 1) = ny
+ IM_LEN(out, 2) = high - low + 1
+
+ if (profile == NULL)
+ call ap_strip (ap, low, high, out, dbuf, nc, nl, c1, l1,
+ sbuf, nx, ny, xs, ys)
+ else
+ call ap_pstrip (ap, low, high, out, gain, Memr[spec],
+ Memr[profile], nx, ny, xs, ys)
+
+ call apmw_saveim (apmw, out, fmt)
+ call apmw_close (apmw)
+ call imunmap (out)
+ }
+
+ call ap_plot1 (gt, Memr[spec], ny, nsubaps)
+
+ case NORM, FLAT:
+ if (iap == 1) {
+ out = immap (Memc[name], NEW_COPY, in)
+ IM_PIXTYPE(out) = TY_REAL
+ if (imaccf (out, "CCDMEAN") == YES)
+ call imdelf (out, "CCDMEAN")
+ call ap_fitspec (ap, in, Memr[spec], ny)
+ k = YES
+ } else {
+ call ap_fitspec (ap, in, Memr[spec], ny)
+ k = NO
+ }
+ if (apaxis == 1) {
+ if (fmt == NORM)
+ call ap_lnorm (ap, out, gain, dbuf, nc, nl, c1, l1,
+ Memr[spec], ny, ys, k)
+ else
+ call ap_lflat (ap, out, dbuf, nc, nl, c1, l1, Memr[spec],
+ sbuf, Memr[profile], nx, ny, xs, ys, k)
+ } else {
+ if (fmt == NORM)
+ call ap_cnorm (ap, out, gain, dbuf, nc, nl, c1, l1,
+ Memr[spec], ny, ys, k)
+ else
+ call ap_cflat (ap, out, dbuf, nc, nl, c1, l1, Memr[spec],
+ sbuf, Memr[profile], nx, ny, xs, ys, k)
+ }
+ if (iap == naps)
+ call imunmap (out)
+
+ if (Memc[name] != EOS) {
+ call sprintf (Memc[str], SZ_LINE,
+ "EXTRACT - Aperture %d from %s --> %s")
+ call pargi (AP_ID(ap))
+ call pargstr (image)
+ call pargstr (Memc[name])
+ call ap_log (Memc[str], YES, YES, NO)
+ call ap_plot1 (gt, Memr[spec], ny, nsubaps)
+ }
+
+ case RATIO, FIT:
+ if (iap == 1) {
+ out = immap (Memc[name], NEW_COPY, in)
+ IM_PIXTYPE(out) = TY_REAL
+ k = YES
+ } else
+ k = NO
+ if (apaxis == 1) {
+ switch (fmt) {
+ case RATIO:
+ call ap_lflat (ap, out, dbuf, nc, nl, c1, l1, Memr[spec],
+ sbuf, Memr[profile], nx, ny, xs, ys, k)
+ case FIT:
+ call ap_lfit (ap, out, gain, Memr[spec], Memr[profile],
+ nx, ny, xs, ys, k)
+ }
+ } else {
+ switch (fmt) {
+ case RATIO:
+ call ap_cflat (ap, out, dbuf, nc, nl, c1, l1, Memr[spec],
+ sbuf, Memr[profile], nx, ny, xs, ys, k)
+ case FIT:
+ call ap_cfit (ap, out, gain, Memr[spec], Memr[profile],
+ nx, ny, xs, ys, k)
+ }
+ }
+ if (iap == naps)
+ call imunmap (out)
+
+ if (Memc[name] != EOS) {
+ call sprintf (Memc[str], SZ_LINE,
+ "EXTRACT - Aperture %d from %s --> %s")
+ call pargi (AP_ID(ap))
+ call pargstr (image)
+ call pargstr (Memc[name])
+ call ap_log (Memc[str], YES, YES, NO)
+ call ap_plot1 (gt, Memr[spec], ny, nsubaps)
+ }
+
+ case DIFF:
+ if (iap == 1) {
+ out = immap (Memc[name], NEW_COPY, in)
+ IM_PIXTYPE(out) = TY_REAL
+ do k = 1, IM_LEN(in,2) {
+ buf = impl2r (out, k)
+ call amovr (Memr[imgl2r(in,k)], Memr[buf], IM_LEN(out,1))
+ }
+ k = NO
+ } else
+ k = NO
+ if (apaxis == 1)
+ call ap_ldiff (ap, out, gain, dbuf, nc, nl, c1, l1, Memr[spec],
+ Memr[profile], nx, ny, xs, ys, k)
+ else
+ call ap_cdiff (ap, out, gain, dbuf, nc, nl, c1, l1, Memr[spec],
+ Memr[profile], nx, ny, xs, ys, k)
+ if (iap == naps)
+ call imunmap (out)
+
+ if (Memc[name] != EOS) {
+ call sprintf (Memc[str], SZ_LINE,
+ "EXTRACT - Aperture %d from %s --> %s")
+ call pargi (AP_ID(ap))
+ call pargstr (image)
+ call pargstr (Memc[name])
+ call ap_log (Memc[str], YES, YES, NO)
+ call ap_plot1 (gt, Memr[spec], ny, nsubaps)
+ }
+
+ case NOISE:
+ if (iap == 1) {
+ low = clgetr ("dmin")
+ high = clgetr ("dmax")
+ l = clgetr ("nbins")
+ if (high < low) {
+ step = low; low = high; high = step
+ }
+ step = (high - low) / l
+ call malloc (sum2, l, TY_REAL)
+ call malloc (sum4, l, TY_REAL)
+ call malloc (nsum, l, TY_INT)
+ call aclrr (Memr[sum2], l)
+ call aclrr (Memr[sum4], l)
+ call aclri (Memi[nsum], l)
+ }
+ call ap_noise (ap, gain, dbuf, nc, nl, c1, l1, sbuf, Memr[spec],
+ Memr[profile], nx, ny, xs, ys, Memr[sum2], Memr[sum4],
+ Memi[nsum], l, low, high)
+ if (iap == naps) {
+ do k = 0, l-1 {
+ m = Memi[nsum+k]
+ if (m > 10) {
+ Memr[sum2+k] = sqrt (Memr[sum2+k] / (m - 1))
+ step = max (0., Memr[sum4+k] / m - Memr[sum2+k]**2)
+ Memr[sum4+k] = sqrt (sqrt (step / m))
+ } else {
+ Memr[sum2+k] = 0.
+ Memr[sum4+k] = 0.
+ }
+ }
+ call ap_nplot (image, in, Memr[sum2], Memr[sum4], l,
+ low, high)
+ call mfree (sum2, TY_REAL)
+ call mfree (sum4, TY_REAL)
+ call mfree (nsum, TY_INT)
+ }
+
+ if (Memc[name] != EOS) {
+ call sprintf (Memc[str], SZ_LINE,
+ "EXTRACT - Aperture %d from %s --> %s")
+ call pargi (AP_ID(ap))
+ call pargstr (image)
+ call pargstr (Memc[name])
+ call ap_log (Memc[str], YES, YES, NO)
+ call ap_plot1 (gt, Memr[spec], ny, nsubaps)
+ }
+ }
+
+ call gt_free (gt)
+ call sfree (sp)
+end
+
+
+# AP_SUM -- Simple, unweighted aperture sum.
+
+procedure ap_sum (ap, dbuf, nc, nl, c1, l1, sbuf, nx, ny, xs, ys, spec,
+ nsubaps, asi)
+
+pointer ap # Aperture structure
+pointer dbuf # Data buffer
+int nc, nl # Size of data buffer
+int c1, l1 # Origin of data buffer
+pointer sbuf # Sky values (NULL if none)
+int nx, ny # Size of profile array
+int xs[ny], ys # Origin of sky array
+real spec[ny, nsubaps] # Spectrum
+int nsubaps # Number of subapertures
+pointer asi # Interpolator for edge pixel weighting
+
+int i, ix, iy, ix1, ix2
+real low, high, step, x1, x2, wt1, wt2, s, sval, skyval
+real ap_cveval()
+pointer cv, data, sky
+errchk asifit
+
+begin
+ i = AP_AXIS(ap)
+ low = AP_CEN(ap,i) + AP_LOW(ap,i)
+ high = AP_CEN(ap,i) + AP_HIGH(ap,i)
+ step = (high - low) / nsubaps
+ cv = AP_CV(ap)
+ do iy = 1, ny {
+ s = ap_cveval (cv, real (iy + ys - 1)) - c1 + 1
+ call ap_asifit (dbuf+(iy+ys-1-l1)*nc, nc, xs[iy]-c1+1,
+ low+s, high+s, data, asi)
+# data = dbuf + (iy + ys - 1 - l1) * nc + xs[iy] - c1 - 1
+# if (asi != NULL)
+# call asifit (asi, Memr[data], nc-xs[iy]+c1)
+ do i = 1, nsubaps {
+ x1 = max (0.5, low + (i - 1) * step + s) + c1 - xs[iy]
+ x2 = min (nc + 0.49, low + i * step + s) + c1 - xs[iy]
+ if (x2 <= x1) {
+ spec[iy,i] = 0.
+ next
+ }
+ ix1 = nint (x1)
+ ix2 = nint (x2)
+
+ # Compute end pixel weights. Remember asi is offset by 1.
+ call ap_edge (asi, x1+1, x2+1, wt1, wt2)
+
+ # Sum pixels.
+ sval = wt1 * Memr[data+ix1] + wt2 * Memr[data+ix2]
+ do ix = ix1+1, ix2-1
+ sval = sval + Memr[data+ix]
+
+ # Subtract sky if desired.
+ if (sbuf != NULL) {
+ sky = sbuf + (iy - 1) * nx - 1
+ skyval = wt1 * Memr[sky+ix1] + wt2 * Memr[sky+ix2]
+ do ix = ix1+1, ix2-1
+ skyval = skyval + Memr[sky+ix]
+ sval = sval - skyval
+ }
+
+ # Save extracted pixel value.
+ spec[iy,i] = sval
+ }
+ }
+end
+
+
+# AP_EDGE -- Compute edge weights.
+
+procedure ap_edge (asi, x1, x2, wt1, wt2)
+
+pointer asi #I Image interpolator pointer
+real x1, x2 #I Aperture edges
+real wt1, wt2 #I Weights
+
+int ix1, ix2
+real a, b
+real asieval(), asigrl()
+
+begin
+ # Edge pixel centers.
+ ix1 = nint (x1)
+ ix2 = nint (x2)
+
+ # Default weights are fractions of pixel.
+ if (ix1 == ix2) {
+ wt1 = (x2 - x1)
+ wt2 = 0
+ } else {
+ wt1 = (ix1 - x1 + 0.5)
+ wt2 = (x2 - ix2 + 0.5)
+ }
+
+ # If there is an interpolator compute fraction of integral.
+ # We require that data and integrals be positive.
+ if (asi != NULL) {
+ if (asieval (asi, real(ix1)) > 0) {
+ b = asigrl (asi, ix1-0.5, ix1+0.5)
+ if (b > 0) {
+ if (ix1 == ix2)
+ a = asigrl (asi, x1, x2)
+ else
+ a = asigrl (asi, x1, ix1+0.5)
+ if (a > 0 && a < b)
+ wt1 = a / b
+ }
+ }
+ if (ix1 != ix2 && asieval (asi, real(ix2)) > 0) {
+ b = asigrl (asi, ix2-0.5, ix2+0.5)
+ if (b > 0) {
+ a = asigrl (asi, ix2-0.5, x2)
+ if (a > 0 && a < b)
+ wt2 = a / b
+ }
+ }
+ }
+end
+
+
+# AP_STRIP -- Simple, unweighted aperture strip.
+# Interpolate so that the lower edge of the aperture is the first pixel.
+
+procedure ap_strip (ap, aplow, aphigh, out, dbuf, nc, nl, c1, l1, sbuf, nx, ny,
+ xs, ys)
+
+pointer ap # Aperture structure
+real aplow, aphigh # Aperture limits
+pointer out # Output IMIO pointer
+pointer dbuf # Data buffer
+int nc, nl # Size of data buffer
+int c1, l1 # Origin of data buffer
+pointer sbuf # Sky values (NULL if none)
+int nx, ny # Size of profile array
+int xs[ny], ys # Origin of sky array
+
+int i, na, iy, ix1, ix2, nasi
+real low, high, s, x, ap_cveval(), asieval()
+pointer obuf, cv, asi, data, sky, ptr, imps2r()
+
+begin
+ i = AP_AXIS(ap)
+ low = aplow - c1 + 1
+ high = aphigh - c1 + 1
+ cv = AP_CV(ap)
+ call asiinit (asi, II_LINEAR)
+
+ na = IM_LEN(out,2)
+ obuf = imps2r (out, 1, ny, 1, na)
+ call aclrr (Memr[obuf], na * ny)
+
+ do iy = 1, ny {
+ i = iy + ys - 1
+ s = ap_cveval (cv, real (i))
+ ix1 = max (1, nint (low + s) - 1)
+ ix2 = min (nc, nint (high + s) + 1)
+ nasi = ix2 - ix1 + 1
+ if (nasi < 3)
+ next
+ data = dbuf + (i - l1) * nc + ix1 - 1
+ iferr (call asifit (asi, Memr[data], nasi))
+ next
+
+ x = low + s - ix1 + 1
+ ptr = obuf + iy - 1
+ if (sbuf == NULL) {
+ do i = 1, na {
+ if (x >= 1 && x <= nasi)
+ Memr[ptr] = asieval (asi, x)
+ x = x + 1.
+ ptr = ptr + ny
+ }
+ } else {
+ sky = sbuf + (iy - 1) * nx + nint (low + s) - xs[iy] + c1 - 2
+ do i = 1, na {
+ if (x >= 1 && x <= nasi)
+ Memr[ptr] = asieval (asi, x) - Memr[sky+i]
+ x = x + 1.
+ ptr = ptr + ny
+ }
+ }
+ }
+
+ call asifree (asi)
+end
+
+
+# AP_PSTRIP -- Profile based strip.
+# Interpolate the profile spectrum so that the lower aperture edge is the
+# first pixel.
+
+procedure ap_pstrip (ap, aplow, aphigh, out, gain, spec, profile, nx, ny,
+ xs, ys)
+
+pointer ap # Aperture structure
+real aplow, aphigh # Aperture limits
+pointer out # Output IMIO pointer
+real gain # Gain
+real spec[ny] # Spectrum
+real profile[ny,nx] # Profile
+int nx, ny # Size of profile array
+int xs[ny], ys # Origin of profile array
+
+int na, ix, iy
+real low, high, s, x, ap_cveval(), asieval()
+pointer sp, cv, asi, data, impl2r()
+
+begin
+ call smark (sp)
+ call salloc (data, nx, TY_REAL)
+
+ ix = AP_AXIS(ap)
+ low = aplow
+ high = aphigh
+ cv = AP_CV(ap)
+ na = IM_LEN(out,2)
+ call asiinit (asi, II_LINEAR)
+
+ do iy = 1, ny {
+ s = spec[iy] / gain
+ do ix = 1, nx
+ Memr[data+ix-1] = s * profile[iy,ix]
+ call asifit (asi, Memr[data], nx)
+ s = ap_cveval (cv, real (iy+ys-1)) - xs[iy] + 1
+ x = low + s
+ do ix = 1, na {
+ profile[iy,ix] = asieval (asi, x)
+ x = x + 1
+ }
+ }
+
+ do ix = 1, na
+ call amovr (profile[1,ix], Memr[impl2r(out,ix)], ny)
+
+ call asifree (asi)
+end
+
+
+# AP_ASIFIT -- Return interpolation pointer and data pointer.
+#
+# The main reason for this routine is to shift the origin of the data by
+# one pixel so that the interpolator may be called to evaluate across
+# the extent of the first and last pixels. This means the calling program
+# will reference asi fit between 1.5 and N+1.5. It also means the returned
+# data pointer may start before the first point but will never be
+# dereferenced outside of the data range.
+
+procedure ap_asifit (dbuf, nc, xs, low, high, data, asi)
+
+pointer dbuf #I Data buffer pointer
+int nc #I Size of data buffer
+int xs #I Start of aperture array (in dbuf coords)
+real low #I Low aperture edge (in dbuf coords)
+real high #I High aperture edge (in dbuf coords)
+pointer data #O Data pointer
+pointer asi #I ASI pointer
+
+int i, ix1, ix2, n
+real x1, x2
+pointer fit
+
+begin
+ # Check for in bounds data.
+ x1 = max (0.5, low)
+ x2 = min (nc + 0.49, high)
+ if (x1 >= x2)
+ return
+
+ # Set data pointer relative to the aperture start with an offset for
+ # one indexing; i.e. pixel i is referenced as Memr[data+i]. The
+ # aperture start may put this outside the data buffer but we expect
+ # routines using the pointer to never index outside of the buffer.
+
+ data = (dbuf + xs - 1) - 1
+
+ # If not using an interpolator we are done.
+
+ if (asi == NULL)
+ return
+
+ # If the aperture, with one extra pixel on each end for integration
+ # across the end pixel, is within the data buffer then fit an
+ # interpolator directly. Otherwise we need to use a temporary
+ # padded buffer. The origin of the fitted buffer is relative
+ # to the data pointer. Note that this means that evaluating the
+ # fit requires the aperture start coordinates to be incremented
+ # by 1.
+
+ ix1 = 0
+ ix2 = nint (x2) + 1 - (xs - 1)
+ n = ix2 + ix1 + 1
+ if (data + ix1 >= dbuf && data + ix2 <= dbuf + nc - 1) {
+ call asifit (asi, Memr[data+ix1], n)
+ return
+ }
+
+ # One or the other end point is out of bounds so to avoid potential
+ # NAN and segmentation errors use an internal array to pad.
+
+ call malloc (fit, n, TY_REAL)
+ do i = 0, n-1 {
+ if (data + i < dbuf)
+ Memr[fit+i] = Memr[dbuf]
+ else if (data + i > dbuf + nc - 1)
+ Memr[fit+i] = Memr[dbuf+nc-1]
+ else
+ Memr[fit+i] = Memr[data+i]
+ }
+ call asifit (asi, Memr[fit], n)
+ call mfree (fit, TY_REAL)
+end
diff --git a/noao/twodspec/apextract/apfind.par b/noao/twodspec/apextract/apfind.par
new file mode 100644
index 00000000..f879a4a7
--- /dev/null
+++ b/noao/twodspec/apextract/apfind.par
@@ -0,0 +1,18 @@
+# APFIND
+
+input,s,a,,,,List of input images
+apertures,s,h,"",,,Apertures
+references,s,h,"",,,"Reference images
+"
+interactive,b,h,no,,,Run task interactively?
+find,b,h,yes,,,Find apertures?
+recenter,b,h,no,,,Recenter apertures?
+resize,b,h,no,,,Resize apertures?
+edit,b,h,yes,,,"Edit apertures?
+"
+line,i,h,INDEF,1,,Dispersion line
+nsum,i,h,1,,,Number of dispersion lines to sum or median
+nfind,i,q,,,,Number of apertures to be found automatically
+minsep,r,h,5.,1.,,Minimum separation between spectra
+maxsep,r,h,1000.,1.,,Maximum separation between spectra
+order,s,h,"increasing","increasing|decreasing",,Order of apertures
diff --git a/noao/twodspec/apextract/apfind.x b/noao/twodspec/apextract/apfind.x
new file mode 100644
index 00000000..f58dd4f4
--- /dev/null
+++ b/noao/twodspec/apextract/apfind.x
@@ -0,0 +1,132 @@
+include <imhdr.h>
+include <mach.h>
+include "apertures.h"
+
+# Sort flags
+define ORDER "|increasing|decreasing|"
+
+# AP_FIND -- Find and set apertures automatically.
+
+procedure ap_find (image, line, nsum, aps, naps)
+
+char image[SZ_FNAME] # Image name
+int line # Image dispersion line
+int nsum # Number of dispersion lines to sum
+pointer aps # Aperture pointers
+int naps # Number of apertures
+
+real minsep, center
+int i, j, npts, apaxis, nfind, nx
+pointer im, imdata, title, sp, str, x, ids
+
+bool clgetb(), ap_answer()
+int apgeti(), apgwrd()
+real apgetr(), ap_center(), ap_cveval()
+
+errchk ap_getdata, ap_default
+
+begin
+ # Find apertures only if there are no other apertures defined.
+ if (naps != 0)
+ return
+
+ # Query user.
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+ call sprintf (Memc[str], SZ_LINE, "Find apertures for %s?")
+ call pargstr (image)
+ if (!ap_answer ("ansfind", Memc[str])) {
+ call sfree (sp)
+ return
+ }
+
+ if (clgetb ("verbose"))
+ call printf ("Finding apertures ...\n")
+
+ # Get CL parameters.
+ nfind = apgeti ("nfind")
+ if (nfind == 0)
+ return
+ minsep = apgetr ("minsep")
+
+ # Map the image and get the image data.
+ call ap_getdata (image, line, nsum, im, imdata, npts, apaxis, title)
+
+ # If nfind > 0 find the peaks. Otherwise divide the image evenly
+ # into apertures.
+
+ if (nfind > 0) {
+ # Allocate working memory.
+ call salloc (x, nfind+2, TY_REAL)
+
+ # Find the peaks.
+ nx = 0
+ call find_peaks (Memr[imdata], npts, 0., 1, nfind+2, minsep,
+ -MAX_REAL, Memr[x], nx)
+ #call find_peaks (Memr[imdata], npts, 0., 1, nfind+2, minsep,
+ # 0, Memr[x], nx)
+ #call asrtr (Memr[x], Memr[x], nx)
+
+ # Center on the peaks.
+ naps = 0
+ for (i = 1; i <= nx && naps < nfind; i = i + 1) {
+ center = Memr[x+i-1]
+ center = ap_center (center, Memr[imdata], npts)
+
+ if (!IS_INDEF(center)) {
+ if (mod (naps, 100) == 0)
+ call realloc (aps, naps+100, TY_POINTER)
+ if (naps == 0)
+ call ap_default (im, INDEFI, 1, apaxis, INDEFR,
+ real (line), Memi[aps+naps])
+ else
+ call ap_copy (Memi[aps], Memi[aps+naps])
+
+ AP_CEN(Memi[aps+naps], AP_AXIS(Memi[aps+naps])) = center -
+ ap_cveval (AP_CV(Memi[aps+naps]), real (line))
+ naps = naps + 1
+ }
+ }
+
+ } else {
+ nfind = abs (nfind)
+ minsep = real (npts) / nfind
+ naps = 0
+ do i = 1, nfind {
+ if (mod (naps, 100) == 0)
+ call realloc (aps, naps+100, TY_POINTER)
+ center = (i - 0.5) * minsep
+ IF (naps == 0)
+ call ap_default (im, INDEFI, 1, apaxis, INDEFR,
+ real (line), Memi[aps+naps])
+ else
+ call ap_copy (Memi[aps], Memi[aps+naps])
+
+ AP_CEN(Memi[aps+naps], AP_AXIS(Memi[aps+naps])) = center -
+ ap_cveval (AP_CV(Memi[aps+naps]), real (line))
+ naps = naps + 1
+ }
+ }
+
+ # Set the aperture ID's
+ i = apgwrd ("order", Memc[str], SZ_LINE, ORDER)
+ call ap_sort (j, Memi[aps], naps, i)
+ call ap_gids (ids)
+ call ap_ids (Memi[aps], naps, ids)
+ call ap_titles (Memi[aps], naps, ids)
+ call ap_fids (ids)
+
+ # Log the apertures found and write them to the database.
+ call sprintf (Memc[str], SZ_LINE, "FIND - %d apertures found for %s")
+ call pargi (naps)
+ call pargstr (image)
+ call ap_log (Memc[str], YES, YES, NO)
+
+ call appstr ("ansdbwrite1", "yes")
+
+ # Free memory and unmap the image.
+ call mfree (imdata, TY_REAL)
+ call mfree (title, TY_CHAR)
+ call imunmap (im)
+ call sfree (sp)
+end
diff --git a/noao/twodspec/apextract/apfindnew.x b/noao/twodspec/apextract/apfindnew.x
new file mode 100644
index 00000000..66762f78
--- /dev/null
+++ b/noao/twodspec/apextract/apfindnew.x
@@ -0,0 +1,83 @@
+include <mach.h>
+include "apertures.h"
+
+# Sort flags
+define ORDER "|increasing|decreasing|"
+
+# AP_FINDNEW -- Find and set new apertures automatically. This task is
+# called from the aperture editor so we don't want to read the image vector
+# again. It also differs from AP_FIND in that existing apertures are
+# maintained and new apertures are added.
+
+procedure ap_findnew (line, data, npts, apdef, aps, naps)
+
+int line # Dispersion line of data
+real data[npts] # Image data in which to find features
+int npts # Number of pixels
+pointer apdef # Default aperture pointer
+pointer aps # Aperture pointers
+int naps # Number of apertures returned
+
+int i, j, nx, nfind
+real center, minsep
+pointer sp, str, x, ids
+
+bool clgetb()
+int apgeti(), apgwrd()
+real apgetr(), ap_center(), ap_cveval()
+
+begin
+ # Determine the maximum number of apertures to be found and return
+ # if that limit has been reached.
+ nfind = apgeti ("nfind")
+ if (nfind <= naps)
+ return
+
+ if (clgetb ("verbose"))
+ call printf ("Finding apertures ...\n")
+
+ # Set the positions of the currently defined apertures.
+ call smark (sp)
+ call salloc (str, SZ_FNAME, TY_CHAR)
+ call salloc (x, max (nfind, naps), TY_REAL)
+ nx = naps
+ for (i = 0; i < nx; i = i + 1)
+ Memr[x+i] = AP_CEN (Memi[aps+i], AP_AXIS(Memi[aps+i])) +
+ ap_cveval (AP_CV(Memi[aps+i]), real (line))
+
+ # Find peaks not already identified.
+ minsep = apgetr ("minsep")
+ #call find_peaks (data, npts, 0., 1, nfind, minsep, 0., Memr[x], nx)
+ call find_peaks (data, npts, 0., 1, nfind, minsep, -MAX_REAL,
+ Memr[x], nx)
+ call asrtr (Memr[x+naps], Memr[x+naps], nx - naps)
+
+ # Center on the new peaks and define new apertures.
+ for (i = naps + 1; i <= nx; i = i + 1) {
+ center = Memr[x+i-1]
+ center = ap_center (center, data, npts)
+
+ if (!IS_INDEF(center)) {
+ if (mod (naps, 100) == 0)
+ call realloc (aps, naps+100, TY_POINTER)
+
+ call ap_copy (apdef, Memi[aps+naps])
+
+ AP_ID(Memi[aps+naps]) = INDEFI
+ if (AP_TITLE(Memi[aps+naps]) != NULL)
+ call mfree (AP_TITLE(Memi[aps+naps]), TY_CHAR)
+ AP_CEN(Memi[aps+naps], AP_AXIS(Memi[aps+naps])) = center -
+ ap_cveval (AP_CV(Memi[aps+naps]), real (line))
+ naps = naps + 1
+ }
+ }
+
+ # Set the aperture ID's
+ i = apgwrd ("order", Memc[str], SZ_LINE, ORDER)
+ call ap_sort (j, Memi[aps], naps, i)
+ call ap_gids (ids)
+ call ap_ids (Memi[aps], naps, ids)
+ call ap_titles (Memi[aps], naps, ids)
+ call ap_fids (ids)
+ call sfree (sp)
+end
diff --git a/noao/twodspec/apextract/apfit.par b/noao/twodspec/apextract/apfit.par
new file mode 100644
index 00000000..1d6da386
--- /dev/null
+++ b/noao/twodspec/apextract/apfit.par
@@ -0,0 +1,30 @@
+# APFIT
+
+input,s,a,,,,List of images to fit
+output,s,a,,,,List of output images
+apertures,s,h,"",,,Apertures
+fittype,s,a,"difference","fit|difference|ratio",,Type of output fit
+references,s,h,"",,,"List of reference images
+"
+interactive,b,h,yes,,,Run task interactively?
+find,b,h,yes,,,Find apertures?
+recenter,b,h,yes,,,Recenter apertures?
+resize,b,h,yes,,,Resize apertures?
+edit,b,h,yes,,,Edit apertures?
+trace,b,h,yes,,,Trace apertures?
+fittrace,b,h,yes,,,Fit traced points interactively?
+fit,b,h,yes,,,"Fit apertures?
+"
+line,i,h,INDEF,1,,Dispersion line
+nsum,i,h,10,,,Number of dispersion lines to sum or median
+threshold,r,h,10.,,,"Division threshold for ratio fit
+"
+background,s,h,"none","none|average|median|minimum|fit",,Background to subtract
+pfit,s,h,"fit1d","fit1d|fit2d",,Profile fitting type (fit1d|fit2d)
+clean,b,h,no,,,Detect and replace bad pixels?
+skybox,i,h,1,1,,Box car smoothing length for sky
+saturation,r,h,INDEF,,,Saturation level
+readnoise,s,h,"0.",,,Read out noise sigma (photons)
+gain,s,h,"1.",,,Photon gain (photons/data number)
+lsigma,r,h,4.,0.,,Lower rejection threshold
+usigma,r,h,4.,0.,,Upper rejection threshold
diff --git a/noao/twodspec/apextract/apfit.x b/noao/twodspec/apextract/apfit.x
new file mode 100644
index 00000000..67bf149d
--- /dev/null
+++ b/noao/twodspec/apextract/apfit.x
@@ -0,0 +1,737 @@
+include <imhdr.h>
+include <imset.h>
+include <pkg/gtools.h>
+include "apertures.h"
+
+
+# AP_FITSPEC -- Fit a spectrum by a smoothing function.
+
+procedure ap_fitspec (ap, in, spec, ny)
+
+pointer ap # Aperture (used for labels)
+pointer in # Input image (used for labels)
+real spec[ny] # spectrum
+int ny # Number of points in spectra
+
+int i, fd, apaxis, clgeti()
+real clgetr()
+pointer sp, str, x, wts, cv, gp, gt, ic, ic1, gt_init()
+bool ap_answer()
+data ic1 /NULL/
+errchk icg_fit, ic_fit
+
+common /apn_com/ ic, gt
+
+begin
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+ call salloc (x, ny, TY_REAL)
+ call salloc (wts, ny, TY_REAL)
+
+ do i = 1, ny {
+ Memr[x+i-1] = i
+ Memr[wts+i-1] = 1
+ }
+
+ if (ic == NULL || ic1 == NULL) {
+ call ic_open (ic)
+ ic1 = ic
+ call clgstr ("function", Memc[str], SZ_LINE)
+ call ic_pstr (ic, "function", Memc[str])
+ call ic_puti (ic, "order", clgeti ("order"))
+ call clgstr ("sample", Memc[str], SZ_LINE)
+ call ic_pstr (ic, "sample", Memc[str])
+ call ic_puti (ic, "naverage", clgeti ("naverage"))
+ call ic_puti (ic, "niterate", clgeti ("niterate"))
+ call ic_putr (ic, "low", clgetr ("low_reject"))
+ call ic_putr (ic, "high", clgetr ("high_reject"))
+ call ic_putr (ic, "grow", clgetr ("grow"))
+ call ic_pstr (ic, "ylabel", "")
+
+ gt = gt_init()
+ }
+
+ call ic_putr (ic, "xmin", 1.)
+ call ic_putr (ic, "xmax", real (ny))
+ apaxis = AP_AXIS(ap)
+ switch (apaxis) {
+ case 1:
+ call ic_pstr (ic, "xlabel", "Line")
+ case 2:
+ call ic_pstr (ic, "xlabel", "Column")
+ }
+ call gt_sets (gt, GTTYPE, "line")
+
+ # Fit spectrum by a smoothing function.
+ call sprintf (Memc[str], SZ_LINE,
+ "%s: %s - Aperture %s")
+ call pargstr (IM_HDRFILE(in))
+ call pargstr (IM_TITLE(in))
+ call pargi (AP_ID(ap))
+ call gt_sets (gt, GTTITLE, Memc[str])
+
+ # Query the user to fit the spectrum interactively.
+ call sprintf (Memc[str], SZ_LINE,
+ "Fit spectrum for aperture %d for %s interactively?")
+ call pargi (AP_ID(ap))
+ call pargstr (IM_HDRFILE(in))
+ if (ap_answer ("ansfitspec1", Memc[str])) {
+ call ap_gopen (gp)
+ call icg_fit (ic, gp, "gcur", gt, cv, Memr[x], spec,
+ Memr[wts], ny)
+ call amovkr (1., Memr[wts], ny)
+ } else
+ call ic_fit (ic, cv, Memr[x], spec, Memr[wts], ny,
+ YES, YES, YES, YES)
+
+ # Make a graph to the plot log.
+ call ap_popen (gp, fd, "fitspec")
+ if (gp != NULL) {
+ call icg_graphr (ic, gp, gt, cv, Memr[x], spec, Memr[wts], ny)
+ call ap_pclose (gp, fd)
+ }
+
+ call cvvector (cv, Memr[x], spec, ny)
+ call cvfree (cv)
+end
+
+
+procedure ap_fitfree ()
+
+pointer ic, gt
+common /apn_com/ ic, gt
+
+begin
+ call ic_closer (ic)
+ call gt_free (gt)
+end
+
+
+# AP_LNORM -- Normalize the input line apertures by the norm spectra.
+
+procedure ap_lnorm (ap, out, gain, dbuf, nc, nl, c1, l1, spec, ny, ys, init)
+
+pointer ap # Aperture structure
+pointer out # Output IMIO pointer
+real gain # Gain
+pointer dbuf # Data buffer
+int nc, nl # Size of data buffer
+int c1, l1 # Origin of data buffer
+real spec[ny] # Normalization spectrum
+int ny # Size of profile array
+int ys # Start of spectrum in image
+int init # Fill between apertures with 1?
+
+bool clgetb() # Center normalize?
+real threshold, clgetr() # Division threshold
+
+int i, ncols, nlines, ix1, ix2, iy, nsum
+real cen, low, high, s, x1, x2, sum, ap_cveval(), asumr()
+pointer cv, datain, dataout, imps2r(), impl2r()
+
+begin
+ threshold = clgetr ("threshold")
+
+ cen = AP_CEN(ap,1)
+ low = AP_CEN(ap,1) + AP_LOW(ap,1)
+ high = AP_CEN(ap,1) + AP_HIGH(ap,1)
+ cv = AP_CV(ap)
+ ncols = IM_LEN(out, 1)
+ nlines = IM_LEN(out, 2)
+
+ # Normalize by the aperture width and apply threshold.
+ call adivkr (spec, high - low, spec, ny)
+ if (clgetb ("cennorm")) {
+ sum = 0.
+ nsum = 0
+ do i = 1, nlines {
+ iy = i - ys + 1
+ if (iy < 1 || iy > ny)
+ next
+ s = cen + ap_cveval (cv, real (i))
+ ix1 = max (1, int (s))
+ ix2 = min (ncols, int (s + 1))
+ if (ix1 > ix2)
+ next
+ datain = dbuf + (i - l1) * nc + ix1 - c1
+ if (ix1 == ix2)
+ sum = sum + Memr[datain]
+ else
+ sum = sum + (ix2-s)*Memr[datain] + (s-ix1)*Memr[datain+1]
+ nsum = nsum + 1
+ }
+ if (nsum > 0) {
+ sum = (asumr (spec, ny) / ny) / (sum / nsum / gain)
+ call adivkr (spec, sum, spec, ny)
+ }
+ }
+ if (!IS_INDEF (threshold))
+ call arltr (spec, ny, threshold, threshold)
+
+ do i = 1, nlines {
+ if (init == YES) {
+ dataout = impl2r (out, i)
+ call amovkr (1., Memr[dataout], ncols)
+ }
+
+ iy = i - ys + 1
+ if (iy < 1 || iy > ny)
+ next
+ s = ap_cveval (cv, real (i))
+ x1 = max (0.5, low + s)
+ x2 = min (ncols + 0.49, high + s)
+ if (x1 > x2)
+ next
+
+ ix1 = nint (x1)
+ ix2 = nint (x2)
+
+ datain = dbuf + (i - l1) * nc + ix1 - c1
+ if (init == YES)
+ dataout = dataout + ix1 - 1
+ else
+ dataout = imps2r (out, ix1, ix2, i, i)
+ call adivkr (Memr[datain], spec[iy] * gain, Memr[dataout],
+ ix2-ix1+1)
+ }
+
+ call imaddr (out, "CCDMEAN", 1.)
+end
+
+
+# AP_CNORM -- Normalize the input column apertures by the norm spectra.
+
+procedure ap_cnorm (ap, out, gain, dbuf, nc, nl, c1, l1, spec, ny, ys, init)
+
+pointer ap # Aperture structure
+pointer out # Output IMIO pointer
+real gain # Gain
+pointer dbuf # Data buffer
+int nc, nl # Size of data buffer
+int c1, l1 # Origin of data buffer
+real spec[ny] # Normalization spectrum
+int ny # Size of profile array
+int ys # Start of spectrum in image
+int init # Fill between apertures with 1?
+
+bool clgetb() # Center normalize?
+real threshold, clgetr() # Division threshold
+
+int ncols, nlines, ix, iy, ix1, ix2, iy1, iy2, nsum
+real cen, low, high, s, sum, ap_cveval(), asumr()
+pointer sp, y1, y2, cv, datain, dataout, buf, imps2r(), impl2r()
+
+begin
+ threshold = clgetr ("threshold")
+
+ call smark (sp)
+ call salloc (y1, 2 * ny, TY_INT)
+ y1 = y1 - ys
+ y2 = y1 + ny
+
+ cen = AP_CEN(ap,2)
+ low = AP_CEN(ap,2) + AP_LOW(ap,2)
+ high = AP_CEN(ap,2) + AP_HIGH(ap,2)
+ cv = AP_CV(ap)
+ ncols = IM_LEN(out, 1)
+ nlines = IM_LEN(out, 2)
+
+ # Normalize by the aperture width and apply threshold.
+ call adivkr (spec, high - low, spec, ny)
+ if (clgetb ("cennorm")) {
+ sum = 0.
+ nsum = 0
+ do ix = ys, ys+ny-1 {
+ s = cen + ap_cveval (cv, real (ix))
+ iy1 = max (1, int (s))
+ iy2 = min (nlines, int (s + 1))
+ if (iy1 > iy2)
+ next
+ datain = dbuf + (ix - l1) * nc + iy1 - c1
+ if (iy1 == iy2)
+ sum = sum + Memr[datain]
+ else
+ sum = sum + (iy2-s)*Memr[datain] + (s-iy1)*Memr[datain+1]
+ nsum = nsum + 1
+ }
+ if (nsum > 0) {
+ sum = (asumr (spec, ny) / ny) / (sum / nsum / gain)
+ call adivkr (spec, sum, spec, ny)
+ }
+ }
+ if (!IS_INDEF (threshold))
+ call arltr (spec, ny, threshold, threshold)
+
+ do ix = ys, ys+ny-1 {
+ s = ap_cveval (cv, real (ix))
+ Memi[y1+ix] = nint (low + s)
+ Memi[y2+ix] = nint (high + s)
+ }
+ call alimi (Memi[y1+ys], 2 * ny, iy1, iy2)
+
+ do iy = 1, nlines {
+ if (init == YES) {
+ buf = impl2r (out, iy)
+ call amovkr (1., Memr[buf], ncols)
+ }
+
+ if (iy < iy1 || iy > iy2)
+ next
+
+ for (ix1=ys; ix1<=ys+ny-1; ix1=ix1+1) {
+ if (iy < Memi[y1+ix1] || iy > Memi[y2+ix1])
+ next
+ for (ix2=ix1+1; ix2<=ys+ny-1; ix2=ix2+1)
+ if (iy < Memi[y1+ix2] || iy > Memi[y2+ix2])
+ break
+ ix2 = ix2 - 1
+
+ datain = dbuf + (ix1 - l1) * nc + iy - c1
+ if (init == YES)
+ dataout = buf + ix1 - 1
+ else
+ dataout = imps2r (out, ix1, ix2, iy, iy)
+ do ix = ix1, ix2 {
+ Memr[dataout] = Memr[datain] / spec[ix-ys+1] / gain
+ datain = datain + nc
+ dataout = dataout + 1
+ }
+ ix1 = ix2
+ }
+ }
+
+ call imaddr (out, "CCDMEAN", 1.)
+
+ call sfree (sp)
+end
+
+
+# AP_LFLAT -- Flatten the input line apertures by the norm spectra.
+
+procedure ap_lflat (ap, out, dbuf, nc, nl, c1, l1, spec, sbuf, profile, nx, ny,
+ xs, ys, init)
+
+pointer ap # Aperture structure
+pointer out # Output IMIO pointer
+pointer dbuf # Data buffer
+int nc, nl # Size of data buffer
+int c1, l1 # Origin of data buffer
+real spec[ny] # Normalization spectrum
+pointer sbuf # Sky buffer
+real profile[ny,nx] # Profile
+int nx, ny # Size of profile array
+int xs[ny], ys # Start of spectrum in image
+int init # Fill between apertures with 1?
+
+real threshold, clgetr() # Division threshold
+
+int i, ncols, nlines, ix, iy, ix1, ix2
+real low, high, s, x1, x2, ap_cveval()
+pointer cv, datain, dataout, sky, imps2r(), impl2r()
+
+begin
+ threshold = clgetr ("threshold")
+ if (IS_INDEF(threshold))
+ threshold = 0.
+ threshold = max (0., threshold)
+
+ low = AP_CEN(ap,1) + AP_LOW(ap,1)
+ high = AP_CEN(ap,1) + AP_HIGH(ap,1)
+ cv = AP_CV(ap)
+ ncols = IM_LEN(out, 1)
+ nlines = IM_LEN(out, 2)
+
+ do i = 1, nlines {
+ if (init == YES) {
+ dataout = impl2r (out, i)
+ call amovkr (1., Memr[dataout], ncols)
+ }
+
+ iy = i - ys + 1
+ if (iy < 1 || iy > ny)
+ next
+ s = ap_cveval (cv, real (i))
+ x1 = max (0.5, low + s)
+ x2 = min (ncols + 0.49, high + s)
+ if (x1 > x2)
+ next
+
+ ix1 = nint (x1)
+ ix2 = nint (x2)
+
+ datain = dbuf + (i - l1) * nc + ix1 - c1
+ if (init == YES)
+ dataout = dataout + ix1 - 1
+ else
+ dataout = imps2r (out, ix1, ix2, i, i)
+ if (sbuf != NULL)
+ sky = sbuf + (iy - 1) * nx - xs[iy]
+ do ix = ix1, ix2 {
+ s = spec[iy] * profile[iy, ix-xs[iy]+1]
+ if (sbuf != NULL)
+ s = s + Memr[sky+ix]
+ if (s > threshold)
+ Memr[dataout] = Memr[datain] / s
+ else
+ Memr[dataout] = 1.
+ datain = datain + 1
+ dataout = dataout + 1
+ }
+ }
+
+ call imaddr (out, "CCDMEAN", 1.)
+end
+
+
+# AP_CFLAT -- Flatten the input column apertures by the norm spectra.
+
+procedure ap_cflat (ap, out, dbuf, nc, nl, c1, l1, spec, sbuf, profile, nx, ny,
+ xs, ys, init)
+
+pointer ap # Aperture structure
+pointer out # Output IMIO pointer
+pointer dbuf # Data buffer
+int nc, nl # Size of data buffer
+int c1, l1 # Origin of data buffer
+real spec[ny] # Normalization spectrum
+pointer sbuf # Sky buffer
+real profile[ny,nx] # Profile
+int nx, ny # Size of profile array
+int xs[ny], ys # Start of spectrum in image
+int init # Fill between apertures with 1?
+
+real threshold, clgetr() # Division threshold
+
+int ncols, nlines, ix, iy, ix1, ix2, iy1, iy2
+real low, high, s, ap_cveval()
+pointer sp, y1, y2, cv, datain, dataout, sky, buf, imps2r(), impl2r()
+
+begin
+ threshold = clgetr ("threshold")
+ if (IS_INDEF(threshold))
+ threshold = 0.
+ threshold = max (0., threshold)
+
+ call smark (sp)
+ call salloc (y1, 2 * ny, TY_INT)
+ y1 = y1 - ys
+ y2 = y1 + ny
+
+ low = AP_CEN(ap,2) + AP_LOW(ap,2)
+ high = AP_CEN(ap,2) + AP_HIGH(ap,2)
+ cv = AP_CV(ap)
+ ncols = IM_LEN(out, 1)
+ nlines = IM_LEN(out, 2)
+
+ do ix = ys, ys+ny-1 {
+ s = ap_cveval (cv, real (ix))
+ Memi[y1+ix] = nint (low + s)
+ Memi[y2+ix] = nint (high + s)
+ }
+ call alimi (Memi[y1+ys], 2 * ny, iy1, iy2)
+
+ do iy = 1, nlines {
+ if (init == YES) {
+ buf = impl2r (out, iy)
+ call amovkr (1., Memr[buf], ncols)
+ }
+
+ if (iy < iy1 || iy > iy2)
+ next
+
+ for (ix1=ys; ix1<=ys+ny-1; ix1=ix1+1) {
+ if (iy < Memi[y1+ix1] || iy > Memi[y2+ix1])
+ next
+ for (ix2=ix1+1; ix2<=ys+ny-1; ix2=ix2+1)
+ if (iy < Memi[y1+ix2] || iy > Memi[y2+ix2])
+ break
+ ix2 = ix2 - 1
+
+ datain = dbuf + (ix1 - l1) * nc + iy - c1
+ if (init == YES)
+ dataout = buf + ix1 - 1
+ else
+ dataout = imps2r (out, ix1, ix2, iy, iy)
+ if (sbuf != NULL)
+ sky = sbuf - ys * nx + iy - xs[iy]
+ do ix = ix1, ix2 {
+ s = spec[ix-ys+1] * profile[ix-ys+1, iy-xs[ix-ys+1]+1]
+ if (sbuf != NULL)
+ s = s + Memr[sky+ix*nx]
+ if (s > threshold)
+ Memr[dataout] = Memr[datain] / s
+ else
+ Memr[dataout] = 1.
+ datain = datain + nc
+ dataout = dataout + 1
+ }
+ ix1 = ix2
+ }
+ }
+
+ call imaddr (out, "CCDMEAN", 1.)
+
+ call sfree (sp)
+end
+
+
+# AP_LDIFF -- Model residuals.
+
+procedure ap_ldiff (ap, out, gain, dbuf, nc, nl, c1, l1, spec, profile, nx, ny,
+ xs, ys, init)
+
+pointer ap # Aperture structure
+pointer out # Output IMIO pointer
+real gain # Gain
+pointer dbuf # Data buffer
+int nc, nl # Size of data buffer
+int c1, l1 # Origin of data buffer
+real spec[ny] # Normalization spectrum
+real profile[ny,nx] # Profile
+int nx, ny # Size of profile array
+int xs[ny], ys # Start of spectrum in image
+int init # Fill between apertures with 1?
+
+int i, ncols, nlines, ix, iy, ix1, ix2
+real low, high, s, x1, x2, ap_cveval()
+pointer cv, datain, dataout, imps2r(), impl2r()
+
+begin
+ low = AP_CEN(ap,1) + AP_LOW(ap,1)
+ high = AP_CEN(ap,1) + AP_HIGH(ap,1)
+ cv = AP_CV(ap)
+ ncols = IM_LEN(out, 1)
+ nlines = IM_LEN(out, 2)
+
+ do i = 1, nlines {
+ if (init == YES) {
+ dataout = impl2r (out, i)
+ call aclrr (Memr[dataout], ncols)
+ }
+
+ iy = i - ys + 1
+ if (iy < 1 || iy > ny)
+ next
+ s = ap_cveval (cv, real (i))
+ x1 = max (0.5, low + s)
+ x2 = min (ncols + 0.49, high + s)
+ if (x1 > x2)
+ next
+
+ ix1 = nint (x1)
+ ix2 = nint (x2)
+
+ datain = dbuf + (i - l1) * nc + ix1 - c1
+ if (init == YES)
+ dataout = dataout + ix1 - 1
+ else
+ dataout = imps2r (out, ix1, ix2, i, i)
+ do ix = ix1, ix2 {
+ s = spec[iy] * profile[iy, ix-xs[iy]+1]
+ Memr[dataout] = (Memr[datain] - s) / gain
+ datain = datain + 1
+ dataout = dataout + 1
+ }
+ }
+end
+
+
+# AP_CDIFF -- Model residuals
+
+procedure ap_cdiff (ap, out, gain, dbuf, nc, nl, c1, l1, spec, profile, nx, ny,
+ xs, ys, init)
+
+pointer ap # Aperture structure
+pointer out # Output IMIO pointer
+real gain # Gain
+pointer dbuf # Data buffer
+int nc, nl # Size of data buffer
+int c1, l1 # Origin of data buffer
+real spec[ny] # Normalization spectrum
+real profile[ny,nx] # Profile
+int nx, ny # Size of profile array
+int xs[ny], ys # Start of spectrum in image
+int init # Fill between apertures with 1?
+
+int ncols, nlines, ix, iy, ix1, ix2, iy1, iy2
+real low, high, s, ap_cveval()
+pointer sp, y1, y2, cv, datain, dataout, buf, imps2r(), impl2r()
+
+begin
+ call smark (sp)
+ call salloc (y1, 2 * ny, TY_INT)
+ y1 = y1 - ys
+ y2 = y1 + ny
+
+ low = AP_CEN(ap,2) + AP_LOW(ap,2)
+ high = AP_CEN(ap,2) + AP_HIGH(ap,2)
+ cv = AP_CV(ap)
+ ncols = IM_LEN(out, 1)
+ nlines = IM_LEN(out, 2)
+
+ do ix = ys, ys+ny-1 {
+ s = ap_cveval (cv, real (ix))
+ Memi[y1+ix] = nint (low + s)
+ Memi[y2+ix] = nint (high + s)
+ }
+ call alimi (Memi[y1+ys], 2 * ny, iy1, iy2)
+
+ do iy = 1, nlines {
+ if (init == YES) {
+ buf = impl2r (out, iy)
+ call aclrr (Memr[buf], ncols)
+ }
+
+ if (iy < iy1 || iy > iy2)
+ next
+
+ for (ix1=ys; ix1<=ys+ny-1; ix1=ix1+1) {
+ if (iy < Memi[y1+ix1] || iy > Memi[y2+ix1])
+ next
+ for (ix2=ix1+1; ix2<=ys+ny-1; ix2=ix2+1)
+ if (iy < Memi[y1+ix2] || iy > Memi[y2+ix2])
+ break
+ ix2 = ix2 - 1
+
+ datain = dbuf + (ix1 - l1) * nc + iy - c1
+ if (init == YES)
+ dataout = buf + ix1 - 1
+ else
+ dataout = imps2r (out, ix1, ix2, iy, iy)
+ do ix = ix1, ix2 {
+ s = spec[ix-ys+1] * profile[ix-ys+1, iy-xs[ix-ys+1]+1]
+ Memr[dataout] = (Memr[datain] - s) / gain
+ datain = datain + nc
+ dataout = dataout + 1
+ }
+ ix1 = ix2
+ }
+ }
+
+ call sfree (sp)
+end
+
+
+# AP_LFIT -- Model fit
+
+procedure ap_lfit (ap, out, gain, spec, profile, nx, ny, xs, ys, init)
+
+pointer ap # Aperture structure
+pointer out # Output IMIO pointer
+real gain # Gain
+real spec[ny] # Normalization spectrum
+real profile[ny,nx] # Profile
+int nx, ny # Size of profile array
+int xs[ny], ys # Start of spectrum in image
+int init # Fill between apertures with 1?
+
+int i, ncols, nlines, ix, iy, ix1, ix2
+real low, high, s, x1, x2, ap_cveval()
+pointer cv, dataout, imps2r(), impl2r()
+
+begin
+ low = AP_CEN(ap,1) + AP_LOW(ap,1)
+ high = AP_CEN(ap,1) + AP_HIGH(ap,1)
+ cv = AP_CV(ap)
+ ncols = IM_LEN(out, 1)
+ nlines = IM_LEN(out, 2)
+
+ do i = 1, nlines {
+ if (init == YES) {
+ dataout = impl2r (out, i)
+ call aclrr (Memr[dataout], ncols)
+ }
+
+ iy = i - ys + 1
+ if (iy < 1 || iy > ny)
+ next
+ s = ap_cveval (cv, real (i))
+ x1 = max (0.5, low + s)
+ x2 = min (ncols + 0.49, high + s)
+ if (x1 > x2)
+ next
+
+ ix1 = nint (x1)
+ ix2 = nint (x2)
+
+ if (init == YES)
+ dataout = dataout + ix1 - 1
+ else
+ dataout = imps2r (out, ix1, ix2, i, i)
+ do ix = ix1, ix2 {
+ s = spec[iy] * profile[iy, ix-xs[iy]+1]
+ Memr[dataout] = s / gain
+ dataout = dataout + 1
+ }
+ }
+end
+
+
+# AP_CFIT -- Model fit
+
+procedure ap_cfit (ap, out, gain, spec, profile, nx, ny, xs, ys, init)
+
+pointer ap # Aperture structure
+pointer out # Output IMIO pointer
+real gain # Gain
+real spec[ny] # Normalization spectrum
+real profile[ny,nx] # Profile
+int nx, ny # Size of profile array
+int xs[ny], ys # Start of spectrum in image
+int init # Fill between apertures with 1?
+
+int ncols, nlines, ix, iy, ix1, ix2, iy1, iy2
+real low, high, s, ap_cveval()
+pointer sp, y1, y2, cv, dataout, buf, imps2r(), impl2r()
+
+begin
+ call smark (sp)
+ call salloc (y1, 2 * ny, TY_INT)
+ y1 = y1 - ys
+ y2 = y1 + ny
+
+ low = AP_CEN(ap,2) + AP_LOW(ap,2)
+ high = AP_CEN(ap,2) + AP_HIGH(ap,2)
+ cv = AP_CV(ap)
+ ncols = IM_LEN(out, 1)
+ nlines = IM_LEN(out, 2)
+
+ do ix = ys, ys+ny-1 {
+ s = ap_cveval (cv, real (ix))
+ Memi[y1+ix] = nint (low + s)
+ Memi[y2+ix] = nint (high + s)
+ }
+ call alimi (Memi[y1+ys], 2 * ny, iy1, iy2)
+
+ do iy = 1, nlines {
+ if (init == YES) {
+ buf = impl2r (out, iy)
+ call aclrr (Memr[buf], ncols)
+ }
+
+ if (iy < iy1 || iy > iy2)
+ next
+
+ for (ix1=ys; ix1<=ys+ny-1; ix1=ix1+1) {
+ if (iy < Memi[y1+ix1] || iy > Memi[y2+ix1])
+ next
+ for (ix2=ix1+1; ix2<=ys+ny-1; ix2=ix2+1)
+ if (iy < Memi[y1+ix2] || iy > Memi[y2+ix2])
+ break
+ ix2 = ix2 - 1
+
+ if (init == YES)
+ dataout = buf + ix1 - 1
+ else
+ dataout = imps2r (out, ix1, ix2, iy, iy)
+ do ix = ix1, ix2 {
+ s = spec[ix-ys+1] * profile[ix-ys+1, iy-xs[ix-ys+1]+1]
+ Memr[dataout] = s / gain
+ dataout = dataout + 1
+ }
+ ix1 = ix2
+ }
+ }
+
+ call sfree (sp)
+end
diff --git a/noao/twodspec/apextract/apfit1.par b/noao/twodspec/apextract/apfit1.par
new file mode 100644
index 00000000..5420917d
--- /dev/null
+++ b/noao/twodspec/apextract/apfit1.par
@@ -0,0 +1,118 @@
+# OUTPUT PARAMETERS
+
+apertures,s,h,)apall.apertures,,,>apfit.apertures
+format,s,h,)apsum.format,,,>apsum.format
+extras,b,h,)apsum.extras,,,>apsum.extras
+dbwrite,s,h,yes,,,Write to database?
+initialize,b,h,yes,,,Initialize answers?
+verbose,b,h,)_.verbose,,,"Verbose output?
+
+# DEFAULT APERTURE PARAMETERS
+"
+lower,r,h,)apdefault.lower,,,>apdefault.lower
+upper,r,h,)apdefault.upper,,,>apdefault.upper
+apidtable,s,h,)apdefault.apidtable,,,">apdefault.apidtable
+
+# DEFAULT BACKGROUND PARAMETERS
+"
+b_function,s,h,)apdefault.b_function,,,>apdefault.b_function
+b_order,i,h,)apdefault.b_order,,,>apdefault.b_order
+b_sample,s,h,)apdefault.b_sample,,,>apdefault.b_sample
+b_naverage,i,h,)apdefault.b_naverage,,,>apdefault.b_naverage
+b_niterate,i,h,)apdefault.b_niterate,,,>apdefault.b_niterate
+b_low_reject,r,h,)apdefault.b_low_reject,,,>apdefault.b_low_reject
+b_high_reject,r,h,)apdefault.b_high_reject,,,>apdefault.b_high_reject
+b_grow,r,h,)apdefault.b_grow,,,">apdefault.b_grow
+
+# APERTURE CENTERING PARAMETERS
+"
+width,r,h,)apedit.width,,,>apedit.width
+radius,r,h,)apedit.radius,,,>apedit.radius
+threshold,r,h,)apedit.threshold,,,">apedit.threshold
+
+# AUTOMATIC FINDING AND ORDERING PARAMETERS
+"
+nfind,i,h,)apfind.nfind,,,>apfind.nfind
+minsep,r,h,)apfind.minsep,,,>apfind.minsep
+maxsep,r,h,)apfind.maxsep,,,>apfind.maxsep
+order,s,h,)apfind.order,,,">apfind.order
+
+# RECENTERING PARAMETERS
+"
+aprecenter,s,h,)aprecenter.aprecenter,,,>aprecenter.aprecenter
+npeaks,r,h,)aprecenter.npeaks,,,>aprecenter.npeaks
+shift,b,h,)aprecenter.shift,,,">aprecenter.shift
+
+# RESIZING PARAMETERS
+"
+llimit,r,h,)apresize.llimit,,,>apresize.llimit
+ulimit,r,h,)apresize.ulimit,,,>apresize.ulimit
+ylevel,r,h,)apresize.ylevel,,,>apresize.ylevel
+peak,b,h,)apresize.peak,,,>apresize.peak
+bkg,b,h,)apresize.bkg,,,>apresize.bkg
+r_grow,r,h,)apresize.r_grow,,,>apresize.r_grow
+avglimits,b,h,)apresize.avglimits,,,">apresize.avglimits
+
+# EDITING PARAMETERS
+"
+e_output,s,q,,,,Output spectra rootname
+e_profiles,s,q,,,,Profile reference image
+
+# TRACING PARAMETERS
+t_nsum,i,h,)aptrace.nsum,,,>aptrace.nsum
+t_step,i,h,)aptrace.step,,,>aptrace.step
+t_nlost,i,h,)aptrace.nlost,,,>aptrace.nlost
+t_width,r,h,)apedit.width,,,>apedit.width
+t_function,s,h,)aptrace.function,,,>aptrace.function
+t_order,i,h,)aptrace.order,,,>aptrace.order
+t_sample,s,h,)aptrace.sample,,,>aptrace.sample
+t_naverage,i,h,)aptrace.naverage,,,>aptrace.naverage
+t_niterate,i,h,)aptrace.niterate,,,>aptrace.niterate
+t_low_reject,r,h,)aptrace.low_reject,,,>aptrace.low_reject
+t_high_reject,r,h,)aptrace.high_reject,,,>aptrace.high_reject
+t_grow,r,h,)aptrace.grow,,,">aptrace.grow
+
+# EXTRACTION PARAMETERS
+"
+background,s,h,)apfit.background,,,>apfit.background
+skybox,i,h,)apfit.skybox,,,>apfit.skybox
+weights,s,h,"none",,,Extraction weights (none|variance)
+pfit,s,h,)apfit.pfit,,,>apfit.pfit
+clean,b,h,)apfit.clean,,,>apfit.clean
+nclean,r,h,0.5,,,Maximum number of pixels to clean
+niterate,i,h,5,0,,Number of profile fitting iterations
+saturation,r,h,)apfit.saturation,,,>apfit.saturation
+readnoise,s,h,)apfit.readnoise,,,>apfit.readnoise
+gain,s,h,)apfit.gain,,,>apfit.gain
+lsigma,r,h,)apfit.lsigma,,,>apfit.lsigma
+usigma,r,h,)apfit.usigma,,,>apfit.usigma
+polysep,r,h,0.90,0.1,0.95,Marsh algorithm polynomial spacing
+polyorder,i,h,10,1,,Marsh algorithm polynomial order
+nsubaps,i,h,1,,,"Number of subapertures per aperture
+
+# ANSWER PARAMETERS
+"
+ansclobber,s,h,"no",,," "
+ansclobber1,s,h,"no",,," "
+ansdbwrite,s,h,"yes",,," "
+ansdbwrite1,s,h,"yes",,," "
+ansedit,s,h,"yes",,," "
+ansextract,s,h,"yes",,," "
+ansfind,s,h,"yes",,," "
+ansfit,s,h,"yes",,," "
+ansfitscatter,s,h,"yes",,," "
+ansfitsmooth,s,h,"yes",,," "
+ansfitspec,s,h,"yes",,," "
+ansfitspec1,s,h,"yes",,," "
+ansfittrace,s,h,"yes",,," "
+ansfittrace1,s,h,"yes",,," "
+ansflat,s,h,"yes",,," "
+ansmask,s,h,"yes",,," "
+ansnorm,s,h,"yes",,," "
+ansrecenter,s,h,"yes",,," "
+ansresize,s,h,"yes",,," "
+ansreview,s,h,"yes",,," "
+ansreview1,s,h,"yes",,," "
+ansscat,s,h,"yes",,," "
+anssmooth,s,h,"yes",,," "
+anstrace,s,h,"yes",,," "
diff --git a/noao/twodspec/apextract/apflat1.par b/noao/twodspec/apextract/apflat1.par
new file mode 100644
index 00000000..0fac8391
--- /dev/null
+++ b/noao/twodspec/apextract/apflat1.par
@@ -0,0 +1,117 @@
+# OUTPUT PARAMETERS
+
+format,s,h,)apsum.format,,,>apsum.format
+extras,b,h,)apsum.extras,,,>apsum.extras
+dbwrite,s,h,yes,,,Write to database?
+initialize,b,h,yes,,,Initialize answers?
+verbose,b,h,)_.verbose,,,"Verbose output?
+
+# DEFAULT APERTURE PARAMETERS
+"
+lower,r,h,)apdefault.lower,,,>apdefault.lower
+upper,r,h,)apdefault.upper,,,>apdefault.upper
+apidtable,s,h,)apdefault.apidtable,,,">apdefault.apidtable
+
+# DEFAULT BACKGROUND PARAMETERS
+"
+b_function,s,h,)apdefault.b_function,,,>apdefault.b_function
+b_order,i,h,)apdefault.b_order,,,>apdefault.b_order
+b_sample,s,h,)apdefault.b_sample,,,>apdefault.b_sample
+b_naverage,i,h,)apdefault.b_naverage,,,>apdefault.b_naverage
+b_niterate,i,h,)apdefault.b_niterate,,,>apdefault.b_niterate
+b_low_reject,r,h,)apdefault.b_low_reject,,,>apdefault.b_low_reject
+b_high_reject,r,h,)apdefault.b_high_reject,,,>apdefault.b_high_reject
+b_grow,r,h,)apdefault.b_grow,,,">apdefault.b_grow
+
+# APERTURE CENTERING PARAMETERS
+"
+width,r,h,)apedit.width,,,>apedit.width
+radius,r,h,)apedit.radius,,,>apedit.radius
+threshold,r,h,)apedit.threshold,,,">apedit.threshold
+
+# AUTOMATIC FINDING AND ORDERING PARAMETERS
+"
+nfind,i,h,)apfind.nfind,,,>apfind.nfind
+minsep,r,h,)apfind.minsep,,,>apfind.minsep
+maxsep,r,h,)apfind.maxsep,,,>apfind.maxsep
+order,s,h,)apfind.order,,,">apfind.order
+
+# RECENTERING PARAMETERS
+"
+aprecenter,s,h,)aprecenter.aprecenter,,,>aprecenter.aprecenter
+npeaks,r,h,)aprecenter.npeaks,,,>aprecenter.npeaks
+shift,b,h,)aprecenter.shift,,,">aprecenter.shift
+
+# RESIZING PARAMETERS
+"
+llimit,r,h,)apresize.llimit,,,>apresize.llimit
+ulimit,r,h,)apresize.ulimit,,,>apresize.ulimit
+ylevel,r,h,)apresize.ylevel,,,>apresize.ylevel
+peak,b,h,)apresize.peak,,,>apresize.peak
+bkg,b,h,)apresize.bkg,,,>apresize.bkg
+r_grow,r,h,)apresize.r_grow,,,>apresize.r_grow
+avglimits,b,h,)apresize.avglimits,,,">apresize.avglimits
+
+# EDITING PARAMETERS
+"
+e_output,s,q,,,,Output spectra rootname
+e_profiles,s,q,,,,Profile reference image
+
+# TRACING PARAMETERS
+t_nsum,i,h,)aptrace.nsum,,,>aptrace.nsum
+t_step,i,h,)aptrace.step,,,>aptrace.step
+t_nlost,i,h,)aptrace.nlost,,,>aptrace.nlost
+t_width,r,h,)apedit.width,,,>apedit.width
+t_function,s,h,)aptrace.function,,,>aptrace.function
+t_order,i,h,)aptrace.order,,,>aptrace.order
+t_sample,s,h,)aptrace.sample,,,>aptrace.sample
+t_naverage,i,h,)aptrace.naverage,,,>aptrace.naverage
+t_niterate,i,h,)aptrace.niterate,,,>aptrace.niterate
+t_low_reject,r,h,)aptrace.low_reject,,,>aptrace.low_reject
+t_high_reject,r,h,)aptrace.high_reject,,,>aptrace.high_reject
+t_grow,r,h,)aptrace.grow,,,">aptrace.grow
+
+# EXTRACTION PARAMETERS
+"
+background,s,h,"none",,,>apflatten.background
+skybox,i,h,1,,,>apflatten.skybox
+weights,s,h,"none",,,Extraction weights (none|variance)
+pfit,s,h,)apflatten.pfit,,,>apflatten.pfit
+clean,b,h,)apflatten.clean,,,>apflatten.clean
+nclean,r,h,0.5,,,Maximum number of pixels to clean
+niterate,i,h,5,0,,Number of profile fitting iterations
+saturation,r,h,)apflatten.saturation,,,>apflatten.saturation
+readnoise,s,h,)apflatten.readnoise,,,>apflatten.readnoise
+gain,s,h,)apflatten.gain,,,>apflatten.gain
+lsigma,r,h,)apflatten.lsigma,,,>apflatten.lsigma
+usigma,r,h,)apflatten.usigma,,,>apflatten.usigma
+polysep,r,h,0.90,0.1,0.90,Marsh algorithm polynomial spacing
+polyorder,i,h,10,1,,Marsh algorithm polynomial order
+nsubaps,i,h,1,,,"Number of subapertures per aperture
+
+# ANSWER PARAMETERS
+"
+ansclobber,s,h,"no",,," "
+ansclobber1,s,h,"no",,," "
+ansdbwrite,s,h,"yes",,," "
+ansdbwrite1,s,h,"yes",,," "
+ansedit,s,h,"yes",,," "
+ansextract,s,h,"yes",,," "
+ansfind,s,h,"yes",,," "
+ansfit,s,h,"yes",,," "
+ansfitscatter,s,h,"yes",,," "
+ansfitsmooth,s,h,"yes",,," "
+ansfitspec,s,h,"yes",,," "
+ansfitspec1,s,h,"yes",,," "
+ansfittrace,s,h,"yes",,," "
+ansfittrace1,s,h,"yes",,," "
+ansflat,s,h,"yes",,," "
+ansmask,s,h,"yes",,," "
+ansnorm,s,h,"yes",,," "
+ansrecenter,s,h,"yes",,," "
+ansresize,s,h,"yes",,," "
+ansreview,s,h,"yes",,," "
+ansreview1,s,h,"yes",,," "
+ansscat,s,h,"yes",,," "
+anssmooth,s,h,"yes",,," "
+anstrace,s,h,"yes",,," "
diff --git a/noao/twodspec/apextract/apflatten.par b/noao/twodspec/apextract/apflatten.par
new file mode 100644
index 00000000..84e5906c
--- /dev/null
+++ b/noao/twodspec/apextract/apflatten.par
@@ -0,0 +1,37 @@
+# APFLATTEN
+
+input,s,a,,,,List of images to flatten
+output,s,a,,,,List of output flatten images
+apertures,s,h,"",,,Apertures
+references,s,h,"",,,"List of reference images
+"
+interactive,b,h,yes,,,Run task interactively?
+find,b,h,yes,,,Find apertures?
+recenter,b,h,yes,,,Recenter apertures?
+resize,b,h,yes,,,Resize apertures?
+edit,b,h,yes,,,Edit apertures?
+trace,b,h,yes,,,Trace apertures?
+fittrace,b,h,yes,,,Fit traced points interactively?
+flatten,b,h,yes,,,Flatten spectra?
+fitspec,b,h,yes,,,"Fit normalization spectra interactively?
+"
+line,i,h,INDEF,1,,Dispersion line
+nsum,i,h,10,,,Number of dispersion lines to sum or median
+threshold,r,h,10.,,,"Threshold for flattening spectra
+"
+pfit,s,h,"fit1d","fit1d|fit2d",,Profile fitting type (fit1d|fit2d)
+clean,b,h,no,,,Detect and replace bad pixels?
+saturation,r,h,INDEF,,,Saturation level
+readnoise,s,h,"0.",,,Read out noise sigma (photons)
+gain,s,h,"1.",,,Photon gain (photons/data number)
+lsigma,r,h,4.,0.,,Lower rejection threshold
+usigma,r,h,4.,0.,,"Upper rejection threshold
+"
+function,s,h,"legendre","chebyshev|legendre|spline1|spline3",,Fitting function for normalization spectra
+order,i,h,1,1,,Fitting function order
+sample,s,h,"*",,,Sample regions
+naverage,i,h,1,,,Average or median
+niterate,i,h,0,0,,Number of rejection iterations
+low_reject,r,h,3.,0.,,Lower rejection sigma
+high_reject,r,h,3.,0.,,High upper rejection sigma
+grow,r,h,0.,0.,,Rejection growing radius
diff --git a/noao/twodspec/apextract/apgetdata.x b/noao/twodspec/apextract/apgetdata.x
new file mode 100644
index 00000000..6645a6c3
--- /dev/null
+++ b/noao/twodspec/apextract/apgetdata.x
@@ -0,0 +1,99 @@
+include <imhdr.h>
+
+# AP_GETDATA -- Get the summed dispersion line.
+# Return the IMIO pointer, pointer to image data, the aperture axis and title.
+# The pointers must be freed by the calling program. Note that the value of
+# line may be changed.
+
+procedure ap_getdata (image, line, nsum, im, imdata, npts, apaxis, title)
+
+char image[SZ_FNAME] # Image name
+int line # Dispersion line to graph
+int nsum # Number of dispersion lines to sum
+pointer im # IMIO pointer
+pointer imdata # Pointer to image data
+int npts # Number of pixels
+int apaxis # Aperture axis
+pointer title # Title for image data
+
+int i, j, k, l, n, dispaxis
+pointer buf, medbuf
+
+real asumr(), amedr()
+pointer ap_immap(), imgs2r()
+
+errchk ap_immap, imgs2r
+
+begin
+ # Map the image
+ im = ap_immap (image, apaxis, dispaxis)
+
+ # Determine the dispersion and aperture axes.
+ if (IS_INDEFI (line))
+ line = IM_LEN(im, dispaxis) / 2
+ else
+ line = max (1, min (IM_LEN(im, dispaxis), line))
+
+ # Allocate memory for the image line and title.
+ npts = IM_LEN(im, apaxis)
+ call calloc (imdata, npts, TY_REAL)
+ call malloc (title, SZ_LINE, TY_CHAR)
+
+ # Sum the specified number of dispersion lines.
+ n = max (1, abs (nsum))
+ switch (apaxis) {
+ case 1:
+ i = max (1, line - n / 2)
+ j = min (IM_LEN(im, dispaxis), i + n - 1)
+ i = max (1, j - n + 1)
+ buf = imgs2r (im, 1, npts, i, j)
+ j = j - i + 1
+ if (j < 3 || nsum > 0) {
+ do k = 1, j
+ call aaddr (Memr[buf+(k-1)*npts], Memr[imdata],
+ Memr[imdata], npts)
+ call sprintf (Memc[title], SZ_LINE,
+ "Image=%s, Sum of lines %d-%d")
+ call pargstr (image)
+ call pargi (i)
+ call pargi (i+j-1)
+ } else {
+ call malloc (medbuf, j, TY_REAL)
+ do k = 0, npts-1 {
+ do l = 0, j-1
+ Memr[medbuf+l] = Memr[buf+l*npts+k]
+ Memr[imdata+k] = amedr (Memr[medbuf], j)
+ }
+ call mfree (medbuf, TY_REAL)
+ call sprintf (Memc[title], SZ_LINE,
+ "Image=%s, Median of lines %d-%d")
+ call pargstr (image)
+ call pargi (i)
+ call pargi (i+j-1)
+ }
+
+ case 2:
+ i = max (1, line - n / 2)
+ j = min (IM_LEN(im, dispaxis), i + n - 1)
+ i = max (1, j - n + 1)
+ buf = imgs2r (im, i, j, 1, npts)
+ j = j - i + 1
+ if (j < 3 || nsum > 0) {
+ do k = 1, npts
+ Memr[imdata+k-1] = asumr (Memr[buf+(k-1)*j], j)
+ call sprintf (Memc[title], SZ_LINE,
+ "Image=%s, Sum of columns %d-%d")
+ call pargstr (image)
+ call pargi (i)
+ call pargi (i+j-1)
+ } else {
+ do k = 1, npts
+ Memr[imdata+k-1] = amedr (Memr[buf+(k-1)*j], j)
+ call sprintf (Memc[title], SZ_LINE,
+ "Image=%s, Median of columns %d-%d")
+ call pargstr (image)
+ call pargi (i)
+ call pargi (i+j-1)
+ }
+ }
+end
diff --git a/noao/twodspec/apextract/apgetim.x b/noao/twodspec/apextract/apgetim.x
new file mode 100644
index 00000000..c5bc96f8
--- /dev/null
+++ b/noao/twodspec/apextract/apgetim.x
@@ -0,0 +1,73 @@
+# AP_GETIM -- Standardize image name so that different ways of specifying
+# the images map to the same database and output rootnames.
+
+int procedure ap_getim (list, image, maxchar)
+
+int list #I Image list
+char image[maxchar] #O Image name
+int maxchar #I Maximum number of chars in image name
+
+char ksection[SZ_FNAME] #O Image name
+
+int i, j, stat, cl_index, cl_size
+pointer im
+pointer sp, cluster, section
+
+int imtgetim(), strlen(), stridxs(), ctoi()
+pointer immap()
+
+begin
+ # Get next image name.
+ stat = imtgetim (list, image, maxchar)
+ if (stat == EOF)
+ return (stat)
+
+ call smark (sp)
+ call salloc (cluster, SZ_FNAME, TY_CHAR)
+ call salloc (section, SZ_FNAME, TY_CHAR)
+
+ call imparse (image, Memc[cluster], SZ_FNAME, ksection, SZ_FNAME,
+ Memc[section], SZ_FNAME, cl_index, cl_size)
+
+ # Strip the extension.
+ call xt_imroot (Memc[cluster], Memc[cluster], SZ_FNAME)
+
+ # Generate standard ksection. Only map image if index used.
+ # Don't worry about cases with both an index and ksection.
+
+ if (cl_index < 0 && ksection[1] == EOS)
+ ;
+ else if (cl_index == 0)
+ ksection[1] = EOS
+ else {
+ if (cl_index > 0) {
+ im = immap (image, READ_ONLY, 0)
+ ksection[1] = '['
+ call imgstr (im, "extname", ksection[2], SZ_FNAME-1)
+ i = strlen (ksection)
+ ifnoerr (call imgstr (im, "extver" ,
+ ksection[i+2], SZ_FNAME-i-1)) {
+ ksection[i+1] = ','
+ i = strlen (ksection)
+ }
+ ksection[i+1] = ']'
+ ksection[i+2] = EOS
+ call imunmap (im)
+ } else {
+ i = stridxs (",", ksection[2]) + 2
+ if (i > 2) {
+ j = ctoi (ksection, i, j)
+ ksection[i] = ']'
+ ksection[i+1] = EOS
+ }
+ }
+ }
+
+ call sprintf (image, maxchar, "%s%s%s")
+ call pargstr (Memc[cluster])
+ call pargstr (ksection)
+ call pargstr (Memc[section])
+
+ call sfree (sp)
+ return (stat)
+end
diff --git a/noao/twodspec/apextract/apgmark.x b/noao/twodspec/apextract/apgmark.x
new file mode 100644
index 00000000..72ad6a68
--- /dev/null
+++ b/noao/twodspec/apextract/apgmark.x
@@ -0,0 +1,126 @@
+include <pkg/rg.h>
+include "apertures.h"
+
+# AP_GMARK -- Mark an aperture.
+
+define SZ_TEXT 10 # Maximum size of aperture number string
+
+procedure ap_gmark (gp, imvec, aps, naps)
+
+pointer gp # GIO pointer
+int imvec # Image vector
+pointer aps[ARB] # Aperture data
+int naps # Number of apertures
+
+int i, apaxis
+real x1, x2, y1, y2, dy, xc, xl, xu
+pointer sp, text, format, ap
+
+int itoc()
+real ap_cveval()
+
+begin
+ # The aperture is marked at the top of the graph.
+ call smark (sp)
+ call salloc (text, SZ_TEXT, TY_CHAR)
+
+ call ggwind (gp, xl, xu, y1, y2)
+ x1 = min (xl, xu)
+ x2 = max (xl, xu)
+ dy = 0.025 * (y2 - y1)
+ y1 = y2 - 4 * dy
+
+ if (naps > 20) {
+ call salloc (format, SZ_LINE, TY_CHAR)
+ call sprintf (Memc[format], SZ_LINE, "h=c,v=b,s=%4.2f")
+ call pargr (20. / naps)
+ }
+
+ for (i = 1; i <= naps; i = i + 1) {
+ ap = aps[i]
+ apaxis = AP_AXIS(ap)
+
+ xc = AP_CEN(ap, apaxis) + ap_cveval (AP_CV(ap), real (imvec))
+ xl = xc + AP_LOW(ap, apaxis)
+ xu = xc + AP_HIGH(ap, apaxis)
+ call gline (gp, xc, y1 - 2 * dy, xc, y1 + 2 * dy)
+ call gline (gp, xl, y1 - dy, xl, y1 + dy)
+ call gline (gp, xu, y1 - dy, xu, y1 + dy)
+ call gline (gp, xl, y1, xu, y1)
+ if ((xc > x1) && (xc < x2)) {
+ if (itoc (AP_ID(ap), Memc[text], SZ_TEXT) > 0) {
+ if (naps > 20)
+ call gtext (gp, xc, y1 + 2.5 * dy, Memc[text],
+ Memc[format])
+ else
+ call gtext (gp, xc, y1 + 2.5 * dy, Memc[text],
+ "h=c,v=b")
+ }
+ }
+ }
+
+ call sfree (sp)
+end
+
+
+# AP_GMARKB -- Mark backgrounds.
+
+procedure ap_gmarkb (gp, imvec, aps, naps)
+
+pointer gp # GIO pointer
+int imvec # Image vector
+pointer aps[ARB] # Aperture data
+int naps # Number of apertures
+
+int i, j, nx, apaxis
+real x1, x2, y1, y2, dy, xc, xl, xu
+pointer sp, sample, x, ap, rg
+
+real ap_cveval()
+pointer rg_xrangesr()
+
+begin
+ call smark (sp)
+ call salloc (sample, SZ_LINE, TY_CHAR)
+
+ # The background is marked at the bottom of the graph.
+ call ggwind (gp, xl, xu, y1, y2)
+ x1 = min (xl, xu)
+ x2 = max (xl, xu)
+ dy = 0.005 * (y2 - y1)
+ y1 = y1 + 4 * dy
+
+ # Allocate x array.
+ nx = x2 - x1 + 2
+ call salloc (x, nx, TY_REAL)
+
+ for (i = 1; i <= naps; i = i + 1) {
+ ap = aps[i]
+ apaxis = AP_AXIS(ap)
+
+ xc = AP_CEN(ap, apaxis) + ap_cveval (AP_CV(ap), real (imvec))
+
+ if (AP_IC(ap) == NULL)
+ next
+ call ic_gstr (AP_IC(ap), "sample", Memc[sample], SZ_LINE)
+
+ do j = 0, nx-1
+ Memr[x+j] = x1 + j - xc
+ rg = rg_xrangesr (Memc[sample], Memr[x], nx)
+
+ do j = 1, RG_NRGS(rg) {
+ xl = Memr[x+RG_X1(rg,j)-1] + xc
+ xu = Memr[x+RG_X2(rg,j)-1] + xc
+ if (xl > x1 && xl < x2)
+ call gline (gp, xl, y1-dy, xl, y1+dy)
+ if (xu > x1 && xu < x2)
+ call gline (gp, xu, y1-dy, xu, y1+dy)
+ call gline (gp, xl, y1, xu, y1)
+
+ }
+
+ call rg_free (rg)
+ }
+
+ call sfree (sp)
+end
diff --git a/noao/twodspec/apextract/apgraph.x b/noao/twodspec/apextract/apgraph.x
new file mode 100644
index 00000000..47d71646
--- /dev/null
+++ b/noao/twodspec/apextract/apgraph.x
@@ -0,0 +1,145 @@
+include <pkg/gtools.h>
+include "apertures.h"
+
+
+# AP_GRAPH -- Graph the image data and call ap_gmark to mark the apertures.
+
+procedure ap_graph (gp, gt, imdata, npts, imvec, aps, naps)
+
+pointer gp # GIO pointer
+pointer gt # GTOOLS pointer
+real imdata[npts] # Image data
+int npts # Number points in image data
+int imvec # Image vector
+pointer aps[ARB] # Aperture pointers
+int naps # Number of apertures
+
+real x1, x2
+
+begin
+ call gclear (gp)
+
+ x1 = 1.
+ x2 = npts
+ call gswind (gp, x1, x2, INDEF, INDEF)
+ call gascale (gp, imdata, npts, 2)
+ call gt_swind (gp, gt)
+ call gt_labax (gp, gt)
+ call gvline (gp, imdata, npts, x1, x2)
+
+ call ap_gmark (gp, imvec, aps, naps)
+ if (naps == 1)
+ call ap_gmarkb (gp, imvec, aps, naps)
+end
+
+
+# AP_PLOT -- Make a plot of the apertures if plot output is defined.
+
+procedure ap_plot (image, line, nsum, aps, naps)
+
+char image[SZ_FNAME] # Image to be edited
+int line # Dispersion line
+int nsum # Number of dispersion lines to sum
+
+pointer aps[ARB] # Aperture pointers
+int naps # Number of apertures
+
+int npts, apaxis, fd
+pointer im, imdata, title, gp, gt, gt_init()
+errchk ap_getdata, ap_popen
+
+begin
+ call ap_popen (gp, fd, "aps")
+ if (gp == NULL)
+ return
+
+ # Map the image and get the image data.
+ call ap_getdata (image, line, nsum, im, imdata, npts, apaxis, title)
+
+ gt = gt_init()
+ call gt_sets (gt, GTTITLE, Memc[title])
+ call gt_sets (gt, GTPARAMS, "")
+ call gt_setr (gt, GTXMIN, INDEF)
+ call gt_setr (gt, GTXMAX, INDEF)
+ call gt_setr (gt, GTYMIN, INDEF)
+ call gt_setr (gt, GTYMAX, INDEF)
+
+ call ap_graph (gp, gt, Memr[imdata], npts, line, aps, naps)
+
+ call mfree (imdata, TY_REAL)
+ call mfree (title, TY_CHAR)
+ call ap_pclose (gp, fd)
+ call gt_free (gt)
+ call imunmap (im)
+end
+
+
+# AP_GRAPH1 -- Make a graph of the extracted 1D spectrum.
+
+procedure ap_graph1 (gt, bufout, npts, nspec)
+
+pointer gt # GTOOLS pointer
+real bufout[npts, nspec] # Data
+int npts # Number of data points
+int nspec # Number of spectra
+
+real wx, wy
+int i, wcs, key, gt_gcur()
+pointer sp, str, gp
+errchk ap_gopen
+
+begin
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ call ap_gopen (gp)
+ call gclear (gp)
+ call gswind (gp, 1., real (npts), INDEF, INDEF)
+ call gascale (gp, bufout, npts * nspec, 2)
+ call gt_swind (gp, gt)
+ call gt_labax (gp, gt)
+ do i = 1, nspec
+ call gvline (gp, bufout[1,i], npts, 1., real (npts))
+ call gflush (gp)
+
+ while (gt_gcur ("gcur", wx, wy, wcs, key, Memc[str],
+ SZ_LINE) != EOF) {
+ switch (key) {
+ case 'I':
+ call fatal (0, "Interrupt")
+ }
+ }
+
+ call sfree (sp)
+end
+
+
+# AP_PLOT1 -- Make a plot of the extracted 1D spectrum.
+
+procedure ap_plot1 (gt, bufout, npts, nspec)
+
+pointer gt # GTOOLS pointer
+real bufout[npts,nspec] # Data
+int npts # Number of data points
+int nspec # Number of spectra
+
+int i, fd
+pointer gp
+errchk ap_popen
+
+begin
+ call ap_popen (gp, fd, "spec")
+ if (gp == NULL)
+ return
+
+ call gclear (gp)
+ call gswind (gp, 1., real (npts), INDEF, INDEF)
+ call gascale (gp, bufout, npts * nspec, 2)
+ call gt_swind (gp, gt)
+ call gt_labax (gp, gt)
+ do i = 1, nspec
+ call gvline (gp, bufout[1,i], npts, 1., real (npts))
+ call gflush (gp)
+
+ call ap_pclose (gp, fd)
+end
diff --git a/noao/twodspec/apextract/apgscur.x b/noao/twodspec/apextract/apgscur.x
new file mode 100644
index 00000000..5306ff9a
--- /dev/null
+++ b/noao/twodspec/apextract/apgscur.x
@@ -0,0 +1,28 @@
+include "apertures.h"
+
+# AP_GSCUR -- Set the graphics cursor to the aperture given by the index.
+# It computes the position of the cursor for the specified dispersion line.
+
+procedure ap_gscur (index, gp, line, aps, y)
+
+int index # Index of aperture
+pointer gp # GIO pointer
+int line # Dispersion line
+pointer aps[ARB] # Apertures
+real y # Y cursor coordinate
+
+int apaxis
+real x
+pointer ap
+
+real ap_cveval()
+
+begin
+ if (index < 1 || IS_INDEF (y))
+ return
+
+ ap = aps[index]
+ apaxis = AP_AXIS(ap)
+ x = AP_CEN(ap, apaxis) + ap_cveval (AP_CV(ap), real (line))
+ call gscur (gp, x, y)
+end
diff --git a/noao/twodspec/apextract/apicset.x b/noao/twodspec/apextract/apicset.x
new file mode 100644
index 00000000..b837a991
--- /dev/null
+++ b/noao/twodspec/apextract/apicset.x
@@ -0,0 +1,84 @@
+include <imhdr.h>
+include "apertures.h"
+
+# AP_ICSET -- Set the background fitting ICFIT structure for an aperture.
+# If the input template aperture is NULL then the output background fitting
+# ICFIT pointer is initialized otherwise a copy from the input template
+# aperture is made.
+
+procedure ap_icset (apin, apout, imlen)
+
+pointer apin # Input template aperture pointer
+pointer apout # Output aperture pointer
+int imlen # Image length along aperture axis
+
+int i
+real x, x1, x2
+pointer ic, sp, str
+
+int apgeti(), ctor()
+real apgetr()
+
+begin
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ if (AP_IC(apout) == NULL)
+ call ic_open (AP_IC(apout))
+ ic = AP_IC(apout)
+
+ if (apin == NULL) {
+ call apgstr ("b_function", Memc[str], SZ_LINE)
+ call ic_pstr (ic, "function", Memc[str])
+ call ic_puti (ic, "order", apgeti ("b_order"))
+ call apgstr ("b_sample", Memc[str], SZ_LINE)
+ for (i=str; Memc[i]==' '; i=i+1)
+ ;
+ if (Memc[i] == EOS)
+ call strcpy ("*", Memc[str], SZ_LINE)
+ call ic_pstr (ic, "sample", Memc[str])
+ call ic_puti (ic, "naverage", apgeti ("b_naverage"))
+ call ic_puti (ic, "niterate", apgeti ("b_niterate"))
+ call ic_putr (ic, "low", apgetr ("b_low_reject"))
+ call ic_putr (ic, "high", apgetr ("b_high_reject"))
+ call ic_putr (ic, "grow", apgetr ("b_grow"))
+ if (AP_AXIS(apout) == 1)
+ call ic_pstr (ic, "xlabel", "Column")
+ else
+ call ic_pstr (ic, "xlabel", "Line")
+ } else {
+ if (AP_IC(apin) == NULL) {
+ call ic_closer (AP_IC(apout))
+ AP_IC(apout) = NULL
+ ic = NULL
+ } else if (AP_IC(apin) != ic)
+ call ic_copy (AP_IC(apin), ic)
+ }
+
+ # Set the background limits
+ if (ic != NULL) {
+ i = AP_AXIS(apout)
+ x1 = AP_LOW(apout, i)
+ x2 = AP_HIGH(apout, i)
+
+ call ic_gstr (ic, "sample", Memc[str], SZ_LINE)
+ for (i=str; Memc[i]!=EOS; i=i+1)
+ if (Memc[i] == ':')
+ Memc[i] = ','
+ for (i=1; Memc[str+i-1]!=EOS; i=i+1) {
+ if (Memc[str+i-1] == '*') {
+ x1 = min (x1, real(-imlen))
+ x2 = max (x2, real(imlen))
+ } else if (ctor (Memc[str], i, x) > 0) {
+ x1 = min (x1, x)
+ x2 = max (x2, x)
+ i = i - 1
+ }
+ }
+
+ call ic_putr (ic, "xmin", x1)
+ call ic_putr (ic, "xmax", x2)
+ }
+
+ call sfree (sp)
+end
diff --git a/noao/twodspec/apextract/apids.x b/noao/twodspec/apextract/apids.x
new file mode 100644
index 00000000..572890a5
--- /dev/null
+++ b/noao/twodspec/apextract/apids.x
@@ -0,0 +1,401 @@
+include <error.h>
+include <mach.h>
+include "apertures.h"
+
+# Data structure for user aperture id table.
+define IDS_LEN 4 # Length of ID structure
+define IDS_NIDS Memi[$1] # Number of aperture IDs
+define IDS_APS Memi[$1+1] # Aperture numbers (pointer)
+define IDS_BEAMS Memi[$1+2] # Beam numbers (pointer)
+define IDS_TITLES Memi[$1+3] # Titles (pointer)
+
+# AP_GIDS -- Get user aperture ID's.
+
+procedure ap_gids (ids)
+
+pointer ids # ID structure
+
+int nids, ap, beam, fd, nalloc
+double ra, dec
+pointer sp, key, str, aps, beams, titles, im, list
+
+int nowhite(), open(), fscan(), nscan()
+pointer immap(), imofnlu(), imgnfn()
+errchk open
+
+begin
+ call smark (sp)
+ call salloc (key, SZ_FNAME, TY_CHAR)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ nids = 0
+ nalloc = 0
+
+ call apgstr ("apidtable", Memc[key], SZ_FNAME)
+ if (nowhite (Memc[key], Memc[key], SZ_FNAME) > 0) {
+ iferr {
+ # Read aperture information from an image.
+ ifnoerr (im = immap (Memc[key], READ_ONLY, 0)) {
+ list = imofnlu (im, "SLFIB[0-9]*")
+ while (imgnfn (list, Memc[key], SZ_FNAME) != EOF) {
+ call imgstr (im, Memc[key], Memc[str], SZ_LINE)
+ call sscan (Memc[str])
+ call gargi (ap)
+ if (nscan() == 0)
+ next
+ if (ap < 1) {
+ call imcfnl (list)
+ call imunmap (im)
+ call error (1,
+ "Aperture numbers in apidtable must be > 0")
+ }
+ if (nalloc == 0) {
+ nalloc = 50
+ call malloc (aps, nalloc, TY_INT)
+ call malloc (beams, nalloc, TY_INT)
+ call malloc (titles, nalloc, TY_POINTER)
+ } else if (nids == nalloc) {
+ nalloc = nalloc + 50
+ call realloc (aps, nalloc, TY_INT)
+ call realloc (beams, nalloc, TY_INT)
+ call realloc (titles, nalloc, TY_POINTER)
+ }
+ Memi[aps+nids] = ap
+ call gargi (Memi[beams+nids])
+ call gargd (ra)
+ call gargd (dec)
+ if (nscan() != 4) {
+ call reset_scan ()
+ call gargi (ap)
+ call gargi (beam)
+ Memc[str] = EOS
+ call gargstr (Memc[str], SZ_LINE)
+ call xt_stripwhite (Memc[str])
+ if (Memc[str] == EOS)
+ Memi[titles+nids] = NULL
+ else {
+ call malloc (Memi[titles+nids], SZ_APTITLE,
+ TY_CHAR)
+ call strcpy (Memc[str], Memc[Memi[titles+nids]],
+ SZ_APTITLE)
+ }
+ } else {
+ Memc[str] = EOS
+ call gargstr (Memc[str], SZ_LINE)
+ call xt_stripwhite (Memc[str])
+ call malloc (Memi[titles+nids], SZ_APTITLE, TY_CHAR)
+ if (Memc[str] == EOS) {
+ call sprintf (Memc[Memi[titles+nids]],
+ SZ_APTITLE, "(%.2h %.2h)")
+ call pargd (ra)
+ call pargd (dec)
+ } else {
+ call sprintf (Memc[Memi[titles+nids]],
+ SZ_APTITLE, "%s (%.2h %.2h)")
+ call pargstr (Memc[str])
+ call pargd (ra)
+ call pargd (dec)
+ }
+ }
+ nids = nids + 1
+ }
+ call imcfnl (list)
+ call imunmap (im)
+
+ # Read aperture information from a file.
+ } else {
+ fd = open (Memc[key], READ_ONLY, TEXT_FILE)
+ while (fscan (fd) != EOF) {
+ call gargi (ap)
+ if (nscan() == 0)
+ next
+ if (ap < 1) {
+ call close (fd)
+ call error (1,
+ "Aperture numbers in apidtable must be > 0")
+ }
+ if (nalloc == 0) {
+ nalloc = 50
+ call malloc (aps, nalloc, TY_INT)
+ call malloc (beams, nalloc, TY_INT)
+ call malloc (titles, nalloc, TY_POINTER)
+ } else if (nids == nalloc) {
+ nalloc = nalloc + 50
+ call realloc (aps, nalloc, TY_INT)
+ call realloc (beams, nalloc, TY_INT)
+ call realloc (titles, nalloc, TY_POINTER)
+ }
+ Memi[aps+nids] = ap
+ Memi[beams+nids] = ap
+ Memc[str] = EOS
+ call gargi (beam)
+ if (nscan() == 2)
+ Memi[beams+nids] = beam
+ call gargstr (Memc[str], SZ_LINE)
+ call xt_stripwhite (Memc[str])
+ if (Memc[str] == EOS)
+ Memi[titles+nids] = NULL
+ else {
+ call malloc (Memi[titles+nids], SZ_APTITLE, TY_CHAR)
+ call strcpy (Memc[str], Memc[Memi[titles+nids]],
+ SZ_APTITLE)
+ }
+ nids = nids + 1
+ }
+ call close (fd)
+ }
+ } then
+ call erract (EA_WARN)
+ }
+
+ if (nalloc > nids) {
+ call realloc (aps, nids, TY_INT)
+ call realloc (beams, nids, TY_INT)
+ call realloc (titles, nids, TY_INT)
+ }
+
+ if (nids > 0) {
+ call malloc (ids, IDS_LEN, TY_STRUCT)
+ IDS_NIDS(ids) = nids
+ IDS_APS(ids) = aps
+ IDS_BEAMS(ids) = beams
+ IDS_TITLES(ids) = titles
+ }
+
+ call sfree (sp)
+end
+
+
+procedure ap_fids (ids)
+
+pointer ids # ID structure
+int i
+
+begin
+ if (ids != NULL) {
+ do i = 1, IDS_NIDS(ids)
+ call mfree (Memi[IDS_TITLES(ids)+i-1], TY_CHAR)
+ call mfree (IDS_APS(ids), TY_INT)
+ call mfree (IDS_BEAMS(ids), TY_INT)
+ call mfree (IDS_TITLES(ids), TY_POINTER)
+ call mfree (ids, TY_STRUCT)
+ }
+end
+
+
+
+# AP_IDS -- Set aperture IDs
+# Do not allow negative or zero aperture numbers.
+
+procedure ap_ids (aps, naps, ids)
+
+pointer aps[ARB] # Aperture pointers
+int naps # Number of apertures
+int ids # ID structure
+
+int i, j, k, l, m, axis, nids, ap, beam, skip, nused
+real maxsep, apgetr()
+pointer sp, used, a, b
+
+begin
+ if (naps < 1)
+ return
+
+ axis = AP_AXIS(aps[1])
+ maxsep = apgetr ("maxsep")
+
+ # Dereference ID structure pointers.
+ if (ids != NULL) {
+ nids = IDS_NIDS(ids)
+ a = IDS_APS(ids)
+ b = IDS_BEAMS(ids)
+ } else
+ nids = 0
+
+ # Make a list of used aperture numbers
+ call smark (sp)
+ call salloc (used, naps, TY_INT)
+ nused = 0
+ do i = 1, naps
+ if (!IS_INDEFI(AP_ID(aps[i]))) {
+ Memi[used+nused] = AP_ID(aps[i])
+ nused = nused + 1
+ }
+
+ # Find first aperture with a defined aperture number.
+ for (i=1; i<=naps && IS_INDEFI(AP_ID(aps[i])); i=i+1)
+ ;
+
+ # If there are no defined aperture numbers start with 1 or first
+ # aperture in the ID table.
+
+ if (i > naps) {
+ i = 1
+ if (nids > 0) {
+ ap = Memi[a]
+ beam = Memi[b]
+ } else {
+ ap = i
+ beam = ap
+ }
+ AP_ID(aps[i]) = ap
+ AP_BEAM(aps[i]) = beam
+ Memi[used+nused] = ap
+ nused = nused + 1
+ } else {
+ ap = AP_ID(aps[i])
+ for (l = 1; l <= nids && ap != Memi[a+l-1]; l = l + 1)
+ ;
+ if (l <= nids)
+ AP_BEAM(aps[i]) = Memi[b+l-1]
+ else
+ AP_BEAM(aps[i]) = ap
+ }
+
+ # Work backwards through the undefined apertures.
+ for (j = i - 1; j > 0; j = j - 1) {
+ skip = abs (AP_CEN(aps[j],axis)-AP_CEN(aps[j+1],axis)) / maxsep
+ if (ids != NULL) {
+ ap = AP_ID(aps[j+1])
+ for (l = 1; l <= nids && ap != Memi[a+l-1]; l = l + 1)
+ ;
+ if (nids <= naps)
+ skip = 0
+ m = l - skip
+ if (l > nids) {
+ l = 1
+ for (k = 2; k <= nids; k = k + 1)
+ if (abs (ap - Memi[a+k-1]) < abs (ap - Memi[a+l-1]))
+ l = k
+ m = l - skip + 1
+ }
+ repeat {
+ m = m - 1
+ if (m > 0) {
+ ap = Memi[a+m-1]
+ beam = Memi[b+m-1]
+ } else {
+ ap = Memi[a+l-1] + m
+ beam = max (0, Memi[b+l-1] + m)
+ }
+ if (ap == 0)
+ next
+ for (k = 0; k < nused && abs(ap) != Memi[used+k]; k = k + 1)
+ ;
+ if (k == nused)
+ break
+ }
+ } else {
+ ap = AP_ID(aps[j+1]) - skip
+ repeat {
+ ap = ap - 1
+ beam = abs (ap)
+ if (ap == 0)
+ next
+ for (k = 0; k < nused && abs(ap) != Memi[used+k]; k = k + 1)
+ ;
+ if (k == nused)
+ break
+ }
+ }
+ ap = abs (ap)
+ AP_ID(aps[j]) = ap
+ AP_BEAM(aps[j]) = beam
+ Memi[used+nused] = ap
+ nused = nused + 1
+ }
+
+ # Work forwards through the undefined apertures.
+ for (i = i + 1; i <= naps; i = i + 1) {
+ if (IS_INDEFI(AP_ID(aps[i]))) {
+ skip = abs (AP_CEN(aps[i],axis)-AP_CEN(aps[i-1],axis)) / maxsep
+ if (nids > 0) {
+ ap = AP_ID(aps[i-1])
+ for (l = 1; l <= nids && ap != Memi[a+l-1]; l = l + 1)
+ ;
+ if (nids <= naps)
+ skip = 0
+ m = l + skip
+ if (l > nids) {
+ l = 1
+ for (k = 2; k <= nids; k = k + 1)
+ if (abs (ap-Memi[a+k-1]) < abs (ap-Memi[a+l-1]))
+ l = k
+ m = l + skip - 1
+ }
+ m = nids - m + 1
+ repeat {
+ m = m - 1
+ if (m > 0) {
+ ap = Memi[a+nids-m]
+ beam = Memi[b+nids-m]
+ } else {
+ ap = Memi[a+l-1] - m
+ beam = max (0, Memi[b+l-1] - m)
+ }
+ if (ap == 0)
+ next
+ for (k=0; k<nused && abs(ap)!=Memi[used+k]; k=k+1)
+ ;
+ if (k == nused)
+ break
+ }
+ } else {
+ ap = AP_ID(aps[i-1]) + skip
+ repeat {
+ ap = ap + 1
+ beam = abs (ap)
+ if (ap == 0)
+ next
+ for (k=0; k<nused && abs(ap)!=Memi[used+k]; k=k+1)
+ ;
+ if (k == nused)
+ break
+ }
+ }
+ ap = abs(ap)
+ AP_ID(aps[i]) = ap
+ AP_BEAM(aps[i]) = beam
+ Memi[used+nused] = ap
+ nused = nused + 1
+ }
+ }
+
+ call sfree (sp)
+end
+
+
+procedure ap_titles (aps, naps, ids)
+
+pointer aps[ARB] # Aperture pointers
+int naps # Number of apertures
+pointer ids # ID structure
+
+int i, j, nids
+pointer a, titles, title
+
+begin
+ if (ids == NULL)
+ return
+
+ nids = IDS_NIDS(ids)
+ a = IDS_APS(ids)
+ titles = IDS_TITLES(ids)
+
+ do i = 1, naps {
+ if (AP_TITLE(aps[i]) != NULL)
+ next
+ do j = 1, nids {
+ if (AP_ID(aps[i]) == Memi[a+j-1]) {
+ title = Memi[titles+j-1]
+ if (title != NULL) {
+ if (AP_TITLE(aps[i]) == NULL)
+ call malloc (AP_TITLE(aps[i]), SZ_APTITLE, TY_CHAR)
+ call strcpy (Memc[title], Memc[AP_TITLE(aps[i])],
+ SZ_APTITLE)
+ } else if (AP_TITLE(aps[i]) != NULL)
+ call mfree (AP_TITLE(aps[i]), TY_CHAR)
+ }
+ }
+ }
+end
diff --git a/noao/twodspec/apextract/apimmap.x b/noao/twodspec/apextract/apimmap.x
new file mode 100644
index 00000000..f001dc39
--- /dev/null
+++ b/noao/twodspec/apextract/apimmap.x
@@ -0,0 +1,48 @@
+include <imhdr.h>
+
+# AP_IMMAP -- Map an input image for the APEXTRACT package.
+
+pointer procedure ap_immap (image, apaxis, dispaxis)
+
+char image[ARB] # Image to map
+int apaxis # Aperture axis
+int dispaxis # Dispersion axis
+
+pointer im, immap()
+int i, j, imgeti(), clgeti()
+errchk immap
+
+data i/0/, j/0/
+
+begin
+ im = immap (image, READ_ONLY, 0)
+ if (IM_NDIM(im) == 1) {
+ call imunmap (im)
+ call error (0, "Image must be two dimensional")
+ } else if (IM_NDIM(im) > 2) {
+ if (i == 0)
+ call eprintf (
+ "Warning: Image(s) are not two dimensional (ignoring higher dimensions)\n")
+ i = i + 1
+ } else
+ i = 0
+
+ iferr (dispaxis = imgeti (im, "dispaxis"))
+ dispaxis = clgeti ("dispaxis")
+ if (dispaxis < 1 || dispaxis > 2) {
+ apaxis = dispaxis
+ dispaxis = max (1, min (2, clgeti ("dispaxis")))
+ if (j == 0) {
+ call eprintf (
+ "WARNING: Dispersion axis %d invalid; using axis %d\n")
+ call pargi (apaxis)
+ call pargi (dispaxis)
+ }
+ j = j + 1
+ } else
+ j = 0
+
+ apaxis = mod (dispaxis, 2) + 1
+
+ return (im)
+end
diff --git a/noao/twodspec/apextract/apinfo.x b/noao/twodspec/apextract/apinfo.x
new file mode 100644
index 00000000..372860ae
--- /dev/null
+++ b/noao/twodspec/apextract/apinfo.x
@@ -0,0 +1,96 @@
+include "apertures.h"
+
+# AP_INFO -- Print information about an aperture.
+
+procedure ap_info (ap)
+
+pointer ap # Aperture pointer
+
+int n, ic_geti(), strlen()
+real ic_getr()
+pointer sp, str1, str2
+
+begin
+ call smark (sp)
+
+ if (AP_IC(ap) != NULL) {
+ call salloc (str1, SZ_LINE, TY_CHAR)
+ call salloc (str2, SZ_LINE, TY_CHAR)
+
+ n = 0
+ call ic_gstr (AP_IC(ap), "function", Memc[str1], SZ_LINE)
+ call sprintf (Memc[str2], SZ_LINE, "background: func=%s ord=%d")
+ call pargstr (Memc[str1])
+ call pargi (ic_geti (AP_IC(ap), "order"))
+ n = strlen (Memc[str2])
+ call printf ("%s")
+ call pargstr (Memc[str2])
+
+ call ic_gstr (AP_IC(ap), "sample", Memc[str1], SZ_LINE)
+ if (Memc[str1] != '*') {
+ call sprintf (Memc[str2], SZ_LINE, " sample=\"%s\"")
+ call pargstr (Memc[str1])
+ n = n + strlen (Memc[str2])
+ if (n > 80) {
+ call printf ("\n\t")
+ n = 8 + strlen (Memc[str2])
+ }
+ call printf ("%s")
+ call pargstr (Memc[str2])
+ }
+ if (ic_geti (AP_IC(ap), "naverage") != 1) {
+ call sprintf (Memc[str2], SZ_LINE, " nav=%d")
+ call pargi (ic_geti (AP_IC(ap), "naverage"))
+ n = n + strlen (Memc[str2])
+ if (n > 80) {
+ call printf ("\n\t")
+ n = 8 + strlen (Memc[str2])
+ }
+ call printf ("%s")
+ call pargstr (Memc[str2])
+ }
+ if (ic_geti (AP_IC(ap), "niterate") > 0) {
+ call sprintf (Memc[str2], SZ_LINE, " nit=%d")
+ call pargi (ic_geti (AP_IC(ap), "niterate"))
+ n = n + strlen (Memc[str2])
+ if (n > 80) {
+ call printf ("\n\t")
+ n = 8 + strlen (Memc[str2])
+ }
+ call printf ("%s")
+ call pargstr (Memc[str2])
+ call sprintf (Memc[str2], SZ_LINE, " low=%3.1f")
+ call pargr (ic_getr (AP_IC(ap), "low"))
+ n = n + strlen (Memc[str2])
+ if (n > 80) {
+ call printf ("\n\t")
+ n = 8 + strlen (Memc[str2])
+ }
+ call printf ("%s")
+ call pargstr (Memc[str2])
+ call sprintf (Memc[str2], SZ_LINE, " high=%3.1f")
+ call pargr (ic_getr (AP_IC(ap), "high"))
+ n = n + strlen (Memc[str2])
+ if (n > 80) {
+ call printf ("\n\t")
+ n = 8 + strlen (Memc[str2])
+ }
+ call printf ("%s")
+ call pargstr (Memc[str2])
+ if (ic_getr (AP_IC(ap), "grow") > 0) {
+ call sprintf (Memc[str2], SZ_LINE, " grow=%d")
+ call pargr (ic_getr (AP_IC(ap), "grow"))
+ n = n + strlen (Memc[str2])
+ if (n > 80) {
+ call printf ("\n\t")
+ n = 8 + strlen (Memc[str2])
+ }
+ call printf ("%s")
+ call pargstr (Memc[str2])
+ }
+ }
+ call printf ("\n")
+ }
+
+ call sfree (sp)
+end
diff --git a/noao/twodspec/apextract/apio.x b/noao/twodspec/apextract/apio.x
new file mode 100644
index 00000000..bfd2c6e6
--- /dev/null
+++ b/noao/twodspec/apextract/apio.x
@@ -0,0 +1,144 @@
+include <time.h>
+
+# AP_LOG -- Verbose, log, and error output.
+
+procedure ap_log (str, log, verbose, err)
+
+char str[ARB] # String
+int log # Write to log if logfile defined?
+int verbose # Write to stdout if verbose?
+int err # Write to stdout?
+
+int fd, open()
+long clktime()
+bool clgetb()
+pointer sp, logfile, date
+errchk open
+
+begin
+ call smark (sp)
+ call salloc (logfile, SZ_LINE, TY_CHAR)
+ call salloc (date, SZ_DATE, TY_CHAR)
+ call cnvdate (clktime(0), Memc[date], SZ_DATE)
+
+ if (err == YES || (verbose == YES && clgetb ("verbose"))) {
+ call printf ("%s: %s\n")
+ call pargstr (Memc[date])
+ call pargstr (str)
+ call flush (STDOUT)
+ }
+
+ if (log == YES) {
+ call clgstr ("logfile", Memc[logfile], SZ_FNAME)
+ if (Memc[logfile] != EOS) {
+ fd = open (Memc[logfile], APPEND, TEXT_FILE)
+ call fprintf (fd, "%s: %s\n")
+ call pargstr (Memc[date])
+ call pargstr (str)
+ call flush (fd)
+ call close (fd)
+ }
+ }
+
+ call sfree (sp)
+end
+
+
+# AP_GOPEN/AP_GCLOSE -- Open and close the graphics device.
+# The device "stdgraph" is used.
+
+procedure ap_gopen (gp)
+
+pointer gp # GIO pointer
+pointer gplast # Last GIO pointer
+
+int flag
+pointer gopen()
+errchk gopen
+
+data flag/NO/
+common /apgio/ gplast
+
+begin
+ if (flag == NO) {
+ flag = YES
+ call ap_gclose ()
+ }
+
+ if (gplast == NULL)
+ gplast = gopen ("stdgraph", NEW_FILE, STDGRAPH)
+
+ gp = gplast
+end
+
+procedure ap_gclose ()
+
+int flag
+pointer gplast
+
+data flag/NO/
+common /apgio/ gplast
+
+begin
+ if (flag == NO) {
+ flag = YES
+ gplast = NULL
+ }
+
+ if (gplast != NULL) {
+ call gclose (gplast)
+ gplast = NULL
+ }
+end
+
+
+# AP_POPEN -- Open the plot device or metacode file. This includes CLIO
+# to get the plot device.
+
+procedure ap_popen (gp, fd, type)
+
+pointer gp # GIO pointer
+int fd # FIO channel for metacode file
+char type[ARB] # Plot type
+
+bool streq(), strne()
+int open(), nowhite(), strncmp()
+pointer sp, str, gopen()
+errchk gopen, open
+
+begin
+ call smark (sp)
+ call salloc (str, SZ_FNAME, TY_CHAR)
+ call clgstr ("plotfile", Memc[str], SZ_LINE)
+
+ gp = NULL
+ fd = NULL
+ if (nowhite (Memc[str], Memc[str], SZ_FNAME) > 0) {
+ if (strncmp ("debug", Memc[str], 5) == 0) {
+ if (streq (type, Memc[str+5]) || streq ("all", Memc[str+5])) {
+ fd = open (Memc[str], APPEND, BINARY_FILE)
+ gp = gopen ("stdvdm", APPEND, fd)
+ }
+ } else if (strne ("fits", type)) {
+ fd = open (Memc[str], APPEND, BINARY_FILE)
+ gp = gopen ("stdvdm", APPEND, fd)
+ }
+ }
+
+ call sfree (sp)
+end
+
+
+# AP_PCLOSE -- Close plot file.
+
+procedure ap_pclose (gp, fd)
+
+pointer gp # GIO pointer
+int fd # FIO channel for metacode file
+
+begin
+ if (gp != NULL)
+ call gclose (gp)
+ if (fd != NULL)
+ call close (fd)
+end
diff --git a/noao/twodspec/apextract/apmask.par b/noao/twodspec/apextract/apmask.par
new file mode 100644
index 00000000..7f8e114b
--- /dev/null
+++ b/noao/twodspec/apextract/apmask.par
@@ -0,0 +1,19 @@
+# APMASK
+
+input,s,a,,,,List of input images
+output,s,a,,,,List of output masks
+apertures,s,h,"",,,Apertures
+references,s,h,"",,,List of reference images
+
+interactive,b,h,yes,,,Run task interactively?
+find,b,h,yes,,,Find apertures?
+recenter,b,h,no,,,Recenter apertures?
+resize,b,h,no,,,Resize apertures?
+edit,b,h,yes,,,Edit apertures?
+trace,b,h,yes,,,Trace apertures?
+fittrace,b,h,yes,,,Fit the traced points interactively?
+mask,b,h,yes,,,"Create mask images?
+"
+line,i,h,INDEF,1,,Starting dispersion line
+nsum,i,h,10,,,Number of dispersion lines to sum or median
+buffer,r,h,0.,,,Buffer distance from apertures
diff --git a/noao/twodspec/apextract/apmask.x b/noao/twodspec/apextract/apmask.x
new file mode 100644
index 00000000..4dc4da19
--- /dev/null
+++ b/noao/twodspec/apextract/apmask.x
@@ -0,0 +1,155 @@
+include <imhdr.h>
+include <pmset.h>
+include "apertures.h"
+
+# AP_MASK -- Create an aperture mask.
+# The mask is boolean with pixels within the apertures having value 1 and
+# pixels outside the mask having values 0. An additional buffer distance
+# may be specified.
+
+procedure ap_mask (image, output, aps, naps)
+
+char image[SZ_FNAME] # Image name
+char output[SZ_FNAME] # Output mask name
+pointer aps[ARB] # Apertures
+int naps # Number of apertures
+
+real buffer # Buffer distance
+
+int i, j, aaxis, baxis, nc, nl, na, nb, apmin, apmax, low, high
+real aplow, aphigh, shift
+long v[2]
+short val
+pointer im, pm, ap, cv, a1, b1
+pointer sp, name, str, buf, a, b, amin, bmax
+
+real clgetr(), ap_cveval()
+bool ap_answer()
+pointer ap_immap(), pm_newmask()
+errchk ap_immap, pm_savef
+
+begin
+ # Query user.
+ call smark (sp)
+ call salloc (name, SZ_LINE, TY_CHAR)
+ call salloc (str, SZ_LINE, TY_CHAR)
+ call sprintf (Memc[str], SZ_LINE, "Create aperture mask for %s?")
+ call pargstr (image)
+ if (!ap_answer ("ansmask", Memc[str])) {
+ call sfree (sp)
+ return
+ }
+
+ # Get buffer distance.
+ buffer = clgetr ("buffer")
+
+ # Make the image and initialize the mask.
+ im = ap_immap (image, aaxis, baxis)
+ pm = pm_newmask (im, 1)
+ nc = IM_LEN(im,1)
+ nl = IM_LEN(im,2)
+ na = IM_LEN(im,aaxis)
+ nb = IM_LEN(im,baxis)
+
+ # Allocate memory.
+ call salloc (buf, nc, TY_SHORT)
+ call salloc (a, naps*nb, TY_SHORT)
+ call salloc (b, naps*nb, TY_SHORT)
+ call salloc (amin, naps, TY_SHORT)
+ call salloc (bmax, naps, TY_SHORT)
+ val = 1
+
+ # Go through and compute all the limits as well as the maximum
+ # range of each aperture. This information must be computed for
+ # an aperture axis of 2 and it is also done for aperture axis
+ # of 1 just to keep the code the same.
+
+ do i = 1, naps {
+ ap = aps[i]
+ cv = AP_CV(ap)
+ aplow = AP_CEN(ap,aaxis) + AP_LOW(ap,aaxis) - buffer
+ aphigh = AP_CEN(ap,aaxis) + AP_HIGH(ap,aaxis) + buffer
+ apmin = aplow
+ apmax = aphigh
+ a1 = a + (i - 1) * nb
+ b1 = b + (i - 1) * nb
+ do j = 1, nb {
+ shift = ap_cveval (cv, real (j))
+ low = nint (aplow + shift)
+ high = nint (aphigh + shift)
+ Mems[a1+j-1] = low
+ Mems[b1+j-1] = high
+ apmin = min (low, apmin)
+ apmax = max (high, apmax)
+ }
+ Mems[amin+i-1] = apmin
+ Mems[bmax+i-1] = apmax
+ }
+
+ # For each line create a pixel array mask. For aperture axis 1 this
+ # is simple while for aperture axis 2 we have to look through each
+ # line to see if any apertures intersect the line.
+
+ switch (aaxis) {
+ case 1:
+ do j = 1, nl {
+ v[2] = j
+ call aclrs (Mems[buf], nc)
+ a1 = a + j - 1
+ b1 = b + j - 1
+ do i = 1, naps {
+ low = Mems[a1]
+ high = Mems[b1]
+ low = max (1, low)
+ high = min (na, high)
+ if (low <= high)
+ call amovks (val, Mems[buf+low-1], high-low+1)
+ a1 = a1 + nb
+ b1 = b1 + nb
+ }
+ call pmplps (pm, v, Mems[buf], 1, nc, PIX_SRC)
+ }
+ case 2:
+ do j = 1, nl {
+ v[2] = j
+ call aclrs (Mems[buf], nc)
+ do i = 1, naps {
+ if (j < Mems[amin+i-1] || j > Mems[bmax+i-1])
+ next
+
+ a1 = a + (i - 1) * nb
+ b1 = b + (i - 1) * nb
+ for (low=0; low<nb; low=low+1) {
+ if (j < Mems[a1+low] || j > Mems[b1+low])
+ next
+ for (high=low+1; high<nb; high=high+1)
+ if (j < Mems[a1+high] || j > Mems[b1+high])
+ break
+ call amovks (val, Mems[buf+low], high-low)
+ low = high - 1
+ }
+ }
+ call pmplps (pm, v, Mems[buf], 1, nc, PIX_SRC)
+ }
+ }
+
+ # Log the output and finish up.
+ if (output[1] == EOS) {
+ call sprintf (Memc[name], SZ_LINE, "%s.pl")
+ call pargstr (image)
+ } else
+ call strcpy (output, Memc[name], SZ_LINE)
+ call sprintf (Memc[str], SZ_LINE, "Aperture mask for %s")
+ call pargstr (image)
+
+ call pm_savef (pm, Memc[name], Memc[str], 0)
+ call pm_close (pm)
+ call imunmap (im)
+
+ call sprintf (Memc[str], SZ_LINE, "MASK - Aperture mask for %s --> %s")
+ call pargstr (image)
+ call pargstr (Memc[name])
+ call ap_log (Memc[str], YES, YES, NO)
+
+ call sfree (sp)
+end
diff --git a/noao/twodspec/apextract/apmw.x b/noao/twodspec/apextract/apmw.x
new file mode 100644
index 00000000..9fcd35d7
--- /dev/null
+++ b/noao/twodspec/apextract/apmw.x
@@ -0,0 +1,280 @@
+include <error.h>
+include <imhdr.h>
+include <imio.h>
+include <mwset.h>
+
+
+# APMW_OPEN -- Open APMW structure.
+# APMW_CLOSE -- Close APMW structure.
+# APMW_SETAP -- Set aperture values in APMW structure.
+# APMW_SAVEIM -- Set WCS in image header.
+# APMW_WCSFIX -- Fix up WCS
+
+# Output formats
+define ONEDSPEC 1 # Individual 1D spectra
+define MULTISPEC 2 # Multiple spectra
+define ECHELLE 3 # Echelle spectra
+define STRIP 4 # Strip spectra
+define NORM 5 # Normalized spectra
+define FLAT 6 # Flat spectra
+define RATIO 7 # Ratio of data to model
+define DIFF 8 # Difference of data and model
+define FIT 9 # Model
+define NOISE 10 # Noise calculation
+
+
+# Data structure for the apertures. This version assumes the coordinates
+# are the same for all the apertures.
+
+define APMW_LEN (8 + $1 * 6) # Structure length
+
+define APMW_LABEL Memi[$1] # WCS label
+define APMW_UNITS Memi[$1+1] # WCS units
+define APMW_DTYPE Memi[$1+2] # Dispersion type
+define APMW_NW Memi[$1+3] # Number of pixels
+define APMW_W1 Memd[P2D($1+4)] # Starting coordinate
+define APMW_DW Memd[P2D($1+6)] # Coordinate per pixel
+define APMW_AP Memi[$1+6*($2-1)+8] # Aperture
+define APMW_BEAM Memi[$1+6*($2-1)+9] # Beam
+define APMW_APLOW Memd[P2D($1+6*($2-1)+10)] # Aperture low
+define APMW_APHIGH Memd[P2D($1+6*($2-1)+12)] # Aperture high
+
+
+# APMW_OPEN -- Open APMW structure.
+
+pointer procedure apmw_open (in, out, dispaxis, naps, nw)
+
+pointer in #I Input IMIO pointer
+pointer out #I Output IMIO pointer
+int dispaxis #I Input dispersion axis
+int naps #I Number of apertures
+int nw #I Number of dispersion pixels
+pointer apmw #O Returned APMW pointer
+
+int imgeti()
+double mw_c1trand()
+pointer mw, ct, mw_openim(), mw_sctran()
+errchk mw_openim, mw_sctran, mw_c1trand, apmw_wcsfix
+
+begin
+ # Allocate data structure.
+ call malloc (apmw, APMW_LEN(naps), TY_STRUCT)
+ call malloc (APMW_LABEL(apmw), SZ_LINE, TY_CHAR)
+ call malloc (APMW_UNITS(apmw), SZ_LINE, TY_CHAR)
+
+ # Set defaults.
+ call strcpy ("Pixel", Memc[APMW_LABEL(apmw)], SZ_LINE)
+ Memc[APMW_UNITS(apmw)] = EOS
+ APMW_DTYPE(apmw,i) = -1
+ APMW_NW(apmw,i) = nw
+ APMW_W1(apmw,i) = 1.
+ APMW_DW(apmw,i) = 1.
+
+ # Get WCS info from input image.
+ iferr {
+ mw = mw_openim (in)
+ iferr (APMW_DTYPE(apmw) = imgeti (in, "DC-FLAG"))
+ APMW_DTYPE(apmw) = -1
+ iferr (call mw_gwattrs (mw, dispaxis, "label",
+ Memc[APMW_LABEL(apmw)], SZ_LINE)) {
+ if (APMW_DTYPE(apmw) == -1)
+ call strcpy ("Pixel", Memc[APMW_LABEL(apmw)], SZ_LINE)
+ else
+ call strcpy ("Wavelength", Memc[APMW_LABEL(apmw)], SZ_LINE)
+ }
+ iferr (call mw_gwattrs (mw, dispaxis, "units",
+ Memc[APMW_UNITS(apmw)], SZ_LINE)) {
+ if (APMW_DTYPE(apmw) == -1)
+ Memc[APMW_UNITS(apmw)] = EOS
+ else
+ call strcpy ("Angstroms", Memc[APMW_UNITS(apmw)], SZ_LINE)
+ }
+
+ call apmw_wcsfix (in, mw)
+ iferr (ct = mw_sctran (mw, "logical", "world", dispaxis))
+ call error (1,
+ "Coordinate system ignored (rotated?). Using pixel coordinates.")
+ APMW_W1(apmw) = mw_c1trand (ct, 1D0)
+ APMW_DW(apmw) = mw_c1trand (ct, double (nw))
+ APMW_DW(apmw) = (APMW_DW(apmw)-APMW_W1(apmw))/(nw-1)
+ } then
+ call erract (EA_WARN)
+
+ call mw_close (mw)
+
+ return (apmw)
+end
+
+
+# APMW_CLOSE -- Close APMW structure.
+
+procedure apmw_close (apmw)
+
+pointer apmw # APMW pointer
+
+begin
+ call mfree (APMW_LABEL(apmw), TY_CHAR)
+ call mfree (APMW_UNITS(apmw), TY_CHAR)
+ call mfree (apmw, TY_STRUCT)
+end
+
+
+# APMW_SETAP -- Set aperture values in APMW structure.
+
+procedure apmw_setap (apmw, line, ap, beam, aplow, aphigh)
+
+pointer apmw # APMW pointer
+int line # Image line
+int ap # Aperture
+int beam # Beam
+real aplow # Aperture lower limit
+real aphigh # Aperture upper limit
+
+begin
+ APMW_AP(apmw,line) = ap
+ APMW_BEAM(apmw,line) = beam
+ APMW_APLOW(apmw,line) = aplow
+ APMW_APHIGH(apmw,line) = aphigh
+end
+
+
+# APMW_SAVEIM -- Save WCS in image header.
+
+procedure apmw_saveim (apmw, im, fmt)
+
+pointer apmw #I APMW pointer
+pointer im #I IMIO pointer
+int fmt #I Output format
+
+int i, naps, wcsdim, axes[3], imaccf()
+double r[3], w[3], cd[9]
+bool strne()
+pointer sp, key, str, mw, list, mw_open(), imofnlu(), imgnfn()
+errchk imdelf
+data axes/1,2,3/
+
+begin
+ call smark (sp)
+ call salloc (key, SZ_FNAME, TY_CHAR)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ if (fmt == STRIP)
+ naps = 1
+ else
+ naps = IM_LEN(im, 2)
+
+ # Workaround for truncation of header during image header copy.
+ IM_HDRLEN(im) = IM_LENHDRMEM(im)
+
+ # Delete keywords.
+ list = imofnlu (im, "SLFIB[0-9]*")
+ while (imgnfn (list, Memc[key], SZ_FNAME) != EOF)
+ call imdelf (im, Memc[key])
+ call imcfnl (list)
+
+ # Add aperture parameters to image header.
+ do i = 1, naps {
+ call sprintf (Memc[key], SZ_FNAME, "APNUM%d")
+ call pargi (i)
+ call sprintf (Memc[str], SZ_LINE, "%d %d %.2f %.2f")
+ call pargi (APMW_AP(apmw,i))
+ call pargi (APMW_BEAM(apmw,i))
+ call pargd (APMW_APLOW(apmw,i))
+ call pargd (APMW_APHIGH(apmw,i))
+ call imastr (im, Memc[key], Memc[str])
+ if (naps == 1) {
+ call sprintf (Memc[key], SZ_FNAME, "APID%d")
+ call pargi (i)
+ ifnoerr (call imgstr (im, Memc[key], Memc[str], SZ_LINE)) {
+ if (strne (Memc[str], IM_TITLE(im))) {
+ call imastr (im, "MSTITLE", IM_TITLE(im))
+ call strcpy (Memc[str], IM_TITLE(im), SZ_IMTITLE)
+ }
+ call imdelf (im, Memc[key])
+ }
+ }
+ }
+
+ # Add dispersion parameters to image header.
+ if (APMW_DTYPE(apmw) != -1)
+ call imaddi (im, "DC-FLAG", APMW_DTYPE(apmw))
+ else if (imaccf (im, "DC-FLAG") == YES)
+ call imdelf (im, "DC-FLAG")
+ if (APMW_NW(apmw) < IM_LEN(im,1))
+ call imaddi (im, "NP2", APMW_NW(apmw))
+ else if (imaccf (im, "NP2") == YES)
+ call imdelf (im, "NP2")
+ iferr (call imdelf (im, "dispaxis"))
+ ;
+ if (fmt == STRIP)
+ call imaddi (im, "dispaxis", 1)
+
+ # Set WCS in image header.
+ wcsdim = IM_NPHYSDIM(im)
+ mw = mw_open (NULL, wcsdim)
+ if (fmt == STRIP)
+ call mw_newsystem (mw, "linear", wcsdim)
+ else
+ call mw_newsystem (mw, "equispec", wcsdim)
+ call mw_swtype (mw, axes, wcsdim, "linear", "")
+ if (Memc[APMW_LABEL(apmw)] != EOS)
+ call mw_swattrs (mw, 1, "label", Memc[APMW_LABEL(apmw)])
+ if (Memc[APMW_UNITS(apmw)] != EOS)
+ call mw_swattrs (mw, 1, "units", Memc[APMW_UNITS(apmw)])
+
+ call aclrd (r, 3)
+ call aclrd (w, 3)
+ call aclrd (cd, 9)
+ r[1] = 1.
+ w[1] = APMW_W1(apmw)
+ cd[1] = APMW_DW(apmw)
+ if (wcsdim == 2)
+ cd[4] = 1.
+ if (wcsdim == 3) {
+ cd[5] = 1.
+ cd[9] = 1.
+ }
+ call mw_swtermd (mw, r, w, cd, wcsdim)
+
+ call mw_saveim (mw, im)
+ call mw_close (mw)
+
+ call sfree (sp)
+end
+
+
+# APMW_WCSFIX -- Fix up WCS to avoid CDELT=0 which occurs if there are WCS
+# keywords in the header but no CDELT.
+
+procedure apmw_wcsfix (im, mw)
+
+pointer im # IMIO pointer
+pointer mw # MWCS pointer
+
+int i, ndim, mw_stati()
+double val
+pointer sp, r, w, cd
+errchk mw_gwtermd, mw_swtermd
+
+begin
+ call mw_seti (mw, MW_USEAXMAP, NO)
+ ndim = mw_stati (mw, MW_NDIM)
+
+ call smark (sp)
+ call salloc (r, ndim, TY_DOUBLE)
+ call salloc (w, ndim, TY_DOUBLE)
+ call salloc (cd, ndim*ndim, TY_DOUBLE)
+
+ # Check cd terms. Assume no rotation.
+ call mw_gwtermd (mw, Memd[r], Memd[w], Memd[cd], ndim)
+ do i = 0, ndim-1 {
+ val = Memd[cd+i*(ndim+1)]
+ if (val == 0D0) {
+ Memd[w+i] = 1D0
+ Memd[cd+i*(ndim+1)] = 1D0
+ }
+ }
+ call mw_swtermd (mw, Memd[r], Memd[w], Memd[cd], ndim)
+
+ call sfree (sp)
+end
diff --git a/noao/twodspec/apextract/apnearest.x b/noao/twodspec/apextract/apnearest.x
new file mode 100644
index 00000000..f3e027c5
--- /dev/null
+++ b/noao/twodspec/apextract/apnearest.x
@@ -0,0 +1,75 @@
+include <mach.h>
+include "apertures.h"
+
+# AP_NEAREST -- Find the index of the aperture nearest cursor position x.
+
+define DELTA 0.01 # Tolerance for equidistant apertures
+
+procedure ap_nearest (index, line, aps, naps, x)
+
+int index # Index of aperture nearest x
+int line # Dispersion line
+pointer aps[ARB] # Aperture pointers
+int naps # Number of apertures
+real x # Point nearest aperture
+
+int i, j, apaxis
+char ch
+real d, delta
+pointer ap
+
+int fscan(), nscan()
+real ap_cveval()
+
+begin
+ if (naps == 0)
+ return
+
+ index = 0
+ delta = MAX_REAL
+
+ for (i = 1; i <= naps; i = i + 1) {
+ ap = aps[i]
+ apaxis = AP_AXIS(ap)
+ d = abs (AP_CEN(ap, apaxis)+ap_cveval(AP_CV(ap),real(line))-x)
+ if (d < delta - DELTA) {
+ j = 1
+ index = i
+ delta = d
+ } else if (d < delta + DELTA)
+ j = j + 1
+ }
+
+ # If there is more than one aperture equally near ask the user.
+ if (j > 1) {
+ call printf ("Apertures")
+ for (i = 1; i <= naps; i = i + 1) {
+ ap = aps[i]
+ apaxis = AP_AXIS(ap)
+ d = abs (AP_CEN(ap, apaxis)+ap_cveval(AP_CV(ap),real(line))-x)
+ if (d < delta + DELTA) {
+ call printf (" %d")
+ call pargi (AP_ID (ap))
+ }
+ }
+ call printf (" are equally near the cursor.\n")
+10 call printf ("Choose an aperture (%d): ")
+ call pargi (AP_ID (aps[index]))
+ call flush (STDOUT)
+ if (fscan (STDIN) != EOF) {
+ call scanc (ch)
+ if (ch == '\n')
+ return
+
+ call reset_scan()
+ call gargi (j)
+ if (nscan() == 0)
+ goto 10
+ for (i=1; (i<=naps)&&(AP_ID(aps[i])!=j); i=i+1)
+ ;
+ if (i > naps)
+ goto 10
+ index = i
+ }
+ }
+end
diff --git a/noao/twodspec/apextract/apnoise.key b/noao/twodspec/apextract/apnoise.key
new file mode 100644
index 00000000..4920453a
--- /dev/null
+++ b/noao/twodspec/apextract/apnoise.key
@@ -0,0 +1,14 @@
+ APNOISE CURSOR COMMANDS
+
+
+? Print command help
+q Quit
+r Redraw
+w Window the graph (see :/help)
+I Interupt immediately
+
+:gain <value> Check or set the gain model parameter
+:readnoise <value> Check or set the read noise model parameter
+
+Also see the CURSOR MODE commads (:.help) and the windowing commands
+(:/help).
diff --git a/noao/twodspec/apextract/apnoise.par b/noao/twodspec/apextract/apnoise.par
new file mode 100644
index 00000000..365bc1c3
--- /dev/null
+++ b/noao/twodspec/apextract/apnoise.par
@@ -0,0 +1,30 @@
+# APSIGMA
+
+input,s,a,,,,List of images to evaluate
+apertures,s,h,"",,,Apertures
+references,s,h,"",,,"List of reference images
+"
+dmin,r,a,,,,Data minimum for sigma bins
+dmax,r,a,,,,Data maximum for sigma bins
+nbins,i,a,,1,,Number of sigma bins
+interactive,b,h,yes,,,Run task interactively?
+find,b,h,yes,,,Find apertures?
+recenter,b,h,yes,,,Recenter apertures?
+resize,b,h,yes,,,Resize apertures?
+edit,b,h,yes,,,Edit apertures?
+trace,b,h,yes,,,Trace apertures?
+fittrace,b,h,yes,,,"Fit traced points interactively?
+"
+line,i,h,INDEF,1,,Dispersion line
+nsum,i,h,10,,,Number of dispersion lines to sum or median
+threshold,r,h,10.,,,"Division threshold for ratio fit
+"
+background,s,h,"none","none|average|median|minimum|fit",,Background to subtract
+pfit,s,h,"fit1d","fit1d|fit2d",,Profile fitting type (fit1d|fit2d)
+clean,b,h,no,,,Detect and replace bad pixels?
+skybox,i,h,1,1,,Box car smoothing length for sky
+saturation,r,h,INDEF,,,Saturation level
+readnoise,s,h,"0.",,,Read out noise sigma (photons)
+gain,s,h,"1.",,,Photon gain (photons/data number)
+lsigma,r,h,4.,0.,,Lower rejection threshold
+usigma,r,h,4.,0.,,Upper rejection threshold
diff --git a/noao/twodspec/apextract/apnoise.x b/noao/twodspec/apextract/apnoise.x
new file mode 100644
index 00000000..d22c09ae
--- /dev/null
+++ b/noao/twodspec/apextract/apnoise.x
@@ -0,0 +1,256 @@
+include <gset.h>
+include <pkg/gtools.h>
+include "apertures.h"
+
+
+# AP_NOISE -- Model residuals.
+
+procedure ap_noise (ap, gain, dbuf, nc, nl, c1, l1, sbuf, spec, profile, nx, ny,
+ xs, ys, sum2, sum4, nsum, nbin, dmin, dmax)
+
+pointer ap # Aperture structure
+real gain # Gain
+pointer dbuf # Data buffer
+int nc, nl # Size of data buffer
+int c1, l1 # Origin of data buffer
+pointer sbuf # Sky buffer (NULL if no sky)
+real spec[ny] # Normalization spectrum
+real profile[ny,nx] # Profile
+int nx, ny # Size of profile array
+int xs[ny], ys # Start of spectrum in image
+real sum2[nbin] # Sum of residuals squared in bin
+real sum4[nbin] # Sum of residuals squared in bin
+int nsum[nbin] # Number of values in bin
+int nbin # Number of bins
+real dmin, dmax # Data limits of bins
+
+int i, ix, iy, ix1, ix2
+real dstep, low, high, s, x1, x2, model, data, ap_cveval()
+pointer cv, sptr, dptr
+
+begin
+ dstep = (dmax - dmin) / nbin
+
+ i = AP_AXIS(ap)
+ low = AP_CEN(ap,i) + AP_LOW(ap,i)
+ high = AP_CEN(ap,i) + AP_HIGH(ap,i)
+ cv = AP_CV(ap)
+
+ do iy = 1, ny {
+ i = iy + ys - 1
+ s = ap_cveval (cv, real (i))
+ x1 = max (0.5, low + s)
+ x2 = min (c1 + nc - 0.49, high + s)
+ if (x1 > x2)
+ next
+
+ ix1 = nint (x1) - xs[iy] + 1
+ ix2 = nint (x2) - xs[iy] + 1
+
+ s = spec[iy]
+ if (sbuf != NULL)
+ sptr = sbuf + (iy - 1) * nx - 1
+ dptr = dbuf + (i - l1) * nc + nint(x1) - c1
+ do ix = ix1, ix2 {
+ if (sbuf != NULL) {
+ model = (s * profile[iy,ix] + Memr[sptr]) / gain
+ sptr = sptr + 1
+ } else
+ model = (s * profile[iy,ix]) / gain
+ data = Memr[dptr] / gain
+ dptr = dptr + 1
+
+ if (model < dmin || model >= dmax)
+ next
+ i = (model - dmin) / dstep + 1
+ sum2[i] = sum2[i] + (data - model) ** 2
+ sum4[i] = sum4[i] + (data - model) ** 4
+ nsum[i] = nsum[i] + 1
+ }
+ }
+end
+
+
+define HELP "noao$twodspec/apextract/apnoise.key"
+define PROMPT "apextract options"
+
+# AP_NPLOT -- Plot and examine noise characteristics.
+
+procedure ap_nplot (image, im, sigma, sigerr, npts, dmin, dmax)
+
+char image[SZ_FNAME] # Image
+pointer im # Image pointer
+real sigma[npts] # Sigma values
+real sigerr[npts] # Sigma errors
+int npts # Number of sigma values
+real dmin, dmax # Data min and max
+
+real rdnoise # Read noise
+real gain # Gain
+
+int i, newgraph, wcs, key
+real wx, wy, x, x1, x2, dx, y, ymin, ymax
+pointer sp, cmd, gp, gt
+
+int gt_gcur()
+real apgimr()
+#int apgwrd()
+#bool ap_answer()
+pointer gt_init()
+errchk ap_gopen
+
+begin
+ # Query user.
+ call smark (sp)
+ call salloc (cmd, SZ_LINE, TY_CHAR)
+ #call sprintf (Memc[cmd], SZ_LINE, "Edit apertures for %s?")
+ # call pargstr (image)
+ #if (!ap_answer ("ansedit", Memc[cmd])) {
+ # call sfree (sp)
+ # return
+ #}
+
+ gain = apgimr ("gain", im)
+ rdnoise = apgimr ("readnoise", im)
+
+ dx = (dmax - dmin) / npts
+ x1 = dmin + dx / 2
+ x2 = dmax - dx / 2
+ ymin = sigma[1] - sigerr[1]
+ ymax = sigma[1] + sigerr[1]
+ do i = 2, npts {
+ ymin = min (ymin, sigma[i] - sigerr[i])
+ ymax = max (ymax, sigma[i] + sigerr[i])
+ }
+
+ # Set up the graphics.
+ call sprintf (Memc[cmd], SZ_LINE, "Noise characteristics of image %s")
+ call pargstr (image)
+ call ap_gopen (gp)
+ gt = gt_init()
+ call gt_sets (gt, GTTITLE, Memc[cmd])
+ call gt_sets (gt, GTXLABEL, "Data value")
+ call gt_sets (gt, GTYLABEL, "Sigma")
+ call gt_sets (gt, GTTYPE, "mark")
+ call gt_sets (gt, GTMARK, "plus")
+
+ # Enter cursor loop.
+ key = 'r'
+ repeat {
+ switch (key) {
+ case '?': # Print help text.
+ call gpagefile (gp, HELP, PROMPT)
+
+ case ':': # Colon commands.
+ if (Memc[cmd] == '/')
+ call gt_colon (Memc[cmd], gp, gt, newgraph)
+ else
+ call ap_ncolon (Memc[cmd], rdnoise, gain, newgraph)
+
+ case 'q':
+ break
+
+ case 'r': # Redraw the graph.
+ newgraph = YES
+
+ case 'w': # Window graph
+ call gt_window (gt, gp, "gcur", newgraph)
+
+ case 'I': # Interrupt
+ call fatal (0, "Interrupt")
+
+ default: # Ring bell for unrecognized commands.
+ call printf ("\007")
+ }
+
+ # Update the graph if needed.
+ if (newgraph == YES) {
+ call sprintf (Memc[cmd], SZ_LINE,
+ "Read noise = %g e-, Gain = %g e-/DN")
+ call pargr (rdnoise)
+ call pargr (gain)
+ call gt_sets (gt, GTPARAMS, Memc[cmd])
+
+ call gclear (gp)
+ y = sqrt ((rdnoise/gain)**2 + dmax/gain)
+ call gswind (gp, dmin, dmax, ymin, max (ymax, y))
+ call gt_swind (gp, gt)
+ call gt_labax (gp, gt)
+ do i = 1, npts {
+ if (sigma[i] > 0) {
+ x = x1 + (i-1) * dx
+ call gmark (gp, x, sigma[i], GM_VEBAR+GM_HLINE, -dx/2,
+ -sigerr[i])
+ }
+ }
+ do i = 1, npts {
+ x = x1 + (i-1) * dx
+ y = sqrt ((rdnoise/gain)**2 + x/gain)
+ if (i == 1)
+ call gamove (gp, x, y)
+ else
+ call gadraw (gp, x, y)
+ }
+ newgraph = NO
+ }
+
+ } until (gt_gcur ("gcur", wx, wy, wcs, key, Memc[cmd], SZ_LINE) == EOF)
+
+ # Free memory.
+ call gt_free (gt)
+ call sfree (sp)
+end
+
+
+# List of colon commands.
+define CMDS "|readnoise|gain|"
+define RDNOISE 1 # Read noise
+define GAIN 2 # Gain
+
+# AP_NCOLON -- Respond to colon command from ap_nplot.
+
+procedure ap_ncolon (command, rdnoise, gain, newgraph)
+
+char command[ARB] # Colon command
+real rdnoise # Readout noise
+real gain # Gain
+int newgraph # New graph?
+
+real rval
+int ncmd, nscan(), strdic()
+pointer sp, cmd
+
+begin
+ # Scan the command string and get the first word.
+ call smark (sp)
+ call salloc (cmd, SZ_LINE, TY_CHAR)
+
+ call sscan (command)
+ call gargwrd (cmd, SZ_LINE)
+ ncmd = strdic (cmd, cmd, SZ_LINE, CMDS)
+
+ switch (ncmd) {
+ case RDNOISE:
+ call gargr (rval)
+ if (nscan() == 2) {
+ rdnoise = rval
+ newgraph = YES
+ } else {
+ call printf ("rdnoise %g\n")
+ call pargr (rdnoise)
+ }
+ case GAIN:
+ call gargr (rval)
+ if (nscan() == 2) {
+ gain = rval
+ newgraph = YES
+ } else {
+ call printf ("gain %g\n")
+ call pargr (gain)
+ }
+ default:
+ call printf ("Unrecognized or ambiguous command\007")
+ }
+
+ call sfree (sp)
+end
diff --git a/noao/twodspec/apextract/apnoise1.par b/noao/twodspec/apextract/apnoise1.par
new file mode 100644
index 00000000..3b5532a7
--- /dev/null
+++ b/noao/twodspec/apextract/apnoise1.par
@@ -0,0 +1,118 @@
+# OUTPUT PARAMETERS
+
+apertures,s,h,)apall.apertures,,,>apnoise.apertures
+format,s,h,)apsum.format,,,>apsum.format
+extras,b,h,)apsum.extras,,,>apsum.extras
+dbwrite,s,h,yes,,,Write to database?
+initialize,b,h,yes,,,Initialize answers?
+verbose,b,h,)_.verbose,,,"Verbose output?
+
+# DEFAULT APERTURE PARAMETERS
+"
+lower,r,h,)apdefault.lower,,,>apdefault.lower
+upper,r,h,)apdefault.upper,,,>apdefault.upper
+apidtable,s,h,)apdefault.apidtable,,,">apdefault.apidtable
+
+# DEFAULT BACKGROUND PARAMETERS
+"
+b_function,s,h,)apdefault.b_function,,,>apdefault.b_function
+b_order,i,h,)apdefault.b_order,,,>apdefault.b_order
+b_sample,s,h,)apdefault.b_sample,,,>apdefault.b_sample
+b_naverage,i,h,)apdefault.b_naverage,,,>apdefault.b_naverage
+b_niterate,i,h,)apdefault.b_niterate,,,>apdefault.b_niterate
+b_low_reject,r,h,)apdefault.b_low_reject,,,>apdefault.b_low_reject
+b_high_reject,r,h,)apdefault.b_high_reject,,,>apdefault.b_high_reject
+b_grow,r,h,)apdefault.b_grow,,,">apdefault.b_grow
+
+# APERTURE CENTERING PARAMETERS
+"
+width,r,h,)apedit.width,,,>apedit.width
+radius,r,h,)apedit.radius,,,>apedit.radius
+threshold,r,h,)apedit.threshold,,,">apedit.threshold
+
+# AUTOMATIC FINDING AND ORDERING PARAMETERS
+"
+nfind,i,h,)apfind.nfind,,,>apfind.nfind
+minsep,r,h,)apfind.minsep,,,>apfind.minsep
+maxsep,r,h,)apfind.maxsep,,,>apfind.maxsep
+order,s,h,)apfind.order,,,">apfind.order
+
+# RECENTERING PARAMETERS
+"
+aprecenter,s,h,)aprecenter.aprecenter,,,>aprecenter.aprecenter
+npeaks,r,h,)aprecenter.npeaks,,,>aprecenter.npeaks
+shift,b,h,)aprecenter.shift,,,">aprecenter.shift
+
+# RESIZING PARAMETERS
+"
+llimit,r,h,)apresize.llimit,,,>apresize.llimit
+ulimit,r,h,)apresize.ulimit,,,>apresize.ulimit
+ylevel,r,h,)apresize.ylevel,,,>apresize.ylevel
+peak,b,h,)apresize.peak,,,>apresize.peak
+bkg,b,h,)apresize.bkg,,,>apresize.bkg
+r_grow,r,h,)apresize.r_grow,,,>apresize.r_grow
+avglimits,b,h,)apresize.avglimits,,,">apresize.avglimits
+
+# EDITING PARAMETERS
+"
+e_output,s,q,,,,Output spectra rootname
+e_profiles,s,q,,,,Profile reference image
+
+# TRACING PARAMETERS
+t_nsum,i,h,)aptrace.nsum,,,>aptrace.nsum
+t_step,i,h,)aptrace.step,,,>aptrace.step
+t_nlost,i,h,)aptrace.nlost,,,>aptrace.nlost
+t_width,r,h,)apedit.width,,,>apedit.width
+t_function,s,h,)aptrace.function,,,>aptrace.function
+t_order,i,h,)aptrace.order,,,>aptrace.order
+t_sample,s,h,)aptrace.sample,,,>aptrace.sample
+t_naverage,i,h,)aptrace.naverage,,,>aptrace.naverage
+t_niterate,i,h,)aptrace.niterate,,,>aptrace.niterate
+t_low_reject,r,h,)aptrace.low_reject,,,>aptrace.low_reject
+t_high_reject,r,h,)aptrace.high_reject,,,>aptrace.high_reject
+t_grow,r,h,)aptrace.grow,,,">aptrace.grow
+
+# EXTRACTION PARAMETERS
+"
+background,s,h,)apnoise.background,,,>apnoise.background
+skybox,i,h,)apnoise.skybox,,,>apnoise.skybox
+weights,s,h,"none",,,Extraction weights (none|variance)
+pfit,s,h,)apnoise.pfit,,,>apnoise.pfit
+clean,b,h,)apnoise.clean,,,>apnoise.clean
+nclean,r,h,0.5,,,Maximum number of pixels to clean
+niterate,i,h,5,0,,Number of profile fitting iterations
+saturation,r,h,)apnoise.saturation,,,>apnoise.saturation
+readnoise,s,h,)apnoise.readnoise,,,>apnoise.readnoise
+gain,s,h,)apnoise.gain,,,>apnoise.gain
+lsigma,r,h,)apnoise.lsigma,,,>apnoise.lsigma
+usigma,r,h,)apnoise.usigma,,,>apnoise.usigma
+polysep,r,h,0.90,0.1,0.95,Marsh algorithm polynomial spacing
+polyorder,i,h,10,1,,Marsh algorithm polynomial order
+nsubaps,i,h,1,,,"Number of subapertures per aperture
+
+# ANSWER PARAMETERS
+"
+ansclobber,s,h,"no",,," "
+ansclobber1,s,h,"no",,," "
+ansdbwrite,s,h,"yes",,," "
+ansdbwrite1,s,h,"yes",,," "
+ansedit,s,h,"yes",,," "
+ansextract,s,h,"yes",,," "
+ansfind,s,h,"yes",,," "
+ansfit,s,h,"yes",,," "
+ansfitscatter,s,h,"yes",,," "
+ansfitsmooth,s,h,"yes",,," "
+ansfitspec,s,h,"yes",,," "
+ansfitspec1,s,h,"yes",,," "
+ansfittrace,s,h,"yes",,," "
+ansfittrace1,s,h,"yes",,," "
+ansflat,s,h,"yes",,," "
+ansmask,s,h,"yes",,," "
+ansnorm,s,h,"yes",,," "
+ansrecenter,s,h,"yes",,," "
+ansresize,s,h,"yes",,," "
+ansreview,s,h,"yes",,," "
+ansreview1,s,h,"yes",,," "
+ansscat,s,h,"yes",,," "
+anssmooth,s,h,"yes",,," "
+anstrace,s,h,"yes",,," "
diff --git a/noao/twodspec/apextract/apnorm1.par b/noao/twodspec/apextract/apnorm1.par
new file mode 100644
index 00000000..1a182dce
--- /dev/null
+++ b/noao/twodspec/apextract/apnorm1.par
@@ -0,0 +1,118 @@
+# OUTPUT PARAMETERS
+
+apertures,s,h,)apall.apertures,,,>apnorm.apertures
+format,s,h,)apsum.format,,,>apsum.format
+extras,b,h,)apsum.extras,,,>apsum.extras
+dbwrite,s,h,yes,,,Write to database?
+initialize,b,h,yes,,,Initialize answers?
+verbose,b,h,)_.verbose,,,"Verbose output?
+
+# DEFAULT APERTURE PARAMETERS
+"
+lower,r,h,)apdefault.lower,,,>apdefault.lower
+upper,r,h,)apdefault.upper,,,>apdefault.upper
+apidtable,s,h,)apdefault.apidtable,,,">apdefault.apidtable
+
+# DEFAULT BACKGROUND PARAMETERS
+"
+b_function,s,h,)apdefault.b_function,,,>apdefault.b_function
+b_order,i,h,)apdefault.b_order,,,>apdefault.b_order
+b_sample,s,h,)apdefault.b_sample,,,>apdefault.b_sample
+b_naverage,i,h,)apdefault.b_naverage,,,>apdefault.b_naverage
+b_niterate,i,h,)apdefault.b_niterate,,,>apdefault.b_niterate
+b_low_reject,r,h,)apdefault.b_low_reject,,,>apdefault.b_low_reject
+b_high_reject,r,h,)apdefault.b_high_reject,,,>apdefault.b_high_reject
+b_grow,r,h,)apdefault.b_grow,,,">apdefault.b_grow
+
+# APERTURE CENTERING PARAMETERS
+"
+width,r,h,)apedit.width,,,>apedit.width
+radius,r,h,)apedit.radius,,,>apedit.radius
+threshold,r,h,)apedit.threshold,,,">apedit.threshold
+
+# AUTOMATIC FINDING AND ORDERING PARAMETERS
+"
+nfind,i,h,)apfind.nfind,,,>apfind.nfind
+minsep,r,h,)apfind.minsep,,,>apfind.minsep
+maxsep,r,h,)apfind.maxsep,,,>apfind.maxsep
+order,s,h,)apfind.order,,,">apfind.order
+
+# RECENTERING PARAMETERS
+"
+aprecenter,s,h,)aprecenter.aprecenter,,,>aprecenter.aprecenter
+npeaks,r,h,)aprecenter.npeaks,,,>aprecenter.npeaks
+shift,b,h,)aprecenter.shift,,,">aprecenter.shift
+
+# RESIZING PARAMETERS
+"
+llimit,r,h,)apresize.llimit,,,>apresize.llimit
+ulimit,r,h,)apresize.ulimit,,,>apresize.ulimit
+ylevel,r,h,)apresize.ylevel,,,>apresize.ylevel
+peak,b,h,)apresize.peak,,,>apresize.peak
+bkg,b,h,)apresize.bkg,,,>apresize.bkg
+r_grow,r,h,)apresize.r_grow,,,>apresize.r_grow
+avglimits,b,h,)apresize.avglimits,,,">apresize.avglimits
+
+# EDITING PARAMETERS
+"
+e_output,s,q,,,,Output spectra rootname
+e_profiles,s,q,,,,Profile reference image
+
+# TRACING PARAMETERS
+t_nsum,i,h,)aptrace.nsum,,,>aptrace.nsum
+t_step,i,h,)aptrace.step,,,>aptrace.step
+t_nlost,i,h,)aptrace.nlost,,,>aptrace.nlost
+t_width,r,h,)apedit.width,,,>apedit.width
+t_function,s,h,)aptrace.function,,,>aptrace.function
+t_order,i,h,)aptrace.order,,,>aptrace.order
+t_sample,s,h,)aptrace.sample,,,>aptrace.sample
+t_naverage,i,h,)aptrace.naverage,,,>aptrace.naverage
+t_niterate,i,h,)aptrace.niterate,,,>aptrace.niterate
+t_low_reject,r,h,)aptrace.low_reject,,,>aptrace.low_reject
+t_high_reject,r,h,)aptrace.high_reject,,,>aptrace.high_reject
+t_grow,r,h,)aptrace.grow,,,">aptrace.grow
+
+# EXTRACTION PARAMETERS
+"
+background,s,h,)apnorm.background,,,>apnorm.background
+skybox,i,h,)apnorm.skybox,,,>apnorm.skybox
+weights,s,h,)apnorm.weights,,,>apnorm.weights
+pfit,s,h,)apnorm.pfit,,,>apnorm.pfit
+clean,b,h,)apnorm.clean,,,>apnorm.clean
+nclean,r,h,0.5,,,Maximum number of pixels to clean
+niterate,i,h,5,0,,Number of profile fitting iterations
+saturation,r,h,)apnorm.saturation,,,>apnorm.saturation
+readnoise,s,h,)apnorm.readnoise,,,>apnorm.readnoise
+gain,s,h,)apnorm.gain,,,>apnorm.gain
+lsigma,r,h,)apnorm.lsigma,,,>apnorm.lsigma
+usigma,r,h,)apnorm.usigma,,,>apnorm.usigma
+polysep,r,h,0.90,0.1,0.95,Marsh algorithm polynomial spacing
+polyorder,i,h,10,1,,Marsh algorithm polynomial order
+nsubaps,i,h,1,,,"Number of subapertures per aperture
+
+# ANSWER PARAMETERS
+"
+ansclobber,s,h,"no",,," "
+ansclobber1,s,h,"no",,," "
+ansdbwrite,s,h,"yes",,," "
+ansdbwrite1,s,h,"yes",,," "
+ansedit,s,h,"yes",,," "
+ansextract,s,h,"yes",,," "
+ansfind,s,h,"yes",,," "
+ansfit,s,h,"yes",,," "
+ansfitscatter,s,h,"yes",,," "
+ansfitsmooth,s,h,"yes",,," "
+ansfitspec,s,h,"yes",,," "
+ansfitspec1,s,h,"yes",,," "
+ansfittrace,s,h,"yes",,," "
+ansfittrace1,s,h,"yes",,," "
+ansflat,s,h,"yes",,," "
+ansmask,s,h,"yes",,," "
+ansnorm,s,h,"yes",,," "
+ansrecenter,s,h,"yes",,," "
+ansresize,s,h,"yes",,," "
+ansreview,s,h,"yes",,," "
+ansreview1,s,h,"yes",,," "
+ansscat,s,h,"yes",,," "
+anssmooth,s,h,"yes",,," "
+anstrace,s,h,"yes",,," "
diff --git a/noao/twodspec/apextract/apnormalize.par b/noao/twodspec/apextract/apnormalize.par
new file mode 100644
index 00000000..2fc64432
--- /dev/null
+++ b/noao/twodspec/apextract/apnormalize.par
@@ -0,0 +1,41 @@
+# APNORMALIZE
+
+input,s,a,,,,List of images to normalize
+output,s,a,,,,List of output normalized images
+apertures,s,h,"",,,Apertures
+references,s,h,"",,,"List of reference images
+"
+interactive,b,h,yes,,,Run task interactively?
+find,b,h,yes,,,Find apertures?
+recenter,b,h,yes,,,Recenter apertures?
+resize,b,h,yes,,,Resize apertures?
+edit,b,h,yes,,,Edit apertures?
+trace,b,h,yes,,,Trace apertures?
+fittrace,b,h,yes,,,Fit traced points interactively?
+normalize,b,h,yes,,,Normalize spectra?
+fitspec,b,h,yes,,,"Fit normalization spectra interactively?
+"
+line,i,h,INDEF,1,,Dispersion line
+nsum,i,h,10,,,Number of dispersion lines to sum or median
+cennorm,b,h,no,,,Normalize to the aperture center?
+threshold,r,h,10.,,,"Threshold for normalization spectra
+"
+background,s,h,"none","none|average|median|minimum|fit",,Background to subtract
+weights,s,h,"none","none|variance",,Extraction weights (none|variance)
+pfit,s,h,"fit1d","fit1d|fit2d",,Profile fitting type (fit1d|fit2d)
+clean,b,h,no,,,Detect and replace bad pixels?
+skybox,i,h,1,1,,Box car smoothing length for sky
+saturation,r,h,INDEF,,,Saturation level
+readnoise,s,h,"0.",,,Read out noise sigma (photons)
+gain,s,h,"1.",,,Photon gain (photons/data number)
+lsigma,r,h,4.,0.,,Lower rejection threshold
+usigma,r,h,4.,0.,,"Upper rejection threshold
+"
+function,s,h,"legendre","chebyshev|legendre|spline1|spline3",,Fitting function for normalization spectra
+order,i,h,1,1,,Fitting function order
+sample,s,h,"*",,,Sample regions
+naverage,i,h,1,,,Average or median
+niterate,i,h,0,0,,Number of rejection iterations
+low_reject,r,h,3.,0.,,Lower rejection sigma
+high_reject,r,h,3.,0.,,High upper rejection sigma
+grow,r,h,0.,0.,,Rejection growing radius
diff --git a/noao/twodspec/apextract/apparams.dat b/noao/twodspec/apextract/apparams.dat
new file mode 100644
index 00000000..897e4f2e
--- /dev/null
+++ b/noao/twodspec/apextract/apparams.dat
@@ -0,0 +1,68 @@
+"OUTPUT PARAMETERS"
+format s %s 26
+extras b %b 26
+dbwrite s %s 26
+
+"DEFAULT APERTURE PARAMETERS"
+lower r %g 26
+upper r %g 26
+apidtable s %s 26
+
+"DEFAULT BACKGROUND PARAMETERS"
+b_function s %s 26
+b_order i %d 26
+b_sample s %s 26
+b_naverage i %d 26
+b_niterate i %d 26
+b_low_reject r %g 26
+b_high_reject r %g 26
+b_grow r %g 26
+
+"APERTURE CENTERING PARAMETERS: FINDING, RECENTERING, MARKING"
+width r %g 26
+radius r %g 26
+threshold r %g 26
+
+"AUTOMATIC APERTURE FINDING AND ORDERING PARAMETERS"
+minsep r %g 26
+maxsep r %g 26
+order s %s 26
+
+"RECENTERING PARAMETERS"
+apertures s %s 26
+npeaks r %g 26
+shift b %b 26
+
+"RESIZING PARAMETERS"
+llimit r %g 26
+ulimit r %g 26
+ylevel r %g 26
+peak b %b 26
+bkg b %b 26
+r_grow r %g 26
+avglimits b %b 26
+
+"TRACING PARAMETERS"
+t_nsum i %d 26
+t_step i %d 26
+t_width r %g 26
+t_function s %s 26
+t_order i %d 26
+t_sample s %s 26
+t_naverage i %d 26
+t_niterate i %d 26
+t_low_reject r %g 26
+t_high_reject r %g 26
+t_grow r %g 26
+
+"EXTRACTION PARAMETERS"
+weights s %s 26
+background s %s 26
+clean b %b 26
+saturation r %g 26
+readnoise r %g 26
+gain r %g 26
+lsigma r %g 26
+usigma r %g 26
+skybox i %d 26
+nsubaps i %d 26
diff --git a/noao/twodspec/apextract/apparams.h b/noao/twodspec/apextract/apparams.h
new file mode 100644
index 00000000..ac3e37cb
--- /dev/null
+++ b/noao/twodspec/apextract/apparams.h
@@ -0,0 +1,92 @@
+# PP_TABLE -- This table assigns pset pointers for each parameter.
+
+define PP_PP_LENTABLE 61
+
+# APDEFAULT
+
+define PP_APIDTABLE Memi[$1]
+define PP_LOWER Memi[$1+1]
+define PP_UPPER Memi[$1+2]
+define PP_B_FUNCTION Memi[$1+3]
+define PP_B_ORDER Memi[$1+4]
+define PP_B_SAMPLE Memi[$1+5]
+define PP_B_NAVERAGE Memi[$1+6]
+define PP_B_NITERATE Memi[$1+7]
+define PP_B_LOW_REJECT Memi[$1+8]
+define PP_B_HIGH_REJECT Memi[$1+9]
+define PP_B_GROW Memi[$1+10]
+
+#APFIND
+
+define PP_NFIND Memi[$1+11]
+define PP_MINSEP Memi[$1+12]
+define PP_MAXSEP Memi[$1+13]
+define PP_ORDER Memi[$1+14]
+
+# APRECENTER
+
+define PP_APERTURES Memi[$1+15]
+define PP_NPEAKS Memi[$1+16]
+define PP_SHIFT Memi[$1+17]
+
+# APRESIZE
+
+define PP_LLIMIT Memi[$1+18]
+define PP_ULIMIT Memi[$1+19]
+define PP_YLEVEL Memi[$1+20]
+define PP_PEAK Memi[$1+21]
+define PP_BKG Memi[$1+22]
+
+# APEDIT
+
+define PP_WIDTH Memi[$1+23]
+define PP_RADIUS Memi[$1+24]
+define PP_THRESHOLD Memi[$1+25]
+define PP_E_OUTPUT Memi[$1+26]
+define PP_E_SKY Memi[$1+27]
+define PP_E_PROFILES Memi[$1+28]
+
+# APTRACE
+
+define PP_FITTRACE Memi[$1+29]
+define PP_T_NSUM Memi[$1+30]
+define PP_STEP Memi[$1+31]
+define PP_T_FUNCTION Memi[$1+32]
+define PP_T_ORDER Memi[$1+33]
+define PP_T_SAMPLE Memi[$1+34]
+define PP_T_NAVERAGE Memi[$1+35]
+define PP_T_NITERATE Memi[$1+36]
+define PP_T_LOW_REJECT Memi[$1+37]
+define PP_T_HIGH_REJECT Memi[$1+38]
+define PP_T_GROW Memi[$1+39]
+
+# APSUM or APSTRIP
+
+define PP_SKYEXTRACT Memi[$1+40]
+define PP_BACKGROUND Memi[$1+41]
+define PP_CLEAN Memi[$1+42]
+define PP_WEIGHTS Memi[$1+43]
+define PP_FIT(pp) Memi[$1+61]
+define PP_NAVERAGE Memi[$1+44]
+define PP_INTERPOLATOR Memi[$1+45]
+define PP_NCLEAN Memi[$1+46]
+define PP_LSIGMA Memi[$1+47]
+define PP_USIGMA Memi[$1+48]
+define PP_V0 Memi[$1+49]
+define PP_V1 Memi[$1+50]
+
+# APNORMALIZE
+
+define PP_N_THRESHOLD Memi[$1+51]
+define PP_N_FUNCTION Memi[$1+52]
+define PP_N_ORDER Memi[$1+53]
+define PP_N_SAMPLE Memi[$1+54]
+define PP_N_NAVERAGE Memi[$1+55]
+define PP_N_NITERATE Memi[$1+56]
+define PP_N_LOW_REJECT Memi[$1+57]
+define PP_N_HIGH_REJECT Memi[$1+58]
+define PP_N_GROW Memi[$1+59]
+
+# APSCATTER
+
+define PP_BUFFER Memi[$1+60]
diff --git a/noao/twodspec/apextract/apparams.par b/noao/twodspec/apextract/apparams.par
new file mode 100644
index 00000000..61b2b2ce
--- /dev/null
+++ b/noao/twodspec/apextract/apparams.par
@@ -0,0 +1,117 @@
+# OUTPUT PARAMETERS
+
+format,s,h,)apsum.format,,,>apsum.format
+extras,b,h,)apsum.extras,,,>apsum.extras
+dbwrite,s,h,yes,,,Write to database?
+initialize,b,h,yes,,,Initialize answers?
+verbose,b,h,)_.verbose,,,"Verbose output?
+
+# DEFAULT APERTURE PARAMETERS
+"
+lower,r,h,)apdefault.lower,,,>apdefault.lower
+upper,r,h,)apdefault.upper,,,>apdefault.upper
+apidtable,s,h,)apdefault.apidtable,,,">apdefault.apidtable
+
+# DEFAULT BACKGROUND PARAMETERS
+"
+b_function,s,h,)apdefault.b_function,,,>apdefault.b_function
+b_order,i,h,)apdefault.b_order,,,>apdefault.b_order
+b_sample,s,h,)apdefault.b_sample,,,>apdefault.b_sample
+b_naverage,i,h,)apdefault.b_naverage,,,>apdefault.b_naverage
+b_niterate,i,h,)apdefault.b_niterate,,,>apdefault.b_niterate
+b_low_reject,r,h,)apdefault.b_low_reject,,,>apdefault.b_low_reject
+b_high_reject,r,h,)apdefault.b_high_reject,,,>apdefault.b_high_reject
+b_grow,r,h,)apdefault.b_grow,,,">apdefault.b_grow
+
+# APERTURE CENTERING PARAMETERS
+"
+width,r,h,)apedit.width,,,>apedit.width
+radius,r,h,)apedit.radius,,,>apedit.radius
+threshold,r,h,)apedit.threshold,,,">apedit.threshold
+
+# AUTOMATIC FINDING AND ORDERING PARAMETERS
+"
+nfind,i,h,)apfind.nfind,,,>apfind.nfind
+minsep,r,h,)apfind.minsep,,,>apfind.minsep
+maxsep,r,h,)apfind.maxsep,,,>apfind.maxsep
+order,s,h,)apfind.order,,,">apfind.order
+
+# RECENTERING PARAMETERS
+"
+aprecenter,s,h,)aprecenter.aprecenter,,,>aprecenter.aprecenter
+npeaks,r,h,)aprecenter.npeaks,,,>aprecenter.npeaks
+shift,b,h,)aprecenter.shift,,,">aprecenter.shift
+
+# RESIZING PARAMETERS
+"
+llimit,r,h,)apresize.llimit,,,>apresize.llimit
+ulimit,r,h,)apresize.ulimit,,,>apresize.ulimit
+ylevel,r,h,)apresize.ylevel,,,>apresize.ylevel
+peak,b,h,)apresize.peak,,,>apresize.peak
+bkg,b,h,)apresize.bkg,,,>apresize.bkg
+r_grow,r,h,)apresize.r_grow,,,>apresize.r_grow
+avglimits,b,h,)apresize.avglimits,,,">apresize.avglimits
+
+# EDITING PARAMETERS
+"
+e_output,s,q,,,,Output spectra rootname
+e_profiles,s,q,,,,Profile reference image
+
+# TRACING PARAMETERS
+t_nsum,i,h,)aptrace.nsum,,,>aptrace.nsum
+t_step,i,h,)aptrace.step,,,>aptrace.step
+t_nlost,i,h,)aptrace.nlost,,,>aptrace.nlost
+t_width,r,h,)apedit.width,,,>apedit.width
+t_function,s,h,)aptrace.function,,,>aptrace.function
+t_order,i,h,)aptrace.order,,,>aptrace.order
+t_sample,s,h,)aptrace.sample,,,>aptrace.sample
+t_naverage,i,h,)aptrace.naverage,,,>aptrace.naverage
+t_niterate,i,h,)aptrace.niterate,,,>aptrace.niterate
+t_low_reject,r,h,)aptrace.low_reject,,,>aptrace.low_reject
+t_high_reject,r,h,)aptrace.high_reject,,,>aptrace.high_reject
+t_grow,r,h,)aptrace.grow,,,">aptrace.grow
+
+# EXTRACTION PARAMETERS
+"
+background,s,h,)apsum.background,,,>apsum.background
+skybox,i,h,)apsum.skybox,,,>apsum.skybox
+weights,s,h,)apsum.weights,,,>apsum.weights
+pfit,s,h,)apsum.pfit,,,>apsum.pfit
+clean,b,h,)apsum.clean,,,>apsum.clean
+nclean,r,h,0.5,,,Maximum number of pixels to clean
+niterate,i,h,5,0,,Number of profile fitting iterations
+saturation,r,h,)apsum.saturation,,,>apsum.saturation
+readnoise,s,h,)apsum.readnoise,,,>apsum.readnoise
+gain,s,h,)apsum.gain,,,>apsum.gain
+lsigma,r,h,)apsum.lsigma,,,>apsum.lsigma
+usigma,r,h,)apsum.usigma,,,>apsum.usigma
+polysep,r,h,0.90,0.1,0.95,Marsh algorithm polynomial spacing
+polyorder,i,h,10,1,,Marsh algorithm polynomial order
+nsubaps,i,h,)apsum.nsubaps,,,">apsum.nsubaps
+
+# ANSWER PARAMETERS
+"
+ansclobber,s,h,"no",,," "
+ansclobber1,s,h,"no",,," "
+ansdbwrite,s,h,"yes",,," "
+ansdbwrite1,s,h,"yes",,," "
+ansedit,s,h,"yes",,," "
+ansextract,s,h,"yes",,," "
+ansfind,s,h,"yes",,," "
+ansfit,s,h,"yes",,," "
+ansfitscatter,s,h,"yes",,," "
+ansfitsmooth,s,h,"yes",,," "
+ansfitspec,s,h,"yes",,," "
+ansfitspec1,s,h,"yes",,," "
+ansfittrace,s,h,"yes",,," "
+ansfittrace1,s,h,"yes",,," "
+ansflat,s,h,"yes",,," "
+ansmask,s,h,"yes",,," "
+ansnorm,s,h,"yes",,," "
+ansrecenter,s,h,"yes",,," "
+ansresize,s,h,"yes",,," "
+ansreview,s,h,"yes",,," "
+ansreview1,s,h,"yes",,," "
+ansscat,s,h,"yes",,," "
+anssmooth,s,h,"yes",,," "
+anstrace,s,h,"yes",,," "
diff --git a/noao/twodspec/apextract/apparams.x b/noao/twodspec/apextract/apparams.x
new file mode 100644
index 00000000..526b4bcd
--- /dev/null
+++ b/noao/twodspec/apextract/apparams.x
@@ -0,0 +1,95 @@
+define PARAMS "apextract$apparams.dat"
+define LEN_LINE 80
+
+# AP_PARAMS -- Show the parameters.
+
+procedure ap_params (file, image, line, nsum)
+
+char file[ARB] # Aperture file
+char image[ARB] # Image name
+int line # Image line
+int nsum # Number of lines to sum
+
+int in, out, len, nchar
+pointer sp, param, type, format, instr, outstr, str
+bool apgetb()
+int apgeti(), open(), fscan(), nscan(), strlen()
+real apgetr()
+errchk open
+
+begin
+ # Open input parameter file and output stream.
+ in = open (PARAMS, READ_ONLY, TEXT_FILE)
+ out = open (file, APPEND, TEXT_FILE)
+
+ call smark (sp)
+ call salloc (param, SZ_LINE, TY_CHAR)
+ call salloc (type, 10, TY_CHAR)
+ call salloc (format, 10, TY_CHAR)
+ call salloc (instr, SZ_LINE, TY_CHAR)
+ call salloc (outstr, SZ_LINE, TY_CHAR)
+ call salloc (str, SZ_LINE, TY_CHAR)
+ Memc[outstr] = EOS
+
+ call fprintf (out, "%32tAPEXTRACT PARAMETERS\n")
+ call fprintf (out, "image=%s%27tline=%d%53tnsum=%d\n")
+ call pargstr (image)
+ call pargi (line)
+ call pargi (nsum)
+ call fprintf (out, "database=%s%27tlogfile=%s%53tplotfile=%s\n\n")
+ call clgstr ("database", Memc[str], SZ_LINE)
+ call pargstr (Memc[str])
+ call clgstr ("logfile", Memc[str], SZ_LINE)
+ call pargstr (Memc[str])
+ call clgstr ("plotfile", Memc[str], SZ_LINE)
+ call pargstr (Memc[str])
+
+ len = 0
+ while (fscan (in) != EOF) {
+ call gargwrd (Memc[param], SZ_LINE)
+ call gargwrd (Memc[type], 10)
+ call gargwrd (Memc[format], 10)
+ call gargi (nchar)
+ if (nscan() < 4)
+ nchar = LEN_LINE
+
+ if (len + nchar > LEN_LINE) {
+ call strcat ("\n", Memc[outstr], SZ_LINE)
+ call fprintf (out, Memc[outstr])
+ Memc[outstr] = EOS
+ len = 0
+ }
+
+ if (nscan() == 1) {
+ call sprintf (Memc[outstr], SZ_LINE, "%%%dt%s")
+ call pargi ((LEN_LINE - strlen (Memc[param])) / 2)
+ call pargstr (Memc[param])
+ } else if (nscan() == 4) {
+ call sprintf (Memc[str], SZ_LINE, "%%%dt%s=")
+ call pargi (len+1)
+ call pargstr (Memc[param])
+ call strcat (Memc[str], Memc[outstr], SZ_LINE)
+
+ call sprintf (Memc[str], SZ_LINE, Memc[format])
+ switch (Memc[type]) {
+ case 'b':
+ call pargb (apgetb (Memc[param]))
+ case 'i':
+ call pargi (apgeti (Memc[param]))
+ case 'r':
+ call pargr (apgetr (Memc[param]))
+ case 's':
+ call apgstr (Memc[param], Memc[instr], SZ_LINE)
+ call pargstr (Memc[instr])
+ }
+ call strcat (Memc[str], Memc[outstr], SZ_LINE)
+ }
+ len = len + nchar
+ }
+ call strcat ("\n", Memc[outstr], SZ_LINE)
+ call fprintf (out, Memc[outstr])
+
+ call close (in)
+ call close (out)
+ call sfree (sp)
+end
diff --git a/noao/twodspec/apextract/appars.x b/noao/twodspec/apextract/appars.x
new file mode 100644
index 00000000..8f68c0c9
--- /dev/null
+++ b/noao/twodspec/apextract/appars.x
@@ -0,0 +1,261 @@
+include <math/iminterp.h>
+
+procedure apopset (pset)
+
+char pset[ARB] # Pset name
+pointer pp, clopset ()
+common /apparam/ pp
+
+begin
+ pp = clopset (pset)
+end
+
+
+procedure apcpset ()
+
+pointer pp
+common /apparam/ pp
+
+begin
+ call clcpset (pp)
+end
+
+
+procedure apgstr (param, str, maxchar)
+
+char param[ARB] # Parameter name
+char str[ARB] # String to return
+int maxchar # Maximum length of string
+
+pointer pp
+common /apparam/ pp
+
+begin
+ call clgpset (pp, param, str, maxchar)
+end
+
+
+bool procedure apgetb (param)
+
+char param[ARB] # Parameter name
+bool clgpsetb()
+pointer pp
+common /apparam/ pp
+
+begin
+ return (clgpsetb (pp, param))
+end
+
+
+int procedure apgeti (param)
+
+char param[ARB] # Parameter name
+int clgpseti()
+pointer pp
+common /apparam/ pp
+
+begin
+ return (clgpseti (pp, param))
+end
+
+
+real procedure apgetr (param)
+
+char param[ARB] # Parameter name
+real clgpsetr()
+pointer pp
+common /apparam/ pp
+
+begin
+ return (clgpsetr (pp, param))
+end
+
+
+real procedure apgimr (param, im)
+
+char param[ARB] # Parameter name
+pointer im # IMIO pointer
+int i, ctor()
+pointer pp, sp, str
+real rval, imgetr()
+common /apparam/ pp
+errchk imgetr
+
+begin
+ call smark (sp)
+ call salloc (str, SZ_FNAME, TY_CHAR)
+ call clgpset (pp, param, Memc[str], SZ_FNAME)
+ i = 1
+ if (ctor (Mems[str], i, rval) == 0)
+ rval = imgetr (im, Memc[str])
+ call sfree (sp)
+ return (rval)
+end
+
+
+int procedure apgwrd (param, keyword, maxchar, dictionary)
+
+char param[ARB] # CL parameter string
+char keyword[ARB] # String matched in dictionary
+int maxchar # Maximum size of str
+char dictionary[ARB] # Dictionary string
+
+int i, strdic()
+pointer pp
+common /apparam/ pp
+
+begin
+ call clgpset (pp, param, keyword, maxchar)
+ i = strdic (keyword, keyword, maxchar, dictionary)
+ if (i <= 0)
+ call error (1, "Ambiguous or unknown parameter value")
+ return (i)
+end
+
+
+# APGINTERP -- Select an interpolator from a CL input string. The procedure
+# is coded to be protected from changes in the values of the interpolator
+# types in interpdef.h.
+
+int procedure apginterp (param)
+
+char param[ARB] # CL parameter prompt string
+int index, iicodes[5]
+pointer sp, word
+int apgwrd()
+errchk apgwrd
+data iicodes /II_NEAREST, II_LINEAR, II_POLY3, II_POLY5, II_SPLINE3/
+
+pointer pp
+common /apparam/ pp
+
+begin
+ call smark (sp)
+ call salloc (word, SZ_FNAME, TY_CHAR)
+
+ index = max (1, min (5, apgwrd (param, Memc[word], SZ_FNAME,
+ "|nearest|linear|poly3|poly5|spline3|")))
+
+ call sfree (sp)
+ return (iicodes[index])
+end
+
+
+procedure appstr (param, str)
+
+char param[ARB] # Parameter name
+char str[ARB] # String to be put
+pointer pp, sp, str1, str2
+common /apparam/ pp
+
+int i, strmatch(), stridxs()
+
+begin
+ if (strmatch (param, "p_") == 0) {
+ call smark (sp)
+ call salloc (str1, SZ_FNAME, TY_CHAR)
+ call salloc (str2, SZ_LINE, TY_CHAR)
+ call sprintf (Memc[str1], SZ_FNAME, "%s.p_prompt")
+ call pargstr (param)
+ call clgpset (pp, Memc[str1], Memc[str2], SZ_LINE)
+ if (Memc[str2] == '>') {
+ i = stridxs (" \\\t\n", Memc[str2])
+ if (i > 0)
+ Memc[str2+i-1] = EOS
+ call clpstr (Memc[str2+1], str)
+ } else
+ call clppset (pp, param, str)
+ call sfree (sp)
+ } else
+ call clppset (pp, param, str)
+end
+
+
+procedure apputb (param, bval)
+
+char param[ARB] # Parameter name
+bool bval # Value to be put
+pointer pp, sp, str1, str2
+common /apparam/ pp
+
+int i, strmatch(), stridxs()
+
+begin
+ if (strmatch (param, "p_") == 0) {
+ call smark (sp)
+ call salloc (str1, SZ_FNAME, TY_CHAR)
+ call salloc (str2, SZ_LINE, TY_CHAR)
+ call sprintf (Memc[str1], SZ_FNAME, "%s.p_prompt")
+ call pargstr (param)
+ call clgpset (pp, Memc[str1], Memc[str2], SZ_LINE)
+ if (Memc[str2] == '>') {
+ i = stridxs (" \\\t\n", Memc[str2])
+ if (i > 0)
+ Memc[str2+i-1] = EOS
+ call clputb (Memc[str2+1], bval)
+ } else
+ call clppsetb (pp, param, bval)
+ call sfree (sp)
+ } else
+ call clppsetb (pp, param, bval)
+end
+
+
+procedure apputi (param, ival)
+
+char param[ARB] # Parameter name
+int ival # Value to be put
+pointer pp, sp, str1, str2
+common /apparam/ pp
+
+int i, strmatch(), stridxs()
+
+begin
+ if (strmatch (param, "p_") == 0) {
+ call smark (sp)
+ call salloc (str1, SZ_FNAME, TY_CHAR)
+ call salloc (str2, SZ_LINE, TY_CHAR)
+ call sprintf (Memc[str1], SZ_FNAME, "%s.p_prompt")
+ call pargstr (param)
+ call clgpset (pp, Memc[str1], Memc[str2], SZ_LINE)
+ if (Memc[str2] == '>') {
+ i = stridxs (" \\\t\n", Memc[str2])
+ if (i > 0)
+ Memc[str2+i-1] = EOS
+ call clputi (Memc[str2+1], ival)
+ } else
+ call clppseti (pp, param, ival)
+ call sfree (sp)
+ } else
+ call clppseti (pp, param, ival)
+end
+
+
+procedure apputr (param, rval)
+
+char param[ARB] # Parameter name
+real rval # Value to be put
+pointer pp, sp, str1, str2
+common /apparam/ pp
+
+int i, strmatch(), stridxs()
+
+begin
+ if (strmatch (param, "p_") == 0) {
+ call smark (sp)
+ call salloc (str1, SZ_FNAME, TY_CHAR)
+ call salloc (str2, SZ_LINE, TY_CHAR)
+ call sprintf (Memc[str1], SZ_FNAME, "%s.p_prompt")
+ call pargstr (param)
+ call clgpset (pp, Memc[str1], Memc[str2], SZ_LINE)
+ if (Memc[str2] == '>') {
+ i = stridxs (" \\\t\n", Memc[str2])
+ if (i > 0)
+ Memc[str2+i-1] = EOS
+ call clputr (Memc[str2+1], rval)
+ } else
+ call clppsetr (pp, param, rval)
+ call sfree (sp)
+ } else
+ call clppsetr (pp, param, rval)
+end
diff --git a/noao/twodspec/apextract/apprint.x b/noao/twodspec/apextract/apprint.x
new file mode 100644
index 00000000..b2bf17f0
--- /dev/null
+++ b/noao/twodspec/apextract/apprint.x
@@ -0,0 +1,34 @@
+include "apertures.h"
+
+# AP_PRINT -- Print the parameters of the indexed aperture.
+
+procedure ap_print (index, line, all, aps)
+
+int index # Index of aperture
+int line # Dispersion line
+int all # All flag
+pointer aps[ARB] # Apertures
+
+int apaxis
+pointer ap
+real ap_cveval()
+
+begin
+ if (index < 1)
+ return
+
+ if (all == YES)
+ call printf ("ALL: ")
+ else
+ call printf (" ")
+
+ ap = aps[index]
+ apaxis = AP_AXIS(ap)
+ call printf (
+"aperture = %d beam = %d center = %.2f low = %.2f upper = %.2f\n")
+ call pargi (AP_ID(ap))
+ call pargi (AP_BEAM(ap))
+ call pargr (AP_CEN(ap, apaxis)+ap_cveval (AP_CV(ap), real (line)))
+ call pargr (AP_LOW(ap, apaxis))
+ call pargr (AP_HIGH(ap, apaxis))
+end
diff --git a/noao/twodspec/apextract/approfile.x b/noao/twodspec/apextract/approfile.x
new file mode 100644
index 00000000..eeb31a6d
--- /dev/null
+++ b/noao/twodspec/apextract/approfile.x
@@ -0,0 +1,765 @@
+include <mach.h>
+include <gset.h>
+include <math/curfit.h>
+include "apertures.h"
+
+
+# AP_PROFILE -- Determine spectrum profile with pixel rejection.
+#
+# The profile is determined by dividing each dispersion point by an estimate
+# of the spectrum and then smoothing and normalizing to unit integral.
+# This routine has two algorithms (procedures) for smoothing, one for nearly
+# aligned spectra and one for tilted spectra. The selection is determined
+# by the calling program and signaled by whether there is a variation in
+# the profile offsets. For both smoothing algorithms the same iterative
+# rejection algorithm may be used to eliminate deviant points from affecting
+# the profile. This rejection is selected by the "clean" parameter.
+# A plot of the final profile along the dispersion may be made for the
+# special plotfile "debugfits" or "debugall".
+#
+# Dispersion points with saturated pixels are ignored as well a when the
+# total sky subtracted flux is negative.
+
+procedure ap_profile (im, ap, dbuf, nc, nl, c1, l1, sbuf, svar, profile, nx, ny,
+ xs, ys, asi)
+
+pointer im # IMIO pointer
+pointer ap # Aperture structure
+pointer dbuf # Data buffer
+int nc, nl # Size of data buffer
+int c1, l1 # Origin of data buffer
+pointer sbuf # Sky values (NULL if none)
+pointer svar # Sky variances
+real profile[ny,nx] # Profile (returned)
+int nx, ny # Size of profile array
+int xs[ny], ys # Origin of profile array
+pointer asi # Image interpolator for edge pixel weighting
+
+real gain # Gain
+real rdnoise # Readout noise
+real saturation # Maximum value for an unsaturated pixel
+bool clean # Clean cosmic rays?
+real lsigma, usigma # Rejection sigmas.
+
+int fd, ix, iy, ix1, ix2, xs1, xs2, nsum
+int i, niterate, ixrej, iyrej, nrej, nreject
+real p, s, chisq, tfac, rrej, predict, var0, var, vmin, resid, wt1, wt2, dat
+pointer sp, str, spec, x1, x2, y, reject, xreject, data, sky, cv, gp
+
+int apgeti()
+real apgetr(), ap_cveval(), apgimr()
+bool apgetb()
+errchk salloc, ap_horne, ap_marsh, apgimr, ap_asifit
+
+begin
+ # Allocate memory. Adjust pointers to be one indexed.
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+ call salloc (spec, ny, TY_REAL)
+ call salloc (x1, ny, TY_REAL)
+ call salloc (x2, ny, TY_REAL)
+ call salloc (y, ny, TY_REAL)
+ call salloc (reject, nx*ny, TY_BOOL)
+ if (sbuf == NULL) {
+ call salloc (sky, nx, TY_REAL)
+ sky = sky - 1
+ }
+ spec=spec-1; x1=x1-1; x2=x2-1; y=y-1
+
+ # Get task parameters.
+ gain = apgimr ("gain", im)
+ rdnoise = apgimr ("readnoise", im) ** 2
+ saturation = apgetr ("saturation")
+ if (!IS_INDEF(saturation))
+ saturation = saturation * gain
+ lsigma = apgetr ("lsigma")
+ usigma = apgetr ("usigma")
+ clean = apgetb ("clean")
+ if (clean)
+ niterate = apgeti ("niterate")
+ else
+ niterate = 0
+
+ # Initialize.
+ if (rdnoise == 0.)
+ vmin = 1.
+ else
+ vmin = rdnoise
+ if (sbuf == NULL) {
+ call aclrr (Memr[sky+1], nx)
+ var0 = rdnoise
+ }
+ cv = AP_CV(ap)
+
+ # Set aperture limits and initialize rejection flags.
+ call alimi (xs, ny, xs1, xs2)
+ i = AP_AXIS(ap)
+ p = AP_CEN(ap,i) + AP_LOW(ap,i)
+ s = AP_CEN(ap,i) + AP_HIGH(ap,i)
+ xreject = reject
+ do iy = 1, ny {
+ dat = ap_cveval (cv, real (iy + ys - 1)) - c1 + 1
+ Memr[x1+iy] = p + dat
+ Memr[x2+iy] = s + dat
+ Memr[x1+iy] = max (0.5, Memr[x1+iy]) + c1 - xs[iy]
+ Memr[x2+iy] = min (nc + 0.49, Memr[x2+iy]) + c1 - xs[iy]
+ ix1 = nint (Memr[x1+iy])
+ ix2 = nint (Memr[x2+iy])
+ Memr[y+iy] = iy
+ do ix = 1, nx {
+ if (ix < ix1 || ix > ix2)
+ Memb[xreject] = false
+ else
+ Memb[xreject] = true
+ xreject = xreject + 1
+ }
+ }
+
+ # Estimate spectrum by summing across the aperture with partial
+ # pixel estimates at the aperture edges. The initial profile
+ # estimates are obtained by normalizing by the spectrum estimate.
+ # Profiles where the spectrum is below sky are set to zero.
+
+ call aclrr (profile, nx * ny)
+ nrej = 0
+ do iy = 1, ny {
+ if (Memr[x1+iy] >= Memr[x2+iy]) {
+ Memr[spec+iy] = 0.
+ do ix = 1, nx
+ profile[iy,ix] = 0.
+ next
+ }
+
+ call ap_asifit (dbuf+(iy+ys-1-l1)*nc, nc, xs[iy]-c1+1,
+ Memr[x1+iy]-c1+xs[iy], Memr[x2+iy]-c1+xs[iy], data, asi)
+ if (sbuf != NULL)
+ sky = sbuf + (iy - 1) * nx - 1
+ call ap_edge (asi, Memr[x1+iy]+1, Memr[x2+iy]+1, wt1, wt2)
+ ix1 = nint (Memr[x1+iy])
+ ix2 = nint (Memr[x2+iy])
+ s = 0.
+ do ix = ix1, ix2 {
+ if (!IS_INDEF(saturation))
+ if (Memr[data+ix] > saturation) {
+ s = 0.
+ nrej = nrej + 1
+ break;
+ }
+ dat = Memr[data+ix] - Memr[sky+ix]
+ if (ix1 == ix2)
+ dat = wt1 * dat
+ else if (ix == ix1)
+ dat = wt1 * dat
+ else if (ix == ix2)
+ dat = wt2 * dat
+ s = s + dat
+ }
+
+ if (s > 0.) {
+ do ix = ix1, ix2
+ profile[iy,ix] = max (0., (Memr[data+ix]-Memr[sky+ix])/s)
+ } else {
+ do ix = ix1, ix2
+ profile[iy,ix] = 0.
+ }
+ Memr[spec+iy] = s
+ }
+
+ if (nrej == ny)
+ call error (1, "All profiles contain saturated pixels")
+ else if (nrej > 0) {
+ call sprintf (Memc[str], SZ_LINE,
+ "EXTRACT: %d profiles with saturated pixels in aperture %d")
+ call pargi (nrej)
+ call pargi (AP_ID(ap))
+ if (nrej < ny / 3)
+ call ap_log (Memc[str], YES, NO, NO)
+ else
+ call ap_log (Memc[str], YES, NO, YES)
+ }
+
+ # Smooth the profile and possibly reject deviant pixels.
+ nreject = 0
+ tfac = 2.
+ do i = 0, niterate {
+
+ # Estimate profile.
+ if (xs1 == xs2)
+ call ap_horne (im, cv, dbuf, nc, nl, c1, l1, Memr[spec+1], sbuf,
+ svar, Memb[reject], profile, nx, ny, xs, ys,
+ Memr[x1+1], Memr[x2+1])
+ else
+ call ap_marsh (im, dbuf, nc, nl, c1, l1, Memr[spec+1], sbuf,
+ svar, Memb[reject], profile, nx, ny, xs, ys,
+ Memr[x1+1], Memr[x2+1])
+
+ if (i == niterate)
+ break
+
+ # Reject pixels. The rejection threshold is based on the overall
+ # chi square. Pixels are rejected on the basis of the current
+ # chi square and the largest residual not rejected is compared
+ # against the final chi square to possibly trigger another round
+ # of rejections.
+
+ chisq = 0.; nsum = 0; ixrej = 0; iyrej = 0; rrej = 0.; nrej = 0
+ do iy = 1, ny {
+ s = Memr[spec+iy]
+ if (s <= 0.)
+ next
+ call ap_asifit (dbuf+(iy+ys-1-l1)*nc, nc, xs[iy]-c1+1,
+ Memr[x1+iy]-c1+xs[iy], Memr[x2+iy]-c1+xs[iy], data, asi)
+ if (sbuf != NULL) {
+ sky = sbuf + (iy - 1) * nx - 1
+ var0 = rdnoise + Memr[svar+iy-1]
+ }
+ call ap_edge (asi, Memr[x1+iy]+1, Memr[x2+iy]+1, wt1, wt2)
+ xreject = reject + (iy - 1) * nx - 1
+ ix1 = nint (Memr[x1+iy])
+ ix2 = nint (Memr[x2+iy])
+ do ix = ix1, ix2 {
+ if (Memb[xreject+ix]) {
+ nsum = nsum + 1
+ predict = max (0., s * profile[iy,ix] + Memr[sky+ix])
+ var = max (vmin, var0 + predict)
+ resid = (Memr[data+ix] - predict) / sqrt (var)
+ chisq = chisq + resid**2
+ if (resid < -tfac*lsigma || resid > tfac*usigma) {
+ if (ix < ix1 || ix > ix2)
+ p = 0.
+ else if (ix1 == ix2)
+ p = wt1
+ else if (ix == ix1)
+ p = wt1
+ else if (ix == ix2)
+ p = wt2
+ else
+ p = 1
+ Memr[spec+iy] = Memr[spec+iy] -
+ p * (Memr[data+ix] - predict)
+ nrej = nrej + 1
+ Memb[xreject+ix] = false
+ } else if (abs (resid) > abs (rrej)) {
+ rrej = resid
+ if (ix < ix1 || ix > ix2)
+ p = 0.
+ else if (ix1 == ix2)
+ p = wt1
+ else if (ix == ix1)
+ p = wt1
+ else if (ix == ix2)
+ p = wt2
+ else
+ p = 1
+ dat = p * (Memr[data+ix] - predict)
+ ixrej = ix
+ iyrej = iy
+ }
+ }
+ }
+ }
+
+ if (nsum == 0)
+ call error (1, "All pixels rejected")
+ tfac = sqrt (chisq / nsum)
+ if (rrej < -tfac * lsigma || rrej > tfac * usigma) {
+ Memr[spec+iyrej] = Memr[spec+iyrej] - dat
+ xreject = reject + (iyrej - 1) * nx - 1
+ Memb[xreject+ixrej] = false
+ nrej = nrej + 1
+ }
+
+ nreject = nreject + nrej
+ if (nrej == 0)
+ break
+ }
+
+ # These plots are too big for production work but can be turned on
+ # for debugging.
+
+ call ap_popen (gp, fd, "fits")
+ if (gp != NULL) {
+ ix1 = xs1
+ ix2 = xs2 + nx - 1
+ if (xs1 != xs2) {
+ ix1 = ix1 + 1
+ ix2 = ix2 - 1
+ }
+ do ix = ix1, ix2 {
+ nrej = 0
+ do iy = 1, ny {
+ i = ix - xs[iy] + 1
+ if (i < 1 || i > nx)
+ next
+ if (Memr[spec+iy] <= 0.)
+ next
+ data = dbuf + (iy + ys - 1 - l1) * nc + ix - c1 - 1
+ if (sbuf != NULL)
+ s = Memr[sbuf+(iy-1)*nx+i-1]
+ else
+ s = Memr[sky+i]
+ nrej = nrej + 1
+ Memr[y+nrej] = iy + ys - 1
+ Memr[x1+nrej] = max (-.1, min (1.1,
+ (Memr[data+1] - s) / Memr[spec+iy]))
+ Memr[x2+nrej] = profile[iy,i]
+ }
+ call gclear (gp)
+ call gascale (gp, Memr[x1+1], nrej, 2)
+ call grscale (gp, Memr[x2+1], nrej, 2)
+ call gswind (gp, Memr[y+1], Memr[y+nrej], INDEF, INDEF)
+ if (AP_AXIS(ap) == 1) {
+ call sprintf (Memc[str], SZ_LINE, "Column %d")
+ call pargi (ix)
+ call glabax (gp, Memc[str], "Line", "Profile")
+ } else {
+ call sprintf (Memc[str], SZ_LINE, "Line %d")
+ call pargi (ix)
+ call glabax (gp, Memc[str], "Column", "Profile")
+ }
+ call gpmark (gp, Memr[y+1], Memr[x1+1], nrej, GM_POINT, 1., 1.)
+ call gpline (gp, Memr[y+1], Memr[x2+1], nrej)
+ }
+ }
+ call ap_pclose (gp, fd)
+
+ # Log the number of rejected pixels.
+ if (clean) {
+ call sprintf (Memc[str], SZ_LINE,
+ "EXTRACT: %d pixels rejected for profile from aperture %d")
+ call pargi (nreject)
+ call pargi (AP_ID(ap))
+ call ap_log (Memc[str], YES, NO, NO)
+ }
+
+ call sfree (sp)
+end
+
+
+# AP_HORNE -- Determine profile by fitting a low order function parallel to
+# dispersion along image lines or columns after dividing by a spectrum
+# estimate. An initial profile estimate and a rejection array are
+# required for setting the weights. This is a straightforward algorithm
+# similar to images.fit1d except that it is noninteractive. The fitting
+# function is fixed at a cubic spline and the number of pieces is set by
+# the amount of tilt such that there is one cubic spline piece per
+# passage across the tilted spectrum plus an amount based on the order
+# of the tracing function. It is named after Keith Horne
+# since this is what is outlined in his paper. The profile array is used
+# cleverly to minimize memory requirements. The storage order of the
+# profile array, which is transposed relative to the data, is determined
+# by this procedure.
+
+procedure ap_horne (im, cvtrace, dbuf, nc, nl, c1, l1, spec, sbuf, svar, reject,
+ profile, nx, ny, xs, ys, x1, x2)
+
+pointer im # IMIO pointer
+pointer cvtrace # Trace pointer
+pointer dbuf # Data buffer
+int nc, nl # Size of data buffer
+int c1, l1 # Origin of data buffer
+real spec[ny] # Spectrum estimate
+pointer sbuf # Sky values (NULL if none)
+pointer svar # Sky variances
+bool reject[nx,ny] # Rejection flags
+real profile[ny,nx] # Initial profile in, improved profile out
+int nx, ny # Size of profile array
+int xs[ny], ys # Origin of profile array
+real x1[ny], x2[ny] # Aperture limits in profile array
+
+int cvtype # Curfit type
+int order # Order of curfit function.
+real rdnoise # Readout noise in RMS data numbers.
+
+int ix, iy, ierr
+real p, s, sk, var, vmin, var0, wmin
+pointer sp, y, w, cv, dbuf1, data, sky
+
+#int apgeti()
+int cvstati()
+real apgimr()
+errchk salloc, apgimr
+
+begin
+ call smark (sp)
+ call salloc (y, ny, TY_REAL)
+ call salloc (w, ny, TY_REAL)
+
+ # Get CL parameters
+ #cvtype = apgeti ("e_function")
+ #order = apgeti ("e_order")
+ rdnoise = apgimr ("readnoise", im) ** 2
+
+ # Initialize.
+ call alimr (x1, ny, p, s)
+ cvtype = SPLINE3
+ order = int (s - p + 1) + max (0, cvstati (cvtrace, CVNCOEFF) - 2)
+ #order = min (20, order)
+ order = 2 * order
+ call cvinit (cv, cvtype, order, 1., real (ny))
+ do iy = 1, ny
+ Memr[y+iy-1] = iy
+ if (rdnoise == 0.)
+ vmin = 1.
+ else
+ vmin = rdnoise
+ dbuf1 = dbuf + (ys - l1 - 1) * nc - c1 - 1
+ if (sbuf == NULL) {
+ sk = 0.
+ var0 = rdnoise
+ }
+
+ # For each line parallel to the dispersion divide by a spectrum
+ # estimate and then fit the smoothing function. Use the input
+ # profile and rejection array to set the weights.
+
+ do ix = 1, nx {
+ data = dbuf1 + ix
+ if (sbuf != NULL)
+ sky = sbuf - nx - 1 + ix
+ wmin = MAX_REAL
+ do iy = 1, ny {
+ s = spec[iy]
+ if (s > 0. && reject[ix,iy]) {
+ if (sbuf != NULL) {
+ sk = Memr[sky+iy*nx]
+ var0 = rdnoise + Memr[svar+iy-1]
+ }
+ p = profile[iy,ix]
+ var = max (vmin, var0 + max (0., s * p + sk))
+ var = (s ** 2) / var
+ wmin = min (wmin, var)
+ Memr[w+iy-1] = var
+ profile[iy,ix] = (Memr[data+iy*nc+xs[iy]] - sk) / s
+ } else
+ Memr[w+iy-1] = 0.
+ }
+ if (wmin == MAX_REAL)
+ call amovkr (1., Memr[w], ny)
+ else
+ call amaxkr (Memr[w], wmin / 10., Memr[w], ny)
+ call cvfit (cv, Memr[y], profile[1,ix], Memr[w], ny, WTS_USER, ierr)
+ call cvvector (cv, Memr[y], profile[1,ix], ny)
+ call amaxkr (profile[1,ix], 0., profile[1,ix], ny)
+ }
+
+ call cvfree (cv)
+ call sfree (sp)
+end
+
+
+# AP_MARSH -- Determine profile by Marsh algorithm (PASP V101, P1032, 1989).
+# This algorithm fits low order polynomials to weighted points sampled
+# at uniform intervals parallel to the aperture trace. The polynomials
+# are coupled through the weights and so requires a 2D matrix inversion.
+# This is a relatively slow algorithm but does provide low order smoothing
+# for arbitrary profile shapes in highly tilted spectra. An estimate
+# of the profile, a rejection array, sky and sky variance, and aperture
+# limit arrays are required.
+
+procedure ap_marsh (im, dbuf, nc, nl, c1, l1, spec, sbuf, svar, reject,
+ profile, nx, ny, xs, ys, x1, x2)
+
+pointer im # IMIO pointer
+pointer dbuf # Data buffer
+int nc, nl # Size of data buffer
+int c1, l1 # Origin of data buffer
+real spec[ny] # Spectrum estimate
+pointer sbuf # Sky values (NULL if none)
+pointer svar # Sky variances
+bool reject[nx,ny] # Rejection flags
+real profile[ny,nx] # Initial profile in, improved profile out
+int nx, ny # Size of profile array
+int xs[ny], ys # Origin of profile array
+real x1[ny], x2[ny] # Aperture limits in profile array
+
+real spix # Polynomial pixel separation
+int npols # Number of polynomials
+int order # Order of function.
+real rdnoise # Readout noise in RMS data numbers.
+
+int il, jl, kl, ll, ix, iy, ix1, ix2, nside, nadd
+int ip, ip1, ip2, index1, index2, index3
+real p, s, s2, dat, sk, var, vmin, var0
+real dx0, dx1, dx2, dx3, dx4, xj, xk, xt, xz, qj, qk, xadd
+double sum1, sum2
+pointer sp, work, work1, work2, work3, work4, ysum, data, sky
+
+int apgeti()
+real apgetr(), apgimr()
+errchk salloc, apgimr
+
+begin
+ # Get CL parameters
+ #npols = apgeti ("npols")
+ spix = apgetr ("polysep")
+ order = apgeti ("polyorder")
+ rdnoise = apgimr ("readnoise", im) ** 2
+
+ # Set dimensions.
+ npols = (x2[1] - x1[1] + 2) / spix
+ spix = (x2[1] - x1[1] + 2) / real (npols)
+ nside = npols * order
+ nadd = nside * nside
+ if (spix > 1.)
+ call error (4, "Polynomial separation too large")
+
+ # Allocate memory. One index pointers.
+ call smark (sp)
+ call salloc (work, nadd+3*nside, TY_REAL)
+ call salloc (work4, nside, TY_INT)
+ call salloc (ysum, ny, TY_REAL)
+ work = work - 1
+ work1 = work + nadd
+ work2 = work1 + nside
+ work3 = work2 + nside
+ work4 = work4 - 1
+ ysum=ysum-1
+ if (sbuf == NULL) {
+ call salloc (sky, nx, TY_REAL)
+ sky = sky - 1
+ }
+
+ # Initialize.
+ call aclrr (Memr[work+1], nadd+3*nside)
+ call aclri (Memi[work4+1], nside)
+ if (rdnoise == 0.)
+ vmin = 1.
+ else
+ vmin = rdnoise
+ if (sbuf == NULL) {
+ call aclrr (Memr[sky+1], nx)
+ var0 = rdnoise
+ }
+
+ # Factors for weights.
+ dx0 = 0.5 - spix
+ dx1 = abs (dx0)
+ dx2 = 1. - (dx0 / spix) ** 2
+ dx3 = 0.5 + spix
+ dx4 = sqrt (2.) * spix
+
+ # Accumulate least terms for least squares matrix equation AX = B.
+
+ # First accumulate B.
+ do jl = 0, npols-1 {
+ do iy = 1, ny {
+ if (spec[iy] <= 0.)
+ next
+
+ xj = x1[iy] - 1 + spix * (real (jl) + 0.5)
+ ix1 = nint (xj - spix)
+ ix2 = nint (xj + spix)
+ if (ix1 < 1 || ix2 > nx) {
+ Memr[ysum+iy] = 0.
+ next
+ }
+
+ data = dbuf + (iy + ys - 1 - l1) * nc + xs[iy] - c1 - 1
+ if (sbuf != NULL) {
+ sky = sbuf + (iy - 1) * nx - 1
+ var0 = rdnoise + Memr[svar+iy-1]
+ }
+
+ # Evaluate qj, the contribution of polynomial number jl+1
+ # for the pixel ix1,jj. Four cases are considered. The
+ # first two account for the triangular interpolation
+ # function partially overlapping a pixel, on one side
+ # only. The third is for the function wholly inside a
+ # pixel, and finally for the pixel wholly covered by the
+ # interpolation function.
+
+ s = spec[iy]
+ sum1 = 0.
+ do ix = ix1, ix2 {
+ if (!reject[ix,iy])
+ next
+ p = profile[iy,ix]
+ sk = Memr[sky+ix]
+ dat = Memr[data+ix] - sk
+ var = max (vmin, var0 + max (0., s * p + sk))
+
+ xz = xj - real (ix)
+ xt = abs (xz)
+ if (xt >= dx1) {
+ if (xt >= 0.5)
+ qj = ((xt - dx3) / dx4) ** 2
+ else
+ qj = 1.- ((xt - dx0) / dx4) ** 2
+
+ } else if (xt <= dx0)
+ qj = 1.
+ else
+ qj = dx2 - (xz / spix) ** 2
+ sum1 = sum1 + qj * s * dat / var
+ }
+ Memr[ysum+iy] = sum1
+ }
+
+ index1 = order * jl
+ do il = 1, order {
+ sum1 = 0.
+ ip = il - 1
+ do iy = 1, ny
+ if (spec[iy] > 0.)
+ sum1 = sum1 + Memr[ysum+iy] * ((real (iy) / ny) ** ip)
+ Memr[work1+index1+il] = sum1
+ }
+ }
+
+ # Now accumulate matrix A. Since it is symmetric we only need to
+ # evaluate half of it. Since it is banded we only need to evaluate
+ # contribution if two polynomial terms can be affected by the same
+ # pixel.
+
+ ip1 = nside - 1
+ ip2 = order * ip1
+ do jl = 0, npols-1 {
+ do kl = 0, jl {
+ if (spix * (jl - kl - 2) > 0.)
+ next
+ do iy = 1, ny {
+ if (spec[iy] <= 0.)
+ next
+ if (sbuf != NULL) {
+ sky = sbuf + (iy - 1) * nx - 1
+ var0 = rdnoise + Memr[svar+iy-1]
+ }
+
+ # Compute left and right limits of polynomials jl+1
+ # and kl+1 for this value of y Evaluate sum over row
+ # of qj[jl+1] times qj[kl+1] where qj[i] is fraction
+ # of polynomial i which contributes to to pixel ix,jj.
+
+ xj = x1[iy] - 1 + spix * (real (jl) + 0.5)
+ xk = x1[iy] - 1 + spix * (real (kl) + 0.5)
+ ix1 = nint (xj - spix)
+ ix2 = nint (xk + spix)
+
+ if (ix2 < ix1 || ix1 < 1 || ix2 > nx) {
+ Memr[ysum+iy] = 0.
+ next
+ }
+
+ s = spec[iy]
+ s2 = s * s
+ sum1 = 0.
+ do ix = ix1, ix2 {
+ if (reject[ix,iy]) {
+ p = profile[iy,ix]
+ sk = Memr[sky+ix]
+ var = max (vmin, var0 + max (0., s * p + sk))
+
+ xz = xj - real (ix)
+ xt = abs (xz)
+ if (xt >= dx1) {
+ if (xt >= 0.5)
+ qj = ((xt-dx3)/dx4)**2
+ else
+ qj = 1.- ((xt-dx0)/dx4)**2
+ } else if (xt <= dx0)
+ qj = 1.
+ else
+ qj = dx2 - (xz / spix) ** 2
+ if (kl != jl) {
+ xz = xk - real (ix)
+ xt = abs (xz)
+ if (xt >= dx1) {
+ if (xt >= 0.5)
+ qk = ((xt-dx3)/dx4)**2
+ else
+ qk = 1.-((xt-dx0)/dx4)**2
+ } else if (xt <= dx0)
+ qk = 1.
+ else
+ qk = dx2 - (xz / spix) ** 2
+ } else
+ qk = qj
+ sum1 = sum1 + qj * qk * s2 / var
+ }
+ }
+ Memr[ysum+iy] = sum1
+ }
+
+ do il = 1, order {
+ do ll = 1, il {
+ sum1 = 0.
+ ip = il + ll - 2
+ do iy = 1, ny
+ if (spec[iy] > 0.)
+ sum1 = sum1 +
+ Memr[ysum+iy] * ((real (iy) / ny)**ip)
+ index1 = nside * (order*jl+il-1) + order * kl + ll
+ Memr[work+index1] = sum1
+ if (ll != il) {
+ ip = ip1 * (ll - il)
+ index2 = index1 + ip
+ Memr[work+index2] = sum1
+ } else
+ index2 = index1
+ if (kl != jl) {
+ index3 = index2 + ip2 * (kl - jl)
+ Memr[work+index3] = sum1
+ if (ll != il)
+ Memr[work+index3-ip] = sum1
+ }
+ }
+ }
+ }
+ }
+
+ # Solve matrix equation AX = B for X. A is a real symmetric,
+ # positive definite matrix, dimension (order*npols)**2. X is
+ # the vector representing the coefficients fitted to the
+ # normalized profile. Coefficients are reordered for later speed.
+
+ call hfti (Memr[work+1], nside, nside, nside, Memr[work1+1], 1, 1,
+ 0.01, ip, p, Memr[work2+1], Memr[work3+1], Memi[work4+1])
+
+ do jl = 1, order {
+ do il = 1, npols {
+ index1 = order * (il - 1) + jl
+ index2 = npols * (jl - 1) + il
+ Memr[work+index2] = Memr[work1+index1]
+ }
+ }
+
+ # Evaluate fit and make profile positive only.
+ do iy = 1, ny {
+ ix1 = nint (x1[iy])
+ ix2 = nint (x2[iy])
+ xadd = x1[iy] - 1
+ s = 0.
+ do ix = 1, nx {
+ xj = real (ix) - xadd - 0.5
+ xk = real (ix) - xadd + 0.5
+ ip1 = int (xj / spix + 0.5)
+ ip2 = int (xk / spix + 1.5)
+ ip1 = max (1, min (ip1, npols))
+ ip2 = max (1, min (ip2, npols))
+ sum1 = 0.
+ do jl = 0, order-1 {
+ index1 = npols * jl
+ sum2 = 0.
+ do il = ip1, ip2 {
+ xz = xadd + spix * (real (il-1) + 0.5) - real (ix)
+ xt = abs (xz)
+ if (xt >= dx1) {
+ if (xt >= 0.5)
+ qj = ((xt - dx3) / dx4) ** 2
+ else
+ qj = 1. - ((xt - dx0) / dx4) ** 2
+ } else if (xt <= dx0)
+ qj = 1.
+ else
+ qj = dx2 - (xz / spix) ** 2
+ sum2 = sum2 + qj * Memr[work+index1+il]
+ }
+ sum1 = sum1 + sum2 * ((real (iy)/ ny) ** jl)
+ }
+ profile[iy,ix] = max (0.d0, sum1)
+ }
+ }
+
+ call sfree (sp)
+end
diff --git a/noao/twodspec/apextract/aprecenter.par b/noao/twodspec/apextract/aprecenter.par
new file mode 100644
index 00000000..a76b4c76
--- /dev/null
+++ b/noao/twodspec/apextract/aprecenter.par
@@ -0,0 +1,17 @@
+# APRECENTER
+
+input,s,a,,,,List of input images
+apertures,s,h,"",,,Apertures
+references,s,h,"",,,"Reference images
+"
+interactive,b,h,no,,,Run task interactively?
+find,b,h,yes,,,Find apertures?
+recenter,b,h,yes,,,Recenter apertures?
+resize,b,h,no,,,Resize apertures?
+edit,b,h,yes,,,"Edit apertures?
+"
+line,i,h,INDEF,1,,Dispersion line
+nsum,i,h,1,,,Number of dispersion lines to sum or median
+aprecenter,s,h,"",,,Apertures for recentering calculation
+npeaks,r,h,INDEF,0.,,Select brightest peaks
+shift,b,h,yes,,,Use average shift instead of recentering?
diff --git a/noao/twodspec/apextract/aprecenter.x b/noao/twodspec/apextract/aprecenter.x
new file mode 100644
index 00000000..fb3b9a86
--- /dev/null
+++ b/noao/twodspec/apextract/aprecenter.x
@@ -0,0 +1,166 @@
+include "apertures.h"
+
+define NRANGES 50
+
+# AP_RECENTER -- Recenter apertures.
+
+procedure ap_recenter (image, line, nsum, aps, naps, apedit)
+
+char image[SZ_FNAME] # Image name
+int line # Image dispersion line
+int nsum # Number of dispersion lines to sum
+pointer aps[ARB] # Aperture pointers
+int naps # Number of apertures
+int apedit # Called by apedit?
+
+pointer ranges # Apertures to select
+int npeaks # Number of bright peaks to select
+bool shift # Shift instead of center?
+
+real center, delta
+int i, j, k, na, npts, apaxis
+pointer sp, str, im, imdata, title, index, peaks, deltas
+
+int decode_ranges()
+real apgetr(), ap_center(), ap_cveval(), asokr()
+bool clgetb(), ap_answer(), apgetb(), is_in_range()
+errchk ap_getdata
+
+begin
+ # Check if apertures are defined.
+ na = 0
+ do i = 1, naps
+ if (AP_SELECT(aps[i]) == YES)
+ na = na + 1
+ if (na < 1)
+ return
+
+ # Query user.
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+ if (apedit == NO) {
+ call sprintf (Memc[str], SZ_LINE, "Recenter apertures for %s?")
+ call pargstr (image)
+ if (!ap_answer ("ansrecenter", Memc[str])) {
+ call sfree (sp)
+ return
+ }
+
+ if (clgetb ("verbose"))
+ call printf ("Recentering apertures ...\n")
+ }
+
+ # Get parameters
+ delta = apgetr ("npeaks")
+ shift = apgetb ("shift")
+ if (IS_INDEFR (delta))
+ npeaks = naps
+ else if (delta < 1.)
+ npeaks = max (1., delta * naps)
+ else
+ npeaks = delta
+
+ # Map the image and get the image data.
+ call ap_getdata (image, line, nsum, im, imdata, npts, apaxis, title)
+
+ if (npeaks == naps && !shift) {
+ na = 0
+ do i = 1, naps {
+ if (AP_SELECT(aps[i]) == NO)
+ next
+ center = AP_CEN(aps[i], apaxis) +
+ ap_cveval (AP_CV(aps[i]), real (line))
+ center = ap_center (center, Memr[imdata], npts)
+ if (!IS_INDEF(center)) {
+ AP_CEN(aps[i], apaxis) = center -
+ ap_cveval (AP_CV(aps[i]), real (line))
+ na = na + 1
+ }
+ }
+ } else {
+ call salloc (ranges, 3*NRANGES, TY_INT)
+ call salloc (index, naps, TY_REAL)
+ call salloc (peaks, naps, TY_REAL)
+ call salloc (deltas, naps, TY_REAL)
+
+ call apgstr ("aprecenter", Memc[str], SZ_LINE)
+ if (decode_ranges (Memc[str], Memi[ranges], NRANGES, i) == ERR)
+ call error (0, "Bad aperture list")
+
+ j = 0
+ do i = 1, naps {
+ if (!is_in_range (Memi[ranges], AP_ID(aps[i])))
+ next
+ center = AP_CEN(aps[i], apaxis) +
+ ap_cveval (AP_CV(aps[i]), real (line))
+ delta = ap_center (center, Memr[imdata], npts)
+ if (!IS_INDEF(delta)) {
+ k = max (1, min (npts, int (delta+0.5)))
+ Memr[index+j] = i
+ Memr[peaks+j] = -Memr[imdata+k-1]
+ Memr[deltas+j] = delta - center
+ j = j + 1
+ }
+ }
+
+ if (j > 0 && npeaks > 0) {
+ if (npeaks < j) {
+ call xt_sort3 (Memr[peaks], Memr[deltas], Memr[index], j)
+ j = npeaks
+ }
+
+ if (shift) {
+ if (mod (j, 2) == 0)
+ delta = (asokr (Memr[deltas], j, j/2) +
+ asokr (Memr[deltas], j, 1+j/2)) / 2
+ else
+ delta = asokr (Memr[deltas], j, 1+j/2)
+ na = 0
+ do i = 1, naps {
+ if (AP_SELECT(aps[i]) == NO)
+ next
+ center = AP_CEN(aps[i], apaxis) + delta
+ AP_CEN(aps[i], apaxis) = center
+ na = na + 1
+ }
+ } else {
+ na = 0
+ do k = 1, j {
+ delta = Memr[deltas+k-1]
+ i = Memr[index+k-1]
+ if (AP_SELECT(aps[i]) == NO)
+ next
+ center = AP_CEN(aps[i], apaxis) + delta
+ AP_CEN(aps[i], apaxis) = center
+ na = na + 1
+ }
+ }
+ }
+ }
+
+ # Log the operation, write the apertures to the database,
+ # unmap the image and free memory.
+ if (shift) {
+ call sprintf (Memc[str], SZ_LINE,
+ "RECENTER - %d apertures shifted by %.2f for %s.")
+ call pargi (na)
+ call pargr (delta)
+ call pargstr (image)
+ } else {
+ call sprintf (Memc[str], SZ_LINE,
+ "RECENTER - %d apertures recentered for %s")
+ call pargi (na)
+ call pargstr (image)
+ }
+ if (apedit == NO)
+ call ap_log (Memc[str], YES, YES, NO)
+ else
+ call ap_log (Memc[str], YES, NO, NO)
+
+ call appstr ("ansdbwrite1", "yes")
+
+ call mfree (imdata, TY_REAL)
+ call mfree (title, TY_CHAR)
+ call imunmap (im)
+ call sfree (sp)
+end
diff --git a/noao/twodspec/apextract/apresize.par b/noao/twodspec/apextract/apresize.par
new file mode 100644
index 00000000..4cbcf4b7
--- /dev/null
+++ b/noao/twodspec/apextract/apresize.par
@@ -0,0 +1,21 @@
+# APRESIZE
+
+input,s,a,,,,List of input images
+apertures,s,h,"",,,Apertures
+references,s,h,"",,,"Reference images
+"
+interactive,b,h,no,,,Run task interactively?
+find,b,h,yes,,,Find apertures?
+recenter,b,h,no,,,Recenter apertures?
+resize,b,h,yes,,,Resize apertures?
+edit,b,h,yes,,,"Edit apertures?
+"
+line,i,h,INDEF,1,,Dispersion line
+nsum,i,h,1,,,Number of dispersion lines to sum or median
+llimit,r,h,INDEF,,,Lower aperture limit relative to center
+ulimit,r,h,INDEF,,,Upper aperture limit relative to center
+ylevel,r,h,0.1,,,Fraction of peak or intensity for automatic width
+peak,b,h,yes,,,Is ylevel a fraction of the peak?
+bkg,b,h,yes,,,Subtract background in automatic width?
+r_grow,r,h,0.,,,"Grow limits by this factor"
+avglimits,b,h,no,,,Average limits over all apertures?
diff --git a/noao/twodspec/apextract/apresize.x b/noao/twodspec/apextract/apresize.x
new file mode 100644
index 00000000..8443223a
--- /dev/null
+++ b/noao/twodspec/apextract/apresize.x
@@ -0,0 +1,142 @@
+include "apertures.h"
+
+# AP_RESIZE -- Resize apertures.
+
+procedure ap_resize (image, line, nsum, aps, naps, apedit)
+
+char image[SZ_FNAME] # Image name
+int line # Image dispersion line
+int nsum # Number of dispersion lines to sum
+int apedit # Called from apedit?
+
+pointer aps[ARB] # Aperture pointers
+int naps # Number of apertures
+
+real llimit, ulimit # Maximum aperture limits
+real ylevel # Fraction of intensity for resize
+bool peak # Is ylevel a fraction of the peak?
+bool bkg # Subtract background?
+real grow # Expand limits by this factor
+bool avglimits # Average limits?
+
+real center, low, high
+int i, na, npts, apaxis
+pointer sp, str, im, imdata, title
+
+bool clgetb(), ap_answer(), apgetb()
+real apgetr(), ap_cveval()
+errchk ap_getdata
+
+begin
+ # Check if apertures are defined.
+ na = 0
+ do i = 1, naps
+ if (AP_SELECT(aps[i]) == YES)
+ na = na + 1
+ if (na == 0)
+ return
+
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+ if (apedit == NO) {
+ call sprintf (Memc[str], SZ_LINE, "Resize apertures for %s?")
+ call pargstr (image)
+ if (!ap_answer ("ansresize", Memc[str])) {
+ call sfree (sp)
+ return
+ }
+
+ if (clgetb ("verbose"))
+ call printf ("Resizing apertures ...\n")
+ }
+
+ # Map the image and get the image data.
+ call ap_getdata (image, line, nsum, im, imdata, npts, apaxis, title)
+
+ # Resize the apertures.
+ llimit = apgetr ("llimit")
+ ulimit = apgetr ("ulimit")
+ ylevel = apgetr ("ylevel")
+ bkg = apgetb ("bkg")
+ peak = apgetb ("peak")
+ grow = apgetr ("r_grow")
+ avglimits = apgetb ("avglimits")
+
+ if (IS_INDEF(llimit))
+ llimit = -npts
+ if (IS_INDEF(ulimit))
+ ulimit = npts
+
+ high = max (llimit, ulimit)
+ llimit = min (llimit, ulimit)
+ ulimit = high
+
+ if (IS_INDEF (ylevel)) {
+ do i = 1, naps {
+ if (AP_SELECT(aps[i]) == YES) {
+ AP_LOW(aps[i], apaxis) = llimit
+ AP_HIGH(aps[i], apaxis) = ulimit
+ }
+ }
+ avglimits = true
+ } else {
+ do i = 1, naps {
+ if (AP_SELECT(aps[i]) == YES) {
+ low = llimit
+ high = ulimit
+ center = AP_CEN(aps[i], apaxis) +
+ ap_cveval (AP_CV(aps[i]), real (line))
+ call ap_ylevel (Memr[imdata], npts, ylevel, peak, bkg, grow,
+ center, low, high)
+ AP_LOW(aps[i], apaxis) = min (low, high)
+ AP_HIGH(aps[i], apaxis) = max (low, high)
+ }
+ }
+
+ if (avglimits) {
+ low = 0.
+ high = 0.
+ do i = 1, naps {
+ if (AP_SELECT(aps[i]) == YES) {
+ low = low + AP_LOW(aps[i], apaxis)
+ high = high + AP_HIGH(aps[i], apaxis)
+ }
+ }
+ low = low / na
+ high = high / na
+ do i = 1, naps {
+ if (AP_SELECT(aps[i]) == YES) {
+ AP_LOW(aps[i], apaxis) = low
+ AP_HIGH(aps[i], apaxis) = high
+ }
+ }
+ }
+ }
+
+ # Log the operation, write the apertures to the database,
+ # unmap the image and free memory.
+ if (na == 1 || avglimits) {
+ call sprintf (Memc[str], SZ_LINE,
+ "APRESIZE - %d apertures resized for %s (%.2f, %.2f)")
+ call pargi (na)
+ call pargstr (image)
+ call pargr (AP_LOW(aps[1], apaxis))
+ call pargr (AP_HIGH(aps[1], apaxis))
+ } else {
+ call sprintf (Memc[str], SZ_LINE,
+ "RESIZE - %d apertures resized for %s")
+ call pargi (na)
+ call pargstr (image)
+ }
+ if (apedit == NO)
+ call ap_log (Memc[str], YES, YES, NO)
+ else
+ call ap_log (Memc[str], YES, NO, NO)
+
+ call appstr ("ansdbwrite1", "yes")
+
+ call mfree (imdata, TY_REAL)
+ call mfree (title, TY_CHAR)
+ call imunmap (im)
+ call sfree (sp)
+end
diff --git a/noao/twodspec/apextract/apscat1.par b/noao/twodspec/apextract/apscat1.par
new file mode 100644
index 00000000..8cb5cf7b
--- /dev/null
+++ b/noao/twodspec/apextract/apscat1.par
@@ -0,0 +1,11 @@
+# APSCAT1
+
+apertures,s,h,)apscatter.apertures,,,>apall.apertures
+function,s,h,"spline3","spline3|legendre|chebyshev|spline1",,Fitting function
+order,i,h,1,1,,Order of fitting function
+sample,s,h,"*",,,Sample points to use in fit
+naverage,i,h,1,,,Number of points in sample averaging
+low_reject,r,h,5.,0.,,Low rejection in sigma of fit
+high_reject,r,h,2.,0.,,High rejection in sigma of fit
+niterate,i,h,5,0,,Number of rejection iterations
+grow,r,h,0.,0.,,Rejection growing radius in pixels
diff --git a/noao/twodspec/apextract/apscat2.par b/noao/twodspec/apextract/apscat2.par
new file mode 100644
index 00000000..2463f110
--- /dev/null
+++ b/noao/twodspec/apextract/apscat2.par
@@ -0,0 +1,10 @@
+# APSCAT2
+
+function,s,h,"spline3","spline3|legendre|chebyshev|spline1",,Fitting function
+order,i,h,1,1,,Order of fitting function
+sample,s,h,"*",,,Sample points to use in fit
+naverage,i,h,1,,,Number of points in sample averaging
+low_reject,r,h,3.,0.,,Low rejection in sigma of fit
+high_reject,r,h,3.,0.,,High rejection in sigma of fit
+niterate,i,h,0,0,,Number of rejection iterations
+grow,r,h,0.,0.,,Rejection growing radius in pixels
diff --git a/noao/twodspec/apextract/apscatter.par b/noao/twodspec/apextract/apscatter.par
new file mode 100644
index 00000000..b7f45991
--- /dev/null
+++ b/noao/twodspec/apextract/apscatter.par
@@ -0,0 +1,25 @@
+# APSCATTER
+
+input,s,a,,,,List of input images to subtract scattered light
+output,s,a,,,,List of output corrected images
+apertures,s,h,"",,,Apertures
+scatter,s,h,"",,,List of scattered light images (optional)
+references,s,h,"",,,"List of aperture reference images
+"
+interactive,b,h,yes,,,Run task interactively?
+find,b,h,yes,,,Find apertures?
+recenter,b,h,yes,,,Recenter apertures?
+resize,b,h,yes,,,Resize apertures?
+edit,b,h,yes,,,Edit apertures?
+trace,b,h,yes,,,Trace apertures?
+fittrace,b,h,yes,,,Fit the traced points interactively?
+subtract,b,h,yes,,,Subtract scattered light?
+smooth,b,h,yes,,,Smooth scattered light along the dispersion?
+fitscatter,b,h,yes,,,Fit scattered light interactively?
+fitsmooth,b,h,yes,,,"Smooth the scattered light interactively?
+"
+line,i,h,INDEF,1,,Dispersion line
+nsum,i,h,10,,,Number of dispersion lines to sum or median
+buffer,r,h,1.,0.,,Buffer distance from apertures
+apscat1,pset,h,"",,,Fitting parameters across the dispersion
+apscat2,pset,h,"",,,Fitting parameters along the dispersion
diff --git a/noao/twodspec/apextract/apscatter.x b/noao/twodspec/apextract/apscatter.x
new file mode 100644
index 00000000..44f56a72
--- /dev/null
+++ b/noao/twodspec/apextract/apscatter.x
@@ -0,0 +1,662 @@
+include <error.h>
+include <imhdr.h>
+include <imset.h>
+include <pkg/gtools.h>
+include "apertures.h"
+
+define MAXBUF 500000 # Buffer size (number of reals) for col access
+
+
+# AP_SCATTER -- Fit and subtract the scattered light from between the apertures.
+#
+# Each line of the input image across the dispersion is read. The points to
+# be fit are selected from between the apertures (which includes a buffer
+# distance). The fitting is done using the ICFIT package. If not smoothing
+# along the dispersion write the scattered light subtracted output directly
+# thus minimizing I/O. If smoothing save the fits in memory. During the
+# smoothing process the fits are evaluated at each point along the dispersion
+# and then fit to the create the scattered light subtracted output image. A
+# scattered light image is only created after the output image by subtracting
+# the input from the output.
+
+procedure ap_scatter (input, output, scatter, aps, naps, line)
+
+char input[SZ_FNAME] # Input image
+char output[SZ_FNAME] # Output image
+char scatter[SZ_FNAME] # Scattered light image
+pointer aps[ARB] # Apertures
+int naps # Number of apertures
+int line # Line to be edited
+
+bool smooth
+int i, aaxis, daxis, npts, nlines, nscatter, nscatter1, new
+pointer sp, str, in, out, scat, cv, cvs, gp, indata, outdata, col, x, y, w
+pointer ic1, ic2, ic3, gt1, gt2
+data ic3/NULL/
+
+real clgetr()
+int clgeti(), ap_gline(), ap_gdata()
+bool clgetb(), ap_answer(), apgansb()
+pointer gt_init(), immap(), ap_immap(), imgl2r(), impl2r()
+
+common /aps_com/ ic1, ic2, gt1, gt2
+
+begin
+ if (naps < 1)
+ return
+
+ # Query the user.
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+ call sprintf (Memc[str], SZ_LINE, "Subtract scattered light in %s?")
+ call pargstr (input)
+ if (!ap_answer ("ansscat", Memc[str])) {
+ call sfree (sp)
+ return
+ }
+
+ call sprintf (Memc[str], SZ_LINE,
+ "Fit scattered light for %s interactively?")
+ call pargstr (input)
+ if (ap_answer ("ansfitscatter", Memc[str]))
+ ;
+
+ call sprintf (Memc[str], SZ_LINE, "Smooth the scattered light in %s?")
+ call pargstr (input)
+ if (ap_answer ("anssmooth", Memc[str])) {
+ call sprintf (Memc[str], SZ_LINE,
+ "Smooth the scattered light for %s interactively?")
+ call pargstr (input)
+ if (ap_answer ("ansfitsmooth", Memc[str]))
+ ;
+ }
+ smooth = apgansb ("anssmooth")
+
+ # Initialize the ICFIT pointers.
+ if (ic1 == NULL || ic3 == NULL) {
+ call ic_open (ic1)
+ call clgstr ("apscat1.function", Memc[str], SZ_LINE)
+ call ic_pstr (ic1, "function", Memc[str])
+ call ic_puti (ic1, "order", clgeti ("apscat1.order"))
+ call clgstr ("apscat1.sample", Memc[str], SZ_LINE)
+ call ic_pstr (ic1, "sample", Memc[str])
+ call ic_puti (ic1, "naverage", clgeti ("apscat1.naverage"))
+ call ic_puti (ic1, "niterate", clgeti ("apscat1.niterate"))
+ call ic_putr (ic1, "low", clgetr ("apscat1.low_reject"))
+ call ic_putr (ic1, "high", clgetr ("apscat1.high_reject"))
+ call ic_putr (ic1, "grow", clgetr ("apscat1.grow"))
+ call ic_pstr (ic1, "ylabel", "")
+ gt1 = gt_init()
+ call gt_sets (gt1, GTTYPE, "line")
+
+ call ic_open (ic2)
+ call clgstr ("apscat2.function", Memc[str], SZ_LINE)
+ call ic_pstr (ic2, "function", Memc[str])
+ call ic_puti (ic2, "order", clgeti ("apscat2.order"))
+ call clgstr ("apscat2.sample", Memc[str], SZ_LINE)
+ call ic_pstr (ic2, "sample", Memc[str])
+ call ic_puti (ic2, "naverage", clgeti ("apscat2.naverage"))
+ call ic_puti (ic2, "niterate", clgeti ("apscat2.niterate"))
+ call ic_putr (ic2, "low", clgetr ("apscat2.low_reject"))
+ call ic_putr (ic2, "high", clgetr ("apscat2.high_reject"))
+ call ic_putr (ic2, "grow", clgetr ("apscat2.grow"))
+ call ic_pstr (ic2, "ylabel", "")
+ gt2 = gt_init()
+ call gt_sets (gt2, GTTYPE, "line")
+
+ ic3 = ic1
+ }
+
+ # Map the input and output images. Warn and return on an error.
+ iferr (in = ap_immap (input, aaxis, daxis)) {
+ call sfree (sp)
+ call erract (EA_WARN)
+ return
+ }
+ iferr (out = immap (output, NEW_COPY, in)) {
+ call imunmap (in)
+ call sfree (sp)
+ call erract (EA_WARN)
+ return
+ }
+ if (IM_PIXTYPE(out) != TY_DOUBLE)
+ IM_PIXTYPE(out) = TY_REAL
+
+ # Allocate memory for curve fitting.
+ call ap_sort (i, aps, naps, 1)
+ npts = IM_LEN (in, aaxis)
+ nlines = IM_LEN (in, daxis)
+ call salloc (col, npts, TY_REAL)
+ call salloc (x, npts, TY_REAL)
+ call salloc (y, npts, TY_REAL)
+ call salloc (w, npts, TY_REAL)
+
+ do i = 1, npts
+ Memr[col+i-1] = i
+ call ic_putr (ic1, "xmin", Memr[col])
+ call ic_putr (ic1, "xmax", Memr[col+npts-1])
+
+ # If the interactive flag is set then use icg_fit to set the
+ # fitting parameters. AP_GLINE returns EOF when the user
+ # is done.
+
+ if (apgansb ("ansfitscatter")) {
+ call ap_gopen (gp)
+
+ if (IS_INDEFI (line))
+ i = nlines / 2
+ else
+ i = line
+ indata = NULL
+ while (ap_gline (ic1, gt1, NULL, in, aaxis, aaxis, i, indata) !=
+ EOF) {
+ call ap_gscatter1 (aps, naps, i, Memr[indata], npts,
+ Memr[x], Memr[y], Memr[w], nscatter)
+ call icg_fit (ic1, gp, "gcur", gt1, cv, Memr[x], Memr[y],
+ Memr[w], nscatter)
+ }
+ call cvfree (cv)
+ }
+
+ # Loop through the input image and create an output image.
+ # To minimize I/O if not smoothing write the final image
+ # directly otherwise save the fit. AP_SMOOTH will then
+ # smooth along the dispersion and compute the scattered
+ # light subtracted image.
+
+ if (clgetb ("verbose")) {
+ call printf (
+ "Fitting the scattered light across the dispersion ...\n")
+ call flush (STDOUT)
+ }
+
+ if (!smooth) {
+ nscatter = 0
+ i = 0
+ while (ap_gdata (in, out, NULL, aaxis, MAXBUF, i,
+ indata, outdata) != EOF) {
+ call ap_gscatter1 (aps, naps, i, Memr[indata], npts, Memr[x],
+ Memr[y], Memr[w], nscatter1)
+ if (nscatter != nscatter1)
+ new = YES
+ else
+ new = NO
+ nscatter = nscatter1
+ call ic_fit (ic1, cv, Memr[x], Memr[y], Memr[w], nscatter,
+ new, YES, new, new)
+ call cvvector (cv, Memr[col], Memr[outdata], npts)
+ call asubr (Memr[indata], Memr[outdata], Memr[outdata], npts)
+ }
+ call cvfree (cv)
+ } else {
+ call salloc (cvs, nlines, TY_POINTER)
+ call amovki (NULL, Memi[cvs], nlines)
+
+ new = YES
+ i = 0
+ while (ap_gdata (in, NULL, NULL, aaxis, MAXBUF, i,
+ indata, outdata) != EOF) {
+ call ap_gscatter1 (aps, naps, i, Memr[indata], npts, Memr[x],
+ Memr[y], Memr[w], nscatter)
+ call ic_fit (ic1, Memi[cvs+i-1], Memr[x], Memr[y], Memr[w],
+ nscatter, new, YES, new, new)
+ }
+
+ # Smooth and subtract along the dispersion.
+ call ap_smooth (in, out, aaxis, daxis, aps, naps, ic2, gt2, cvs)
+ do i = 1, nlines
+ call cvfree (Memi[cvs+i-1])
+ }
+
+ call imastr (out, "apscatter", "Scattered light subtracted")
+ call imunmap (out)
+ call imunmap (in)
+
+ # If a scattered light image is desired compute it from the difference
+ # of the input and output images.
+
+ if (scatter[1] != EOS) {
+ in = immap (input, READ_ONLY, 0)
+ out = immap (output, READ_ONLY, 0)
+ ifnoerr (scat = immap (scatter, NEW_COPY, in)) {
+ if (IM_PIXTYPE(scat) != TY_DOUBLE)
+ IM_PIXTYPE(scat) = TY_REAL
+ npts = IM_LEN(in,1)
+ nlines = IM_LEN(in,2)
+ do i = 1, nlines
+ call asubr (Memr[imgl2r(in,i)], Memr[imgl2r(out,i)],
+ Memr[impl2r(scat,i)], npts)
+ call imunmap (scat)
+ } else
+ call erract (EA_WARN)
+ call imunmap (in)
+ call imunmap (out)
+ }
+
+ # Make a log.
+ call sprintf (Memc[str], SZ_LINE,
+ "SCATTER - Scattered light subtracted from %s")
+ call pargstr (input)
+ call ap_log (Memc[str], YES, YES, NO)
+
+ call sfree (sp)
+end
+
+
+# SCAT_FREE -- Free scattered light memory.
+
+procedure scat_free ()
+
+pointer ic1, ic2, gt1, gt2
+pointer sp, str
+
+int ic_geti()
+real ic_getr()
+
+common /aps_com/ ic1, ic2, gt1, gt2
+
+begin
+ if (ic1 != NULL) {
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ call ic_gstr (ic1, "function", Memc[str], SZ_LINE)
+ call clpstr ("apscat1.function", Memc[str])
+ call ic_gstr (ic1, "sample", Memc[str], SZ_LINE)
+ call clpstr ("apscat1.sample", Memc[str])
+ call clputi ("apscat1.order", ic_geti (ic1, "order"))
+ call clputi ("apscat1.naverage", ic_geti (ic1, "naverage"))
+ call clputi ("apscat1.niterate", ic_geti (ic1, "niterate"))
+ call clputr ("apscat1.low", ic_getr (ic1, "low"))
+ call clputr ("apscat1.high", ic_getr (ic1, "high"))
+ call clputr ("apscat1.grow", ic_getr (ic1, "grow"))
+
+ call ic_gstr (ic2, "function", Memc[str], SZ_LINE)
+ call clpstr ("apscat2.function", Memc[str])
+ call ic_gstr (ic2, "sample", Memc[str], SZ_LINE)
+ call clpstr ("apscat2.sample", Memc[str])
+ call clputi ("apscat2.order", ic_geti (ic2, "order"))
+ call clputi ("apscat2.naverage", ic_geti (ic2, "naverage"))
+ call clputi ("apscat2.niterate", ic_geti (ic2, "niterate"))
+ call clputr ("apscat2.low", ic_getr (ic2, "low"))
+ call clputr ("apscat2.high", ic_getr (ic2, "high"))
+ call clputr ("apscat2.grow", ic_getr (ic2, "grow"))
+
+ call ic_closer (ic1)
+ call gt_free (gt1)
+ call ic_closer (ic2)
+ call gt_free (gt2)
+ call sfree (sp)
+ }
+end
+
+
+# AP_SMOOTH -- Smooth the scattered light by fitting one dimensional functions.
+#
+# The output image consists of smooth one dimensional fits across the
+# dispersion. This routine reads each line along the dispersion and fits
+# a function to smooth the fits made across the dispersion. The output
+# image is used both as input of the cross dispersion fits and as output
+# of the scattered light subtracted image.
+
+procedure ap_smooth (in, out, aaxis, daxis, aps, naps, ic, gt, cvs)
+
+pointer in # Input IMIO pointer
+pointer out # Output IMIO pointer
+int aaxis, daxis # Aperture and dispersion axes
+pointer aps[ARB] # Apertures
+int naps # Number of apertures
+pointer ic # ICFIT pointer
+pointer gt # GTOOLS pointer
+pointer cvs # CURFIT pointers
+
+int i, npts, nlines, new
+pointer cv, gp, indata, outdata, x, w
+
+int ap_gline(), ap_gdata()
+bool clgetb(), apgansb()
+
+begin
+ if (!apgansb ("anssmooth"))
+ return
+
+ # Allocate memory for curve fitting.
+ npts = IM_LEN (in, daxis)
+ nlines = IM_LEN (in, aaxis)
+ call salloc (x, npts, TY_REAL)
+ call salloc (w, npts, TY_REAL)
+
+ do i = 1, npts
+ Memr[x+i-1] = i
+ call amovkr (1., Memr[w], npts)
+ call ic_putr (ic, "xmin", Memr[x])
+ call ic_putr (ic, "xmax", Memr[x+npts-1])
+
+ # If the interactive flag is set then use icg_fit to set the
+ # fitting parameters. AP_GLINE returns EOF when the user
+ # is done.
+
+ if (apgansb ("ansfitsmooth")) {
+ call ap_gopen (gp)
+
+ i = nlines / 2
+ outdata = NULL
+ while (ap_gline (ic, gt, cvs, out, daxis, aaxis, i, outdata) !=
+ EOF) {
+ call icg_fit (ic, gp, "gcur", gt, cv, Memr[x],
+ Memr[outdata], Memr[w], npts)
+ call amovkr (1., Memr[w], npts)
+ }
+ call mfree (outdata, TY_REAL)
+ }
+
+ # Loop through the input image and create an output image.
+ if (clgetb ("verbose")) {
+ call printf ("Smoothing scattered light along the dispersion ...\n")
+ call flush (STDOUT)
+ }
+
+ # Use the new flag to optimize the fitting.
+ new = YES
+ i = 0
+ while (ap_gdata (in, out, cvs, daxis, MAXBUF, i,
+ indata, outdata) != EOF) {
+ call ic_fit (ic, cv, Memr[x], Memr[outdata], Memr[w], npts,
+ new, YES, new, new)
+ call cvvector (cv, Memr[x], Memr[outdata], npts)
+ call asubr (Memr[indata], Memr[outdata], Memr[outdata], npts)
+ new = NO
+ }
+ call cvfree (cv)
+end
+
+
+# AP_GSCATTER -- Get scattered light pixels.
+#
+# The pixels outside the apertures extended by the specified buffer
+# distance are selected. The x and weight arrays are also set.
+# The apertures must be sorted by position.
+
+procedure ap_gscatter1 (aps, naps, line, data, npts, x, y, w, nscatter)
+
+pointer aps[naps] # Apertures
+int naps # Number of apertures
+int line # Line
+real data[npts] # Image data
+int npts # Number of points
+real x[npts] # Scattered light positions
+real y[npts] # Image data
+real w[npts] # Weights
+int nscatter # Number of scattered light pixels
+
+real buf # Aperture buffer
+
+int i, j, axis
+int low, high
+real center, ap_cveval(), clgetr()
+
+begin
+ buf = clgetr ("buffer") + 0.5
+ call aclrr (x, npts)
+
+ axis = AP_AXIS(aps[1])
+ do i = 1, naps {
+ center = AP_CEN(aps[i],axis) + ap_cveval (AP_CV(aps[i]), real(line))
+ low = max (1, int (center + AP_LOW(aps[i],axis) - buf))
+ high = min (npts, int (center + AP_HIGH(aps[i],axis) + buf))
+ do j = low, high
+ x[j] = 1
+ }
+
+ nscatter = 0
+ do i = 1, npts {
+ if (x[i] == 0.) {
+ nscatter = nscatter + 1
+ x[nscatter] = i
+ y[nscatter] = data[i]
+ w[nscatter] = 1.
+ }
+ }
+end
+
+
+# AP_GDATA -- Get the next line of image data. Return EOF at end.
+# This task optimizes column access if needed. It assumes sequential access.
+
+int procedure ap_gdata (in, out, cvs, axis, maxbuf, index, indata, outdata)
+
+pointer in # Input IMIO pointer
+pointer out # Output IMIO pointer (NULL if no output)
+pointer cvs # CURFIT pointers
+int axis # Image axis
+int maxbuf # Maximum buffer size chars for column axis
+int index # Last line (input), current line (returned)
+pointer indata # Input data pointer
+pointer outdata # Output data pointer
+
+real val, ap_cveval()
+int i, last_index, col1, col2, nc, nd, ncols, nlines, ncols_block
+pointer inbuf, outbuf, ptr, imgl2r(), impl2r(), imgs2r(), imps2r()
+
+begin
+ # Increment to the next image vector.
+ index = index + 1
+
+ # Initialize for the first vector.
+ if (index == 1) {
+ ncols = IM_LEN (in, 1)
+ if (IM_NDIM (in) == 1)
+ nlines = 1
+ else
+ nlines = IM_LEN (in, 2)
+
+ switch (axis) {
+ case 1:
+ nd = ncols
+ last_index = nlines
+ case 2:
+ nd = nlines
+ last_index = ncols
+ ncols_block =
+ max (1, min (ncols, maxbuf / nlines))
+ col2 = 0
+
+ call malloc (indata, nlines, TY_REAL)
+ if (out != NULL)
+ call malloc (outdata, nlines, TY_REAL)
+ }
+ }
+
+ # Finish up if the last vector has been done.
+ if (index > last_index) {
+ if (axis == 2) {
+ call mfree (indata, TY_REAL)
+ if (out != NULL) {
+ ptr = outbuf + index - 1 - col1
+ do i = 1, nlines {
+ Memr[ptr] = Memr[outdata+i-1]
+ ptr = ptr + nc
+ }
+ call mfree (outdata, TY_REAL)
+ }
+ }
+ index = 0
+ return (EOF)
+ }
+
+ # Get the next image vector.
+ switch (axis) {
+ case 1:
+ indata = imgl2r (in, index)
+ if (out != NULL)
+ outdata = impl2r (out, index)
+ case 2:
+ if (out != NULL)
+ if (index > 1) {
+ ptr = outbuf + index - 1 - col1
+ do i = 1, nlines {
+ Memr[ptr] = Memr[outdata+i-1]
+ ptr = ptr + nc
+ }
+ }
+
+ if (index > col2) {
+ col1 = col2 + 1
+ col2 = min (ncols, col1 + ncols_block - 1)
+ nc = col2 - col1 + 1
+ inbuf = imgs2r (in, col1, col2, 1, nlines)
+ if (out != NULL)
+ outbuf = imps2r (out, col1, col2, 1, nlines)
+ }
+
+ ptr = inbuf + index - col1
+ do i = 1, nlines {
+ Memr[indata+i-1] = Memr[ptr]
+ ptr = ptr + nc
+ }
+ }
+ if (cvs != NULL) {
+ val = index
+ do i = 1, nd
+ Memr[outdata+i-1] = ap_cveval (Memi[cvs+i-1], val)
+ }
+
+ return (index)
+end
+
+
+define CMDS "|quit|line|column|buffer|"
+define QUIT 1 # Quit
+define LINE 2 # Line to examine
+define COLUMN 3 # Column to examine
+define BUFFER 4 # Buffer distance
+
+# AP_GLINE -- Get image data to be fit interactively. Return EOF
+# when the user enters EOF or CR. The out of bounds
+# requests are silently limited to the nearest edge.
+
+int procedure ap_gline (ic, gt, cvs, im, axis, aaxis, line, data)
+
+pointer ic # ICFIT pointer
+pointer gt # GTOOLS pointer
+pointer cvs # CURFIT pointers
+pointer im # IMIO pointer
+int axis # Image axis
+int aaxis # Aperture axis
+int line # Line to get
+pointer data # Image data
+
+real rval, clgetr(), ap_cveval()
+int i, stat, cmd, ival, strdic(), scan(), nscan()
+pointer sp, name, str, imgl2r(), imgs2r()
+
+begin
+ call smark (sp)
+ call salloc (name, SZ_FNAME, TY_CHAR)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ stat = OK
+ if (data != NULL) {
+ cmd = 0
+ repeat {
+ switch (cmd) {
+ case QUIT:
+ stat = EOF
+ break
+ case LINE:
+ call gargi (ival)
+ if (axis == 2 || nscan() == 1) {
+ call printf ("line %d - ")
+ call pargi (line)
+ } else {
+ line = max (1, min (IM_LEN(im,2), ival))
+ break
+ }
+ case COLUMN:
+ call gargi (ival)
+ if (axis == 1 || nscan() == 1) {
+ call printf ("column %d - ")
+ call pargi (line)
+ } else {
+ line = max (1, min (IM_LEN(im,1), ival))
+ break
+ }
+ case BUFFER:
+ if (axis == aaxis) {
+ call gargr (rval)
+ if (nscan() == 1) {
+ call printf ("buffer %g - ")
+ call pargr (clgetr ("buffer"))
+ } else {
+ call clputr ("buffer", rval)
+ break
+ }
+ }
+ }
+
+ if (axis == aaxis) {
+ if (axis == 1)
+ call printf (
+ "Command (quit, buffer <value>, line <value>): ")
+ else
+ call printf (
+ "Command (quit, buffer <value>, column <value>): ")
+ } else {
+ if (axis == 1)
+ call printf (
+ "Command (quit, line <value>): ")
+ else
+ call printf (
+ "Command (quit, column <value>): ")
+ }
+ call flush (STDOUT)
+ stat = scan ()
+ if (stat == EOF)
+ break
+ call gargwrd (Memc[str], SZ_LINE)
+ cmd = strdic (Memc[str], Memc[str], SZ_LINE, CMDS)
+ }
+
+ }
+
+ if (stat != EOF) {
+ call imstats (im, IM_IMAGENAME, Memc[name], SZ_FNAME)
+ switch (axis) {
+ case 1:
+ call sprintf (Memc[str], SZ_LINE, "%s: Fit line %d\n%s")
+ call pargstr (Memc[name])
+ call pargi (line)
+ call pargstr (IM_TITLE(im))
+ call gt_sets (gt, GTTITLE, Memc[str])
+ call ic_pstr (ic, "xlabel", "Column")
+ if (axis == aaxis)
+ data = imgl2r (im, line)
+ else {
+ if (data == NULL)
+ call malloc (data, IM_LEN(im,1), TY_REAL)
+ rval = line
+ do i = 1, IM_LEN(im,1)
+ Memr[data+i-1] = ap_cveval (Memi[cvs+i-1], rval)
+ }
+ case 2:
+ call sprintf (Memc[str], SZ_LINE, "%s: Fit column %d\n%s")
+ call pargstr (Memc[name])
+ call pargi (line)
+ call pargstr (IM_TITLE(im))
+ call gt_sets (gt, GTTITLE, Memc[str])
+ call ic_pstr (ic, "xlabel", "Line")
+ if (axis == aaxis)
+ data = imgs2r (im, line, line, 1, IM_LEN(im,2))
+ else {
+ if (data == NULL)
+ call malloc (data, IM_LEN(im,2), TY_REAL)
+ rval = line
+ do i = 1, IM_LEN(im,2)
+ Memr[data+i-1] = ap_cveval (Memi[cvs+i-1], rval)
+ }
+ }
+ }
+
+ call sfree (sp)
+ return (stat)
+end
diff --git a/noao/twodspec/apextract/apselect.x b/noao/twodspec/apextract/apselect.x
new file mode 100644
index 00000000..47730f47
--- /dev/null
+++ b/noao/twodspec/apextract/apselect.x
@@ -0,0 +1,40 @@
+include "apertures.h"
+
+define NRANGES 100
+
+
+# AP_SELECT -- Select apertures.
+# The AP_SELECT field of the aperture structure is set.
+
+procedure ap_select (apertures, aps, naps)
+
+char apertures[ARB] #I Aperture selection string
+pointer aps[ARB] #U Aperture pointers
+int naps #I Number of apertures
+
+pointer sp, ranges
+int i, decode_ranges()
+bool is_in_range()
+
+begin
+ # Check if apertures are defined.
+ if (naps < 1)
+ return
+
+ call smark (sp)
+ call salloc (ranges, 3*NRANGES, TY_INT)
+
+ # Decode aperture string.
+ if (decode_ranges (apertures, Memi[ranges], NRANGES, i) == ERR)
+ call error (0, "Bad aperture list")
+
+ # Select apertures.
+ do i = 1, naps {
+ if (is_in_range (Memi[ranges], AP_ID(aps[i])))
+ AP_SELECT(aps[i]) = YES
+ else
+ AP_SELECT(aps[i]) = NO
+ }
+
+ call sfree (sp)
+end
diff --git a/noao/twodspec/apextract/apshow.x b/noao/twodspec/apextract/apshow.x
new file mode 100644
index 00000000..16f4d504
--- /dev/null
+++ b/noao/twodspec/apextract/apshow.x
@@ -0,0 +1,46 @@
+include "apertures.h"
+
+# AP_SHOW -- List the apertures to a text file.
+
+procedure ap_show (file, aps, naps)
+
+char file[ARB] # Aperture file
+pointer aps[ARB] # Aperture pointers
+int naps # Number of apertures
+
+pointer ap
+int i, apaxis, fd, open()
+errchk open
+
+begin
+ if (naps == 0)
+ return
+
+ # Open the output file. Return if an error occurs.
+ fd = open (file, APPEND, TEXT_FILE)
+
+ call fprintf (fd, "# APERTURES\n\n%4s %4s %7s %7s %7s %s\n")
+ call pargstr ("##ID")
+ call pargstr ("BEAM")
+ call pargstr ("CENTER")
+ call pargstr ("LOW")
+ call pargstr ("HIGH")
+ call pargstr ("TITLE")
+ for (i = 1; i <= naps; i = i + 1) {
+ ap = aps[i]
+ apaxis = AP_AXIS(ap)
+ call fprintf (fd, "%4d %4d %7.2f %7.2f %7.2f")
+ call pargi (AP_ID(ap))
+ call pargi (AP_BEAM(ap))
+ call pargr (AP_CEN(ap, apaxis))
+ call pargr (AP_LOW(ap, apaxis))
+ call pargr (AP_HIGH(ap, apaxis))
+ if (AP_TITLE(ap) != NULL) {
+ call fprintf (fd, " %s")
+ call pargstr (Memc[AP_TITLE(ap)])
+ }
+ call fprintf (fd, "\n")
+ }
+
+ call close (fd)
+end
diff --git a/noao/twodspec/apextract/apskyeval.x b/noao/twodspec/apextract/apskyeval.x
new file mode 100644
index 00000000..05f47f14
--- /dev/null
+++ b/noao/twodspec/apextract/apskyeval.x
@@ -0,0 +1,368 @@
+include <math/iminterp.h>
+include <mach.h>
+include "apertures.h"
+
+# Background fitting types
+define BACKGROUND "|none|average|median|minimum|fit|"
+define B_NONE 1
+define B_AVERAGE 2
+define B_MEDIAN 3
+define B_MINIMUM 4
+define B_FIT 5
+
+define NSAMPLE 20 # Maximum number of background sample regions
+
+
+# AP_SKYEVAL -- Evaluate sky within aperture.
+#
+# The sky pixels specified by the background sample string are used to
+# determine a sky function at each line which is then evaluated for each
+# pixel in the aperture as given by the SBUF array with starting offsets
+# given by XS. The fitting consists of either a straight average or a
+# function fit using ICFIT. The sky regions are specified relative to the
+# aperture center. To avoid systematics due to shifting of the aperture
+# relative to the integer pixel positions the sky regions are linearly
+# interpolated. The average uses the integral of the interpolation
+# function within the sample region endpoints. The fit samples the
+# interpolation on a pixel grid with the aperture exactly centered on
+# a pixel. A crude sky variance is computed for each line based solely
+# on the variance model and the square root of the number of "pixels"
+# used for the fit. This variance is used to boost the variance of
+# the sky subtracted spectrum during variance weighting. Because sky
+# noise may be significant in short slits a box car smoothing may be
+# used giving a lower variance per pixel but bad errors near sky lines.
+# An unweighted aperture sum of the sky is returned in case the user
+# wants to save the subtracted 1D sky spectrum.
+
+procedure ap_skyeval (im, ap, dbuf, nc, nl, c1, l1, sbuf, svar, sky, nx, ny,
+ xs, ys, nsubaps, rdnoise)
+
+pointer im # IMIO pointer
+pointer ap # Aperture structure
+pointer dbuf # Data buffer
+int nc, nl # Size of data buffer
+int c1, l1 # Origin of data buffer
+real sbuf[nx,ny] # Sky values
+real svar[ny] # Sky variances
+real sky[ny,nsubaps] # Extracted sky (out)
+int nx, ny # Size of profile array
+int xs[ny], ys # Origin of profile array
+int nsubaps # Number of subapertures
+real rdnoise # Readout noise in RMS data numbers.
+
+int bkg # Background type
+int skybox # Sky box car smoothing
+
+int i, j, ix1, ix2, nsample, nsky, nfit, ix, iy
+real center, xmin, xmax, a, b, c, s, avg
+pointer ic, cv, cv1, asi, sp, str, data, as, bs, x, y, w
+
+int apgwrd(), apgeti(), ctor()
+real ic_getr(), ap_cveval(), asieval(), asigrl(), amedr()
+errchk salloc, ic_fit
+
+begin
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ # Get CL parameters and set shift and fitting function pointers.
+ bkg = apgwrd ("background", Memc[str], SZ_LINE, BACKGROUND)
+ skybox = apgeti ("skybox")
+
+ cv = AP_CV(ap)
+ ic = AP_IC(ap)
+
+ # Set center and maximum limits relative to data buffer.
+ # The limits are required to overlap the aperture and include
+ # an extra point at each end for interpolation. Shifts
+ # and boundary limits will be enforced later.
+
+ i = AP_AXIS(ap)
+ center = AP_CEN(ap,i)
+ xmin = center + min (AP_LOW(ap,i), ic_getr (ic, "xmin"))
+ xmax = center + max (AP_HIGH(ap,i), ic_getr (ic, "xmax"))
+ ix1 = nint (xmin) - 1
+ ix2 = nint (xmax) + 1
+ nfit = ix2 - ix1 + 1
+
+ # Allocate memory and parse sample string.
+ # The colons in the sample string must be changed to avoid
+ # sexigesimal interpretation.
+
+ call salloc (as, NSAMPLE, TY_REAL)
+ call salloc (bs, NSAMPLE, TY_REAL)
+
+ call ic_gstr (ic, "sample", Memc[str], SZ_LINE)
+ for (i=str; Memc[i]!=EOS; i=i+1)
+ if (Memc[i] == ':')
+ Memc[i] = '$'
+
+ nsample = 0
+ for (i=1; Memc[str+i-1]!=EOS; i=i+1) {
+ if (ctor (Memc[str], i, a) > 0) {
+ i = i - 1
+ if (Memc[str+i] == '$') {
+ i = i + 2
+ if (ctor (Memc[str], i, b) > 0) {
+ i = i - 1
+ Memr[as+nsample] = center + min (a, b)
+ Memr[bs+nsample] = center + max (a, b)
+ nsample = nsample + 1
+ if (nsample == NSAMPLE)
+ break
+ }
+ }
+ }
+ }
+
+ if (nsample == 0) {
+ Memr[as] = xmin
+ Memr[bs] = xmax
+ nsample = 1
+ }
+
+ if (bkg == B_MEDIAN)
+ call salloc (y, nfit, TY_REAL)
+ else if (bkg == B_FIT) {
+ call salloc (x, nfit, TY_REAL)
+ call salloc (y, nfit, TY_REAL)
+ call salloc (w, nfit, TY_REAL)
+ }
+
+ # Initialize the image interpolator.
+ call asiinit (asi, II_LINEAR)
+
+ # Determine sky at each dispersion point.
+ call aclrr (svar, ny)
+ do iy = 1, ny {
+
+ # Fit image interpolation function including extra points
+ # and apply image boundary limits.
+
+ i = iy + ys - 1
+ s = ap_cveval (cv, real (i))
+ ix1 = max (c1, nint (xmin + s) - 1)
+ ix2 = min (c1+nc-1, nint (xmax + s) + 1)
+ nfit = ix2 - ix1 + 1
+ if (nfit < 3) {
+ call aclrr (sbuf[1,iy], nx)
+ svar[iy] = 0.
+ next
+ }
+ data = dbuf + (i - l1) * nc + ix1 - c1
+ if (bkg == B_AVERAGE || bkg == B_FIT) {
+ iferr (call asifit (asi, Memr[data], nfit)) {
+ call aclrr (sbuf[1,iy], nx)
+ svar[iy] = 0.
+ next
+ }
+ }
+
+ # Determine background
+ switch (bkg) {
+ case B_AVERAGE:
+ # The background is computed by integrating the interpolator
+ avg = 0.
+ nsky = 0
+ c = 0.
+ for (i=0; i < nsample; i=i+1) {
+ a = max (real (ix1), Memr[as+i] + s) - ix1 + 1
+ b = min (real (ix2), Memr[bs+i] + s) - ix1 + 1
+ if (b - a > 0.) {
+ avg = avg + asigrl (asi, a, b)
+ c = c + b - a
+ nsky = nsky + nint (b) - nint(a) + 1
+ }
+ }
+ if (c > 0.)
+ avg = avg / c
+ call amovkr (avg, sbuf[1,iy], nx)
+ if (nsky > 1)
+ svar[iy] = max (0., (rdnoise + avg) / (nsky - 1))
+ case B_MEDIAN:
+ # The background is computed by the median pixel
+ avg = 0.
+ nsky = 0
+ for (i=0; i < nsample; i=i+1) {
+ a = max (real (ix1), Memr[as+i] + s) - ix1 + 1
+ b = min (real (ix2), Memr[bs+i] + s) - ix1 + 1
+ do j = nint (a), nint (b) {
+ Memr[y+nsky] = Memr[data+j-1]
+ nsky = nsky + 1
+ }
+ }
+ if (nsky > 0)
+ avg = amedr (Memr[y], nsky)
+ call amovkr (avg, sbuf[1,iy], nx)
+ if (nsky > 1)
+ svar[iy] = max (0., (rdnoise + avg) / (nsky - 1))
+ case B_MINIMUM:
+ # The background is computed by the minimum pixel
+ avg = MAX_REAL
+ nsky = 0
+ for (i=0; i < nsample; i=i+1) {
+ a = max (real (ix1), Memr[as+i] + s) - ix1 + 1
+ b = min (real (ix2), Memr[bs+i] + s) - ix1 + 1
+ do j = nint (a), nint (b) {
+ avg = min (avg, Memr[data+j-1])
+ nsky = nsky + 1
+ }
+ }
+ if (nsky == 0)
+ avg = 0
+ call amovkr (avg, sbuf[1,iy], nx)
+ if (nsky > 1)
+ svar[iy] = max (0., (rdnoise + avg) / (nsky - 1))
+ case B_FIT:
+ # The fitting is done in a coordinate system relative to
+ # aperture center.
+
+ c = center + s
+ a = ix1 + c - int (c)
+ do i = 1, nfit-1 {
+ Memr[x+i-1] = nint (1000. * (a - c)) / 1000.
+ Memr[y+i-1] = asieval (asi, a-ix1+1)
+ Memr[w+i-1] = 1.
+ a = a + 1.
+ }
+
+ iferr {
+ call ic_fit (ic, cv1, Memr[x], Memr[y], Memr[w], nfit-1,
+ YES, YES, YES, YES)
+
+ avg = 0.
+ do i = 1, nx {
+ a = xs[iy] + i - 1
+ b = ap_cveval (cv1, a - c)
+ avg = avg + b
+ sbuf[i,iy] = b
+ }
+ avg = avg / nx
+ } then {
+ avg = 0.
+ call aclrr (sbuf[1,iy], nx)
+ }
+
+ nsky = 0.
+ for (i=0; i < nsample; i=i+1) {
+ a = max (real (ix1), Memr[as+i] + s) - ix1 + 1
+ b = min (real (ix2), Memr[bs+i] + s) - ix1 + 1
+ nsky = nsky + nint (b) - nint (a) + 1
+ }
+ if (nsky > 1)
+ svar[iy] = max (0., (rdnoise + avg) / (nsky - 1))
+ }
+ }
+
+ # Do box car smoothing if desired.
+ if (skybox > 1) {
+ ix2 = skybox ** 2
+ avg = 0.
+ a = 0.
+ iy = 1
+ for (i=1; i<=skybox; i=i+1) {
+ avg = avg + sbuf[1,i]
+ a = a + svar[i]
+ }
+ for (; i<=ny; i=i+1) {
+ b = sbuf[1,iy]
+ c = svar[iy]
+ sbuf[1,iy] = avg / skybox
+ svar[iy] = a / ix2
+ avg = avg + sbuf[1,i] - b
+ a = a + svar[i] - c
+ iy = iy + 1
+ }
+ sbuf[1,iy] = avg / skybox
+ svar[iy] = a / ix2
+ i = ny - skybox + 1
+ for (iy=ny; iy > ny-skybox/2; iy=iy-1)
+ svar[iy] = svar[i]
+ for (; i > 1; i=i-1) {
+ svar[iy] = svar[i]
+ iy = iy - 1
+ }
+ for (; iy > 1; iy=iy-1)
+ svar[iy] = svar[1]
+
+ switch (bkg) {
+ case B_AVERAGE, B_MEDIAN, B_MINIMUM:
+ i = ny - skybox + 1
+ for (iy=ny; iy > ny-skybox/2; iy=iy-1)
+ call amovkr (sbuf[1,i], sbuf[1,iy], nx)
+ for (; i > 1; i=i-1) {
+ call amovkr (sbuf[1,i], sbuf[1,iy], nx)
+ iy = iy - 1
+ }
+ for (; iy > 1; iy=iy-1)
+ call amovkr (sbuf[1,1], sbuf[1,iy], nx)
+ case B_FIT:
+ i = ny - skybox + 1
+ for (iy=ny; iy > ny-skybox/2; iy=iy-1)
+ sbuf[1,iy] = sbuf[1,i]
+ for (; i > 1; i=i-1) {
+ sbuf[1,iy] = sbuf[1,i]
+ iy = iy - 1
+ }
+ for (; iy > 1; iy=iy-1)
+ sbuf[1,iy] = sbuf[1,1]
+ do ix1 = 2, nx {
+ avg = 0.
+ iy = 1
+ for (i=1; i<=skybox; i=i+1)
+ avg = avg + sbuf[ix1,i]
+ for (; i<=ny; i=i+1) {
+ b = sbuf[ix1,iy]
+ sbuf[ix1,iy] = avg / skybox
+ avg = avg + sbuf[ix1,i] - b
+ iy = iy + 1
+ }
+ sbuf[ix1,iy] = avg / skybox
+ i = ny - skybox + 1
+ for (iy=ny; iy > ny-skybox/2; iy=iy-1)
+ sbuf[ix1,iy] = sbuf[ix1,i]
+ for (; i > 1; i=i-1) {
+ sbuf[ix1,iy] = sbuf[ix1,i]
+ iy = iy - 1
+ }
+ for (; iy > 1; iy=iy-1)
+ sbuf[ix1,iy] = sbuf[ix1,1]
+ }
+ }
+ }
+
+ # Compute the unweighted aperture sky spectrum.
+ i = AP_AXIS(ap)
+ a = AP_CEN(ap,i) + AP_LOW(ap,i)
+ b = AP_CEN(ap,i) + AP_HIGH(ap,i)
+ c = (b - a) / nsubaps
+
+ do iy = 1, ny {
+ data = dbuf + (iy + ys - 1 - l1) * nc + xs[iy] - c1 - 1
+ s = ap_cveval (cv, real (iy + ys - 1)) - c1 + 1
+ do i = 1, nsubaps {
+ xmin = max (0.5, a + (i - 1) * c + s) + c1 - xs[iy]
+ xmax = min (nc + 0.49, a + i * c + s) + c1 - xs[iy]
+ if (xmin >= xmax) {
+ sky[iy,i] = 0.
+ next
+ }
+ ix1 = nint (xmin)
+ ix2 = nint (xmax)
+
+ if (ix1 == ix2)
+ sky[iy,i] = (xmax - xmin) * sbuf[ix1,iy]
+ else {
+ sky[iy,i] = (ix1 - xmin + 0.5) * sbuf[ix1,iy]
+ sky[iy,i] = sky[iy,i] + (xmax - ix2 + 0.5) * sbuf[ix2,iy]
+ }
+ do ix = ix1+1, ix2-1
+ sky[iy,i] = sky[iy,i] + sbuf[ix,iy]
+ }
+ }
+
+ if (bkg == B_FIT)
+ call cvfree (cv1)
+ call asifree (asi)
+ call sfree (sp)
+end
diff --git a/noao/twodspec/apextract/apsort.x b/noao/twodspec/apextract/apsort.x
new file mode 100644
index 00000000..85b21cc5
--- /dev/null
+++ b/noao/twodspec/apextract/apsort.x
@@ -0,0 +1,55 @@
+include "apertures.h"
+
+# Sort flags:
+define INC 1 # Sort by aperture position in increasing order
+define DEC 2 # Sort by position in decreasing order
+
+# AP_SORT -- Sort the apertures.
+
+procedure ap_sort (current, aps, naps, flag)
+
+int current # Current aperture
+pointer aps[ARB] # Aperture data
+int naps # Number of apertures
+int flag # Sort flag
+
+int i, j, apaxis
+pointer ap
+
+begin
+ if (naps < 1)
+ return
+
+ switch (flag) {
+ case INC:
+ apaxis = AP_AXIS (aps[1])
+ for (i = 1; i <= naps - 1; i = i + 1) {
+ for (j = i + 1; j <= naps; j = j + 1) {
+ if (AP_CEN(aps[i], apaxis) > AP_CEN(aps[j], apaxis)) {
+ ap = aps[i]
+ aps[i] = aps[j]
+ aps[j] = ap
+ if (current == i)
+ current = j
+ else if (current == j)
+ current = i
+ }
+ }
+ }
+ case DEC:
+ apaxis = AP_AXIS (aps[1])
+ for (i = 1; i <= naps - 1; i = i + 1) {
+ for (j = i + 1; j <= naps; j = j + 1) {
+ if (AP_CEN(aps[i], apaxis) < AP_CEN(aps[j], apaxis)) {
+ ap = aps[i]
+ aps[i] = aps[j]
+ aps[j] = ap
+ if (current == i)
+ current = j
+ else if (current == j)
+ current = i
+ }
+ }
+ }
+ }
+end
diff --git a/noao/twodspec/apextract/apsum.par b/noao/twodspec/apextract/apsum.par
new file mode 100644
index 00000000..b5b58013
--- /dev/null
+++ b/noao/twodspec/apextract/apsum.par
@@ -0,0 +1,34 @@
+# APSUM
+
+input,s,a,,,,List of input images
+output,s,h,"",,,List of output spectra
+apertures,s,h,"",,,Apertures
+format,s,h,"multispec","onedspec|multispec|echelle|strip",,Extracted spectra format
+references,s,h,"",,,List of aperture reference images
+profiles,s,h,"",,,"List of aperture profile images
+"
+interactive,b,h,yes,,,Run task interactively?
+find,b,h,yes,,,Find apertures?
+recenter,b,h,no,,,Recenter apertures?
+resize,b,h,no,,,Resize apertures?
+edit,b,h,yes,,,Edit apertures?
+trace,b,h,yes,,,Trace apertures?
+fittrace,b,h,yes,,,Fit the traced points interactively?
+extract,b,h,yes,,,Extract apertures?
+extras,b,h,no,,,"Extract sky, sigma, etc.?"
+review,b,h,yes,,,"Review extractions?
+"
+line,i,h,INDEF,1,,Dispersion line
+nsum,i,h,10,,,"Number of dispersion lines to sum or median
+"
+background,s,h,"none",,,Background to subtract (none|average|fit)
+weights,s,h,"none","none|variance",,Extraction weights (none|variance)
+pfit,s,h,"fit1d","fit1d|fit2d",,Profile fitting type (fit1d|fit2d)
+clean,b,h,no,,,Detect and replace bad pixels?
+skybox,i,h,1,1,,Box car smoothing length for sky
+saturation,r,h,INDEF,,,Saturation level
+readnoise,s,h,"0.",,,Read out noise sigma (photons)
+gain,s,h,"1.",,,Photon gain (photons/data number)
+lsigma,r,h,4.,0.,,Lower rejection threshold
+usigma,r,h,4.,0.,,Upper rejection threshold
+nsubaps,i,h,1,1,,Number of subapertures per aperture
diff --git a/noao/twodspec/apextract/aptrace.par b/noao/twodspec/apextract/aptrace.par
new file mode 100644
index 00000000..9134a012
--- /dev/null
+++ b/noao/twodspec/apextract/aptrace.par
@@ -0,0 +1,27 @@
+# APTRACE
+
+input,s,a,,,,List of input images to trace
+apertures,s,h,"",,,Apertures
+references,s,h,"",,,List of reference images
+
+interactive,b,h,yes,,,Run task interactively?
+find,b,h,yes,,,Find apertures?
+recenter,b,h,no,,,Recenter apertures?
+resize,b,h,no,,,Resize apertures?
+edit,b,h,no,,,Edit apertures?
+trace,b,h,yes,,,Trace apertures?
+fittrace,b,h,yes,,,"Fit the traced points interactively?
+"
+line,i,h,INDEF,1,,Starting dispersion line
+nsum,i,h,10,,,Number of dispersion lines to sum
+step,i,h,10,1,,Tracing step
+nlost,i,h,3,1,,"Number of consecutive times profile is lost before quitting
+"
+function,s,h,"legendre","chebyshev|legendre|spline1|spline3",,Trace fitting function
+order,i,h,2,1,,Trace fitting function order
+sample,s,h,"*",,,Trace sample regions
+naverage,i,h,1,,,Trace average or median
+niterate,i,h,0,0,,Trace rejection iterations
+low_reject,r,h,3.,0.,,Trace lower rejection sigma
+high_reject,r,h,3.,0.,,Trace upper rejection sigma
+grow,r,h,0.,0.,,Trace rejection growing radius
diff --git a/noao/twodspec/apextract/aptrace.x b/noao/twodspec/apextract/aptrace.x
new file mode 100644
index 00000000..c38af01c
--- /dev/null
+++ b/noao/twodspec/apextract/aptrace.x
@@ -0,0 +1,669 @@
+include <imhdr.h>
+include <math/curfit.h>
+include <pkg/center1d.h>
+include <pkg/gtools.h>
+include "apertures.h"
+
+define MAXBUF 100000 # Column buffer size
+
+
+# AP_TRACE -- Trace features in a two dimensional image.
+#
+# Given an image pointer, the starting dispersion position, and a set
+# of apertures defining the centers of features, trace the feature
+# centers to other dispersion positions and fit a curve to the positions.
+# The user specifies the dispersion step size, the number of dispersion
+# lines to sum, and parameters for the feature centering function
+# fitting.
+
+procedure ap_trace (image, line, aps, naps, apedit)
+
+char image[SZ_FNAME] # Image name
+int line # Starting dispersion position
+pointer aps[ARB] # Apertures
+int naps # Number of apertures
+int apedit # Called from APEDIT?
+
+int step # Tracing step
+int nsum # Number of dispersion lines to sum
+int nlost # Number of steps lost before quitting
+real cradius # Centering radius
+real cwidth # Centering width
+real cthreshold # Detection threshold for centering
+
+int i, na, dispaxis, apaxis
+real center
+pointer im, ic, ic1, sp, str
+data ic1 /NULL/
+
+int apgeti()
+real apgetr()
+bool clgetb(), ap_answer()
+pointer ap_immap()
+
+errchk ap_immap, ic_open, ap_ltrace, ap_ctrace, ap_default
+
+common /apt_com/ ic
+
+begin
+ na = 0
+ do i = 1, naps
+ if (AP_SELECT(aps[i]) == YES)
+ na = na + 1
+ if (naps > 0 && na == 0)
+ return
+
+ # Query user.
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+ if (apedit == NO) {
+ call sprintf (Memc[str], SZ_LINE, "Trace apertures for %s?")
+ call pargstr (image)
+ if (!ap_answer ("anstrace", Memc[str])) {
+ call sfree (sp)
+ return
+ }
+
+ call sprintf (Memc[str], SZ_LINE,
+ "Fit traced positions for %s interactively?")
+ call pargstr (image)
+ if (ap_answer ("ansfittrace", Memc[str])) {
+ call apgstr ("ansfittrace", Memc[str], SZ_LINE)
+ call appstr ("ansfittrace1", Memc[str])
+ } else
+ call appstr ("ansfittrace1", "NO")
+
+ if (clgetb ("verbose"))
+ call printf ("Tracing apertures ...\n")
+ }
+
+ # Tracing parameters
+ step = apgeti ("t_step")
+ nsum = max (1, abs (apgeti ("t_nsum")))
+ nlost = apgeti ("t_nlost")
+ if (ic == NULL || ic1 == NULL) {
+ call ic_open (ic)
+ ic1 = ic
+ call apgstr ("t_function", Memc[str], SZ_LINE)
+ call ic_pstr (ic, "function", Memc[str])
+ call ic_puti (ic, "order", apgeti ("t_order"))
+ call apgstr ("t_sample", Memc[str], SZ_LINE)
+ call ic_pstr (ic, "sample", Memc[str])
+ call ic_puti (ic, "naverage", apgeti ("t_naverage"))
+ call ic_puti (ic, "niterate", apgeti ("t_niterate"))
+ call ic_putr (ic, "low", apgetr ("t_low_reject"))
+ call ic_putr (ic, "high", apgetr ("t_high_reject"))
+ call ic_putr (ic, "grow", apgetr ("t_grow"))
+ }
+
+ im = ap_immap (image, apaxis, dispaxis)
+
+ # If no apertures are defined default to the center of the image.
+ if (naps == 0) {
+ naps = 1
+ center = IM_LEN (im, apaxis) / 2.
+ call ap_default (im, 1, 1, apaxis, center, real (line),
+ aps[naps])
+ call sprintf (Memc[str], SZ_LINE,
+ "TRACE - Default aperture defined centered on %s")
+ call pargstr (image)
+ call ap_log (Memc[str], YES, NO, YES)
+ }
+
+ # Centering parameters
+ cwidth = apgetr ("t_width")
+ cradius = apgetr ("radius")
+ cthreshold = apgetr ("threshold")
+
+ switch (dispaxis) {
+ case 1:
+ call ap_ctrace (image, im, ic, line, step, nsum, nlost, cradius,
+ cwidth, cthreshold, aps, naps)
+ case 2:
+ call ap_ltrace (image, im, ic, line, step, nsum, nlost, cradius,
+ cwidth, cthreshold, aps, naps)
+ }
+
+ # Log the tracing and write the traced apertures to the database.
+
+ call sprintf (Memc[str], SZ_LINE,
+ "TRACE - %d apertures traced in %s.")
+ call pargi (na)
+ call pargstr (image)
+ if (apedit == NO)
+ call ap_log (Memc[str], YES, YES, NO)
+ else
+ call ap_log (Memc[str], YES, NO, NO)
+
+ call appstr ("ansdbwrite1", "yes")
+
+ call imunmap (im)
+ call sfree (sp)
+end
+
+
+procedure ap_trfree ()
+
+pointer ic
+common /apt_com/ ic
+
+begin
+ call ic_closer (ic)
+end
+
+
+# AP_CTRACE -- Trace feature positions for aperture axis 2.
+
+procedure ap_ctrace (image, im, ic, start, step, nsum, nlost, cradius, cwidth,
+ threshold, aps, naps)
+
+char image[ARB] # Image to be traced.
+pointer im # IMIO pointer
+pointer ic # ICFIT pointer
+int start # Starting column
+int step # Tracing step size
+int nsum # Number of lines or columns to sum
+int nlost # Number of steps lost before quiting
+real cradius # Centering radius
+real cwidth # Centering width
+real threshold # Detection threshold for centering
+pointer aps[ARB] # Apertures
+int naps # Number of apertures
+
+int nlines, col, col1, col2, line1, line2
+int i, j, n, nx, ny, ntrace, istart, lost, fd
+real yc, yc1
+pointer co, data, sp, str, x, y, wts, gp, gt
+
+real center1d(), ap_cveval()
+bool ap_answer()
+pointer comap(), gt_init()
+
+errchk ap_cveval, xt_csum, xt_csumb, center1d, icg_fit, ic_fit
+errchk ap_gopen, ap_popen
+
+begin
+ # Set up column access buffering.
+
+ co = comap (im, MAXBUF)
+
+ # Determine the number of lines to be traced and allocate memory.
+
+ nx = IM_LEN(im, 1)
+ ny = IM_LEN(im, 2)
+ if (IS_INDEFI (start))
+ start = nx / 2
+ nlines = 5 * cwidth
+ istart = (start - 1) / step + 1
+ ntrace = istart + (nx - start) / step
+
+ # Allocate memory for the traced positions and the weights for fitting.
+
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+ call salloc (x, ntrace, TY_REAL)
+ call salloc (y, ntrace, TY_REAL)
+ call salloc (wts, ntrace, TY_REAL)
+ call aclrr (Memr[y], ntrace)
+ data = NULL
+
+ # Initialize the ICFIT limits and the GTOOLS parameters.
+ # Set initial interactive flag.
+
+ call ic_putr (ic, "xmin", 1.)
+ call ic_putr (ic, "xmax", real (nx))
+ call ic_pstr (ic, "xlabel", "Column")
+ call ic_pstr (ic, "ylabel", "Line")
+
+ gt = gt_init()
+ call gt_setr (gt, GTXMIN, 1. - step / 2)
+ call gt_setr (gt, GTXMAX, real (nx + step / 2))
+
+ # Trace each feature.
+
+ line1 = 0
+ line2 = 0
+ do j = 1, naps {
+ if (AP_SELECT(aps[j]) == NO)
+ next
+
+ # Trace from the starting column to the last column while the
+ # position is not INDEF.
+
+ lost = 0
+ yc = AP_CEN(aps[j], 2) + ap_cveval (AP_CV(aps[j]), real (start))
+ do i = istart, ntrace {
+ Memr[y+i-1] = INDEF
+ if (lost < nlost) {
+ # Update the scrolling buffer if the feature center is less
+ # than cwidth from the edge of the buffer.
+ if (((yc-line1) < cwidth) || ((line2-yc) < cwidth)) {
+ line1 = max (1, int (yc + .5 - nlines / 2))
+ line2 = min (ny, line1 + nlines - 1)
+ line1 = max (1, line2 - nlines + 1)
+ }
+
+ # Sum columns to form the 1D vector for centering.
+
+ col = start + (i - istart) * step
+ col1 = max (1, col - nsum / 2)
+ col2 = min (nx, col1 + nsum - 1)
+ col1 = max (1, col2 - nsum + 1)
+
+ # If columns in the sum overlap then use buffering.
+
+ if (step < nsum)
+ call xt_csumb (co, col1, col2, line1, line2, data)
+ else
+ call xt_csum (co, col1, col2, line1, line2, data)
+
+ # Center the feature for the new column using the previous
+ # center as the starting point. Convert to position
+ # relative to the start of the data buffer for centering
+ # and then convert back to position relative to the
+ # edge of the image.
+
+ yc1 = center1d (yc-line1+1, Memr[data], line2-line1+1,
+ cwidth, EMISSION, cradius, threshold)
+
+ if (!IS_INDEF (yc1)) {
+ lost = 0
+ yc = yc1 + line1 - 1
+ Memr[y+i-1] = yc
+ if (IS_INDEF (Memr[y+i-2])) {
+ call sprintf (Memc[str], SZ_LINE,
+ "TRACE - Trace of aperture %d in %s recovered at column %d.")
+ call pargi (AP_ID(aps[j]))
+ call pargstr (image)
+ call pargi (col)
+ call ap_log (Memc[str], YES, NO, YES)
+ }
+ } else {
+ lost = lost + 1
+ call sprintf (Memc[str], SZ_LINE,
+ "TRACE - Trace of aperture %d in %s lost at column %d.")
+ call pargi (AP_ID(aps[j]))
+ call pargstr (image)
+ call pargi (col)
+ call ap_log (Memc[str], YES, NO, YES)
+ }
+ }
+ }
+
+ # Trace from the starting column to the first column while the
+ # position is not INDEF.
+
+ lost = 0
+ yc = AP_CEN(aps[j], 2) + ap_cveval (AP_CV(aps[j]), real (start))
+ do i = istart - 1, 1, -1 {
+ Memr[y+i-1] = INDEF
+ if (lost < nlost) {
+ # Update the scrolling buffer if the feature center is less
+ # than cwidth from the edge of the buffer.
+
+ if (((yc-line1) < cwidth) || ((line2-yc) < cwidth)) {
+ line1 = max (1, int (yc + .5 - nlines / 2))
+ line2 = min (ny, line1 + nlines - 1)
+ line1 = max (1, line2 - nlines + 1)
+ }
+
+ # Sum columns to form the 1D vector for centering.
+
+ col = start + (i - istart) * step
+ col1 = max (1, col - nsum / 2)
+ col2 = min (nx, col1 + nsum - 1)
+ col1 = max (1, col2 - nsum + 1)
+
+ # If columns in the sum overlap then use buffering.
+
+ if (step < nsum)
+ call xt_csumb (co, col1, col2, line1, line2, data)
+ else
+ call xt_csum (co, col1, col2, line1, line2, data)
+
+ # Center the feature for the new column using the previous
+ # center as the starting point. Convert to position
+ # relative to the start of the data buffer for centering
+ # and then convert back to position relative to the
+ # edge of the image.
+
+ yc1 = center1d (yc-line1+1, Memr[data], line2-line1+1,
+ cwidth, EMISSION, cradius, threshold)
+
+ if (!IS_INDEF (yc1)) {
+ lost = 0
+ yc = yc1 + line1 - 1
+ Memr[y+i-1] = yc
+ if (IS_INDEF (Memr[y+i])) {
+ call sprintf (Memc[str], SZ_LINE,
+ "TRACE - Trace of aperture %d in %s recovered at column %d.")
+ call pargi (AP_ID(aps[j]))
+ call pargstr (image)
+ call pargi ((i - 1) * step + 1)
+ call ap_log (Memc[str], YES, NO, YES)
+ }
+ } else {
+ lost = lost + 1
+ call sprintf (Memc[str], SZ_LINE,
+ "TRACE - Trace of aperture %d in %s lost at column %d.")
+ call pargi (AP_ID(aps[j]))
+ call pargstr (image)
+ call pargi ((i - 1) * step + 1)
+ call ap_log (Memc[str], YES, NO, YES)
+ }
+ }
+ }
+
+ # Order the traced points and exclude INDEF positions.
+
+ n = 0
+ do i = 1, ntrace {
+ if (IS_INDEF (Memr[y+i-1]))
+ next
+ n = n + 1
+ Memr[x+n-1] = start + (i - istart) * step
+ Memr[y+n-1] = Memr[y+i-1]
+ Memr[wts+n-1] = 1.
+ }
+
+ # If all positions are INDEF print a message and go on to the next
+ # aperture.
+
+ if (n < 2) {
+ call eprintf (
+ "Not enough points traced for aperture %d of %s\n")
+ call pargi (AP_ID(aps[j]))
+ call pargstr (image)
+ next
+ }
+
+ # Fit a curve to the traced positions and graph the result.
+
+ call sprintf (Memc[str], SZ_LINE, "Aperture %d of %s")
+ call pargi (AP_ID(aps[j]))
+ call pargstr (image)
+ call gt_sets (gt, GTTITLE, Memc[str])
+
+ call sprintf (Memc[str], SZ_LINE,
+ "Fit curve to aperture %d of %s interactively")
+ call pargi (AP_ID(aps[j]))
+ call pargstr (image)
+ if (ap_answer ("ansfittrace1", Memc[str])) {
+ call ap_gopen (gp)
+ call icg_fit (ic, gp, "gcur", gt,
+ AP_CV(aps[j]), Memr[x], Memr[y], Memr[wts], n)
+ } else
+ call ic_fit (ic, AP_CV(aps[j]), Memr[x], Memr[y], Memr[wts], n,
+ YES, YES, YES, YES)
+
+ call ap_popen (gp, fd, "trace")
+ if (gp != NULL) {
+ call icg_graphr (ic, gp, gt, AP_CV(aps[j]),
+ Memr[x], Memr[y], Memr[wts], n)
+ call ap_pclose (gp, fd)
+ }
+
+ call asubkr (Memr[y], AP_CEN(aps[j], 2), Memr[y], n)
+ call ic_fit (ic, AP_CV(aps[j]), Memr[x], Memr[y], Memr[wts], n,
+ YES, YES, YES, YES)
+ }
+
+ # Free allocated memory.
+
+ call gt_free (gt)
+ call mfree (data, TY_REAL)
+ call counmap (co)
+ call sfree (sp)
+end
+
+
+# AP_LTRACE -- Trace feature positions for aperture axis 1.
+
+procedure ap_ltrace (image, im, ic, start, step, nsum, nlost, cradius, cwidth,
+ threshold, aps, naps)
+
+char image[ARB] # Image to be traced
+pointer im # IMIO pointer
+pointer ic # ICFIT pointer
+int start # Starting line
+int step # Tracing step size
+int nsum # Number of lines or columns to sum
+int nlost # Number of steps lost before quiting
+real cradius # Centering radius
+real cwidth # Centering width
+real threshold # Detection threshold for centering
+pointer aps[ARB] # Apertures
+int naps # Number of apertures
+
+real xc1
+int i, j, n, nx, ny, ntrace, istart, line, line1, line2, fd
+pointer data, sp, str, x, y, wts, xc, lost, x1, x2, gp, gt
+
+real center1d(), ap_cveval()
+bool ap_answer()
+pointer gt_init()
+
+errchk ap_cveval, xt_lsum, xt_lsumb, center1d, icg_fit, ic_fit
+errchk ap_gopen, ap_popen
+
+begin
+ # Determine the number of lines to be traced and allocate memory.
+
+ nx = IM_LEN(im, 1)
+ ny = IM_LEN(im, 2)
+ if (IS_INDEFI (start))
+ start = ny / 2
+
+ istart = (start - 1) / step + 1
+ ntrace = istart + (ny - start) / step
+
+ # Allocate memory for the traced positions and the weights for fitting.
+
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+ call salloc (x, ntrace * naps, TY_REAL)
+ call salloc (y, ntrace, TY_REAL)
+ call salloc (wts, ntrace, TY_REAL)
+ call salloc (xc, naps, TY_REAL)
+ call salloc (lost, naps, TY_INT)
+ call aclrr ( Memr[x], ntrace * naps)
+ data = NULL
+
+ # Set the dispersion lines to be traced.
+
+ do i = 1, ntrace
+ Memr[y+i-1] = start + (i - istart) * step
+
+ # Trace from the starting line to the last line.
+
+ x1 = x + istart - 1
+ do i = 1, naps {
+ if (AP_SELECT(aps[i]) == NO)
+ next
+ Memr[xc+i-1] = AP_CEN(aps[i], 1) +
+ ap_cveval (AP_CV(aps[i]), real (start))
+ Memi[lost+i-1] = 0
+ }
+
+ do i = istart, ntrace {
+ line = Memr[y+i-1]
+ line1 = max (1, line - nsum / 2)
+ line2 = min (ny, line1 + nsum - 1)
+ line1 = max (1, line2 - nsum + 1)
+
+ # If the sums overlap use buffering.
+
+ if (step < nsum)
+ call xt_lsumb (im, 1, nx, line1, line2, data)
+ else
+ call xt_lsum (im, 1, nx, line1, line2, data)
+
+ do j = 1, naps {
+ if (AP_SELECT(aps[j]) == NO)
+ next
+ x2 = x1 + (j - 1) * ntrace
+ Memr[x2] = INDEF
+ if (Memi[lost+j-1] < nlost) {
+ xc1 = center1d (Memr[xc+j-1], Memr[data], nx,
+ cwidth, EMISSION, cradius, threshold)
+ if (IS_INDEF(xc1)) {
+ Memi[lost+j-1] = Memi[lost+j-1] + 1
+ call sprintf (Memc[str], SZ_LINE,
+ "TRACE - Trace of aperture %d in %s lost at line %d.")
+ call pargi (AP_ID(aps[j]))
+ call pargstr (image)
+ call pargi (line)
+ call ap_log (Memc[str], YES, NO, YES)
+ } else {
+ Memi[lost+j-1] = 0
+ Memr[xc+j-1] = xc1
+ Memr[x2] = xc1
+ if (IS_INDEF (Memr[x2-1])) {
+ call sprintf (Memc[str], SZ_LINE,
+ "TRACE - Trace of aperture %d in %s recovered at line %d.")
+ call pargi (AP_ID(aps[j]))
+ call pargstr (image)
+ call pargi (line)
+ call ap_log (Memc[str], YES, NO, YES)
+ }
+ }
+ }
+ }
+ x1 = x1 + 1
+ }
+
+ # Trace from the starting line to the first line.
+
+ x1 = x + istart - 2
+ do i = 1, naps {
+ if (AP_SELECT(aps[i]) == NO)
+ next
+ Memr[xc+i-1] = AP_CEN(aps[i], 1) +
+ ap_cveval (AP_CV(aps[i]), real (start))
+ Memi[lost+i-1] = 0
+ }
+
+ do i = istart - 1, 1, -1 {
+ line = Memr[y+i-1]
+ line1 = max (1, line - nsum / 2)
+ line2 = min (ny, line1 + nsum - 1)
+ line1 = max (1, line2 - nsum + 1)
+
+ # If the sums overlap use buffering.
+
+ if (step < nsum)
+ call xt_lsumb (im, 1, nx, line1, line2, data)
+ else
+ call xt_lsum (im, 1, nx, line1, line2, data)
+
+ do j = 1, naps {
+ if (AP_SELECT(aps[j]) == NO)
+ next
+ x2 = x1 + (j - 1) * ntrace
+ Memr[x2] = INDEF
+ if (Memi[lost+j-1] < nlost) {
+ xc1 = center1d (Memr[xc+j-1], Memr[data], nx,
+ cwidth, EMISSION, cradius, threshold)
+ if (IS_INDEF(xc1)) {
+ Memi[lost+j-1] = Memi[lost+j-1] + 1
+ call sprintf (Memc[str], SZ_LINE,
+ "TRACE - Trace of aperture %d in %s lost at line %d.")
+ call pargi (AP_ID(aps[j]))
+ call pargstr (image)
+ call pargi (line)
+ call ap_log (Memc[str], YES, NO, YES)
+ } else {
+ Memi[lost+j-1] = 0
+ Memr[xc+j-1] = xc1
+ Memr[x2] = xc1
+ if (IS_INDEF (Memr[x2+1])) {
+ call sprintf (Memc[str], SZ_LINE,
+ "TRACE - Trace of aperture %d in %s recovered at line %d.")
+ call pargi (AP_ID(aps[j]))
+ call pargstr (image)
+ call pargi (line)
+ call ap_log (Memc[str], YES, NO, YES)
+ }
+ }
+ }
+ }
+ x1 = x1 - 1
+ }
+
+ # Initialize the the GTOOLS parameters.
+ call ic_putr (ic, "xmin", 1.)
+ call ic_putr (ic, "xmax", real (ny))
+ call ic_pstr (ic, "xlabel", "Line")
+ call ic_pstr (ic, "ylabel", "Column")
+
+ gt = gt_init()
+ call gt_setr (gt, GTXMIN, 1. - step / 2)
+ call gt_setr (gt, GTXMAX, real (ny + step / 2))
+
+ do j = 1, naps {
+ if (AP_SELECT(aps[j]) == NO)
+ next
+
+ # Order the traced points and exclude INDEF positions.
+
+ x1 = x + (j - 1) * ntrace
+ n = 0
+
+ do i = 1, ntrace {
+ if (IS_INDEF (Memr[x1+i-1]))
+ next
+ n = n + 1
+ Memr[x1+n-1] = Memr[x1+i-1]
+ Memr[y+n-1] = start + (i - istart) * step
+ Memr[wts+n-1] = 1.
+ }
+
+ # If all positions are INDEF print a message and go on to the next
+ # aperture.
+
+ if (n < 2) {
+ call eprintf (
+ "Not enough points traced for aperture %d of %s\n")
+ call pargi (AP_ID(aps[j]))
+ call pargstr (image)
+ next
+ }
+
+ # Fit a curve to the traced positions and graph the result.
+
+ call sprintf (Memc[str], SZ_LINE, "Aperture %d of %s")
+ call pargi (AP_ID(aps[j]))
+ call pargstr (image)
+ call gt_sets (gt, GTTITLE, Memc[str])
+
+ call sprintf (Memc[str], SZ_LINE,
+ "Fit curve to aperture %d of %s interactively")
+ call pargi (AP_ID(aps[j]))
+ call pargstr (image)
+ if (ap_answer ("ansfittrace1", Memc[str])) {
+ call ap_gopen (gp)
+ call icg_fit (ic, gp, "gcur", gt,
+ AP_CV(aps[j]), Memr[y], Memr[x1], Memr[wts], n)
+ } else
+ call ic_fit (ic, AP_CV(aps[j]), Memr[y], Memr[x1], Memr[wts], n,
+ YES, YES, YES, YES)
+
+ call ap_popen (gp, fd, "trace")
+ if (gp != NULL) {
+ call icg_graphr (ic, gp, gt, AP_CV(aps[j]),
+ Memr[y], Memr[x1], Memr[wts], n)
+ call ap_pclose (gp, fd)
+ }
+
+ # Subtract the aperture center and refit offset curve.
+ call asubkr (Memr[x1], AP_CEN(aps[j], 1), Memr[x1], n)
+ call ic_fit (ic, AP_CV(aps[j]), Memr[y], Memr[x1], Memr[wts], n,
+ YES, YES, YES, YES)
+ }
+
+ # Free allocated memory.
+
+ call gt_free (gt)
+ call mfree (data, TY_REAL)
+ call sfree (sp)
+end
diff --git a/noao/twodspec/apextract/apupdate.x b/noao/twodspec/apextract/apupdate.x
new file mode 100644
index 00000000..d3344b5f
--- /dev/null
+++ b/noao/twodspec/apextract/apupdate.x
@@ -0,0 +1,44 @@
+include <gset.h>
+include "apertures.h"
+
+# AP_UPDATE -- Update an aperture.
+
+procedure ap_update (gp, ap, line, apid, apbeam, center, low, high)
+
+pointer gp # GIO pointer
+pointer ap # Aperture pointer
+int line # Dispersion line
+int apid # New aperture ID
+int apbeam # New aperture beam
+real center # New center at dispersion line
+real low # New lower limit
+real high # New upper limit
+
+real ap_cveval(), ic_getr()
+
+begin
+ # Check for bad values.
+ if (IS_INDEFR(center) || IS_INDEFR(low) || IS_INDEFR(high))
+ call error (1, "INDEF not allowed")
+
+ # Erase the current aperture.
+ call gseti (gp, G_PLTYPE, 0)
+ call ap_gmark (gp, line, ap, 1)
+
+ # Update the aperture.
+ AP_ID(ap) = apid
+ AP_BEAM(ap) = apbeam
+ AP_CEN(ap, AP_AXIS(ap)) = center - ap_cveval (AP_CV(ap), real (line))
+ AP_LOW(ap, AP_AXIS(ap)) = min (low, high)
+ AP_HIGH(ap, AP_AXIS(ap)) = max (low, high)
+ if (AP_IC(ap) != NULL) {
+ call ic_putr (AP_IC(ap), "xmin",
+ min (low, high, ic_getr (AP_IC(ap), "xmin")))
+ call ic_putr (AP_IC(ap), "xmax",
+ max (low, high, ic_getr (AP_IC(ap), "xmax")))
+ }
+
+ # Mark the new aperture.
+ call gseti (gp, G_PLTYPE, 1)
+ call ap_gmark (gp, line, ap, 1)
+end
diff --git a/noao/twodspec/apextract/apvalues.x b/noao/twodspec/apextract/apvalues.x
new file mode 100644
index 00000000..2072907e
--- /dev/null
+++ b/noao/twodspec/apextract/apvalues.x
@@ -0,0 +1,32 @@
+include "apertures.h"
+
+# AP_VALUES -- Return the values for an aperture
+
+procedure ap_values (current, aps, line, apid, apbeam, center, low, high)
+
+int current # Index to current aperture
+pointer aps[ARB] # Apertures
+int line # Line
+int apid # Aperture ID
+int apbeam # Aperture beam
+real center # Aperture center
+real low # Lower limit of aperture
+real high # Upper limit of aperture
+
+int apaxis
+pointer ap
+
+real ap_cveval()
+
+begin
+ if (current > 0) {
+ ap = aps[current]
+ apaxis = AP_AXIS(ap)
+
+ apid = AP_ID(ap)
+ apbeam = AP_BEAM(ap)
+ center = AP_CEN(ap, apaxis) + ap_cveval (AP_CV(ap), real (line))
+ low = AP_LOW(ap, apaxis)
+ high = AP_HIGH(ap, apaxis)
+ }
+end
diff --git a/noao/twodspec/apextract/apvariance.x b/noao/twodspec/apextract/apvariance.x
new file mode 100644
index 00000000..015eed74
--- /dev/null
+++ b/noao/twodspec/apextract/apvariance.x
@@ -0,0 +1,420 @@
+include <gset.h>
+include "apertures.h"
+
+
+# AP_VARIANCE -- Variance weighted extraction based on profile and CCD noise.
+# If desired reject deviant pixels. In addition to the variance weighted
+# spectrum, the unweighted and uncleaned "raw" spectrum is extracted and
+# a sigma spectrum is returned. Wavelengths with saturated pixels are
+# flagged with 0 value and negative sigma if cleaning.
+
+procedure ap_variance (im, ap, dbuf, nc, nl, c1, l1, sbuf, svar, profile,
+ nx, ny, xs, ys, spec, raw, specsig, nsubaps, asi)
+
+pointer im # IMIO pointer
+pointer ap # Aperture structure
+pointer dbuf # Data buffer
+int nc, nl # Size of data buffer
+int c1, l1 # Origin of data buffer
+pointer sbuf # Sky values (NULL if none)
+pointer svar # Sky variance
+real profile[ny,nx] # Profile (returned)
+int nx, ny # Size of profile array
+int xs[ny], ys # Origin of profile array
+real spec[ny,nsubaps] # Spectrum
+real raw[ny,nsubaps] # Raw spectrum
+real specsig[ny,nsubaps] # Sky variance in, spectrum sigma out
+int nsubaps # Number of subapertures
+pointer asi # Image interpolator for edge pixel weighting
+
+real rdnoise # Readout noise in RMS data numbers.
+real gain # Gain in photons per data number.
+real saturation # Maximum value for an unsaturated pixel.
+bool clean # Clean cosmic rays?
+real nclean # Number of pixels to clean
+real lsigma, usigma # Rejection sigmas.
+
+bool sat
+int fd, iterate, niterate, nrej, irej, nreject
+int i, ix, iy, ix1, ix2
+real low, high, step, shift, x1, x2, wt1, wt2, s, w, dat, sk, var, var0
+real sum, wsum, wvsum, sum1, sum2, total1, total2
+real vmin, resid, rrej
+pointer cv, gp
+pointer sp, str, work, wt, xplot, yplot, eplot, fplot, data, sky, data1
+
+real apgetr(), apgimr(), ap_cveval()
+bool apgetb()
+errchk apgimr, ap_asifit
+
+begin
+ # Get task parameters.
+ gain = apgimr ("gain", im)
+ rdnoise = apgimr ("readnoise", im) ** 2
+ saturation = apgetr ("saturation")
+ if (!IS_INDEF(saturation))
+ saturation = saturation * gain
+ clean = apgetb ("clean")
+ lsigma = apgetr ("lsigma")
+ usigma = apgetr ("usigma")
+ call ap_popen (gp, fd, "clean")
+
+ # Allocate memory and one index.
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+ call salloc (work, 6*nx, TY_REAL)
+ wt = work - 1
+ xplot = wt + nx
+ yplot = xplot + nx
+ eplot = yplot + nx
+ fplot = eplot + nx
+ data1 = fplot + nx
+ if (sbuf == NULL) {
+ call salloc (sky, nx, TY_REAL)
+ call aclrr (Memr[sky], nx)
+ sky = sky - 1
+ var0 = rdnoise
+ }
+
+ # Initialize
+ if (rdnoise == 0.)
+ vmin = 1.
+ else
+ vmin = rdnoise
+ if (clean) {
+ nclean = apgetr ("nclean")
+ if (nclean < 1.)
+ niterate = max (1., nclean * nx)
+ else
+ niterate = max (1., min (real (nx), nclean))
+ } else
+ niterate = 0
+
+ call aclrr (spec, ny * nsubaps)
+ call aclrr (raw, ny * nsubaps)
+ call amovkr (-1., specsig, ny * nsubaps)
+
+ i = AP_AXIS(ap)
+ low = AP_CEN(ap,i) + AP_LOW(ap,i)
+ high = AP_CEN(ap,i) + AP_HIGH(ap,i)
+ step = (high - low) / nsubaps
+ cv = AP_CV(ap)
+
+ # For each line compute the weighted spectrum and then iterate
+ # to reject deviant pixels. Rejected pixels are flagged by negative
+ # variance.
+
+ nreject = 0
+ total1 = 0.
+ total2 = 0.
+ do iy = 1, ny {
+ shift = ap_cveval (cv, real (iy + ys - 1)) - c1 + 1
+ x1 = max (0.5, low + shift) + c1 - xs[iy]
+ x2 = min (nc + 0.49, high + shift) + c1 - xs[iy]
+ if (x1 >= x2)
+ next
+ ix1 = nint (x1)
+ ix2 = nint (x2)
+
+ call ap_asifit (dbuf+(iy+ys-1-l1)*nc, nc, xs[iy]-c1+1,
+ low+shift, high+shift, data, asi)
+# data = dbuf + (iy + ys - 1 - l1) * nc + xs[iy] - c1 - 1
+ if (sbuf != NULL) {
+ sky = sbuf + (iy - 1) * nx - 1
+ var0 = rdnoise + Memr[svar+iy-1]
+ }
+
+ # Set pixel weights for summing.
+# if (asi != NULL)
+# call asifit (asi, Memr[data], nc-xs[iy]+c1)
+ call ap_edge (asi, x1+1, x2+1, wt1, wt2)
+
+ # First estimate spectrum by summing across the aperture.
+ # Accumulate the raw spectrum and set up various arrays for
+ # plotting and later access.
+
+ sat = false
+ sum = 0.
+ wsum = 0.
+ wvsum = 0.
+ do ix = ix1, ix2 {
+ if (ix1 == ix2)
+ w = wt1
+ else if (ix == ix1)
+ w = wt1
+ else if (ix == ix2)
+ w = wt2
+ else
+ w = 1.
+ dat = Memr[data+ix]
+ if (!IS_INDEF(saturation))
+ if (dat > saturation)
+ sat = true
+ sk = Memr[sky+ix]
+ raw[iy,1] = raw[iy,1] + w * (dat - sk)
+
+ Memr[xplot+ix] = ix + xs[iy] - 1
+ Memr[yplot+ix] = dat - sk
+ Memr[data1+ix] = dat - sk
+ Memr[wt+ix] = w
+ var = max (vmin, var0 + max (0., dat))
+ w = profile[iy,ix] / var
+ var = sqrt (var)
+ Memr[eplot+ix] = var
+ sum = sum + w * (dat - sk)
+ wsum = wsum + w * profile[iy,ix]
+ wvsum = wvsum + (w * var) ** 2
+ }
+ if (wsum > 0.) {
+ spec[iy,1] = sum / wsum
+ specsig[iy,1] = sqrt (wvsum) / abs (wsum)
+ } else {
+ spec[iy,1] = 0.
+ specsig[iy,1] = -1.
+ }
+
+ sum = 0.
+ wsum = 0.
+ wvsum = 0.
+ sum1 = 0.
+ sum2 = 0.
+ do ix = ix1, ix2 {
+ sum1 = sum1 + Memr[wt+ix] * Memr[data1+ix]
+ if (Memr[eplot+ix] <= 0.)
+ next
+ sk = Memr[sky+ix]
+ s = max (0., spec[iy,1]) * profile[iy,ix]
+ var = max (vmin, var0 + (s + sk))
+ w = profile[iy,ix] / var
+ var = sqrt (var)
+ Memr[eplot+ix] = var
+ Memr[fplot+ix] = s
+ sum = sum + w * Memr[data1+ix]
+ wsum = wsum + w * profile[iy,ix]
+ wvsum = wvsum + (w * var) ** 2
+ }
+ if (wsum > 0.) {
+ spec[iy,1] = sum / wsum
+ specsig[iy,1] = sqrt (wvsum) / abs (wsum)
+ sum2 = sum2 + spec[iy,1]
+ } else {
+ spec[iy,1] = 0.
+ specsig[iy,1] = -1.
+ sum1 = 0.
+ sum2 = 0.
+ }
+
+ # Reject cosmic rays one at a time.
+ nrej = 0
+ do iterate = 1, niterate {
+ irej = 0
+ rrej = 0.
+
+ # Compute revised variance estimate using profile model
+ # skip rejected pixels, find worst pixel.
+
+ do ix = ix1, ix2 {
+ if (Memr[eplot+ix] <= 0.)
+ next
+ s = max (0., spec[iy,1]) * profile[iy,ix]
+ sk = Memr[sky+ix]
+ var = sqrt (max (vmin, var0 + max (0., s + sk)))
+ Memr[fplot+ix] = s
+ Memr[eplot+ix] = var
+
+ resid = (Memr[data1+ix] - Memr[fplot+ix]) / var
+ if (abs (resid) > abs (rrej)) {
+ rrej = resid
+ irej = ix
+ }
+ }
+
+ # Reject worst outlier.
+
+ if (rrej <= -lsigma || rrej >= usigma) {
+ Memr[eplot+irej] = -Memr[eplot+irej]
+ Memr[data1+irej] = Memr[fplot+irej]
+ nrej = nrej + 1
+ } else
+ break
+
+ # Update spectrum estimate excluding rejected pixels.
+ sum = 0.
+ wsum = 0.
+ wvsum = 0.
+ sum1 = 0.
+ sum2 = 0.
+ do ix = ix1, ix2 {
+ sum1 = sum1 + Memr[wt+ix] * Memr[data1+ix]
+ if (Memr[eplot+ix] <= 0.)
+ next
+ w = profile[iy,ix] / Memr[eplot+ix]**2
+ sum = sum + w * Memr[data1+ix]
+ wsum = wsum + w * profile[iy,ix]
+ wvsum = wvsum + (w * Memr[eplot+ix]) ** 2
+ }
+
+ if (wsum > 0.) {
+ spec[iy,1] = sum / wsum
+ specsig[iy,1] = sqrt (wvsum) / abs (wsum)
+ sum2 = sum2 + spec[iy,1]
+ } else {
+ spec[iy,1] = 0.
+ specsig[iy,1] = -1.
+ sum1 = 0.
+ sum2 = 0.
+ }
+ }
+
+ nreject = nreject + nrej
+ total1 = total1 + sum1
+ total2 = total2 + sum2
+
+ # Calculate subapertures if desired.
+ if (nsubaps > 1) {
+ do i = 1, nsubaps {
+ x1 = max (0.5, low + (i - 1) * step + shift) + c1 - xs[iy]
+ x2 = min (nc + 0.49, low + i * step + shift) + c1 - xs[iy]
+ if (x1 >= x2) {
+ spec[iy,i] = 0.
+ raw[iy,i] = 0.
+ specsig[iy,i] = -1.
+ next
+ }
+ ix1 = nint (x1)
+ ix2 = nint (x2)
+ call ap_edge (asi, x1+1, x2+1, wt1, wt2)
+
+ sum = 0.
+ wvsum = 0.
+ raw[iy,i] = 0.
+ do ix = ix1, ix2 {
+ if (ix1 == ix2)
+ w = wt1
+ else if (ix == ix1)
+ w = wt1
+ else if (ix == ix2)
+ w = wt2
+ else
+ w = 1.
+ raw[iy,i] = raw[iy,i] + w * Memr[yplot+ix]
+ if (Memr[eplot+ix] <= 0.)
+ next
+ w = profile[iy,ix] / Memr[eplot+ix]**2
+ sum = sum + w * Memr[data1+ix]
+ wvsum = wvsum + (w * Memr[eplot+ix]) ** 2
+ }
+
+ if (wsum > 0.) {
+ spec[iy,i] = sum / wsum
+ specsig[iy,i] = sqrt (wvsum) / abs (wsum)
+ } else {
+ spec[iy,i] = 0.
+ specsig[iy,i] = -1.
+ }
+ }
+ }
+
+ # Flag points with saturated pixels.
+ if (sat)
+ do i = 1, nsubaps
+ specsig[iy,i] = -specsig[iy,i]
+
+ # Plot profile with cosmic rays if desired.
+ if (gp != NULL && nrej > 0 && spec[iy,1] > 0.) {
+ call sprintf (Memc[str], SZ_LINE, "Profile %4d")
+ call pargi (iy)
+ s = Memr[yplot+ix1] - abs (Memr[eplot+ix1])
+ w = Memr[yplot+ix1] + abs (Memr[eplot+ix1])
+ do ix = ix1+1, ix2 {
+ s = min (s, Memr[yplot+ix] - abs (Memr[eplot+ix]))
+ w = max (w, Memr[yplot+ix] + abs (Memr[eplot+ix]))
+ }
+ sum = w - s
+ x1 = ix1 + xs[iy] - 2
+ x2 = ix2 + xs[iy]
+ s = s - 0.1 * sum
+ w = w + 0.1 * sum
+ call gclear (gp)
+ call gswind (gp, x1, x2, s, w)
+ call glabax (gp, Memc[str], "", "")
+
+ do ix = ix1, ix2 {
+ if (Memr[eplot+ix] > 0.) {
+ call gmark (gp, Memr[xplot+ix], Memr[yplot+ix],
+ GM_PLUS, 2., 2.)
+ call gmark (gp, Memr[xplot+ix], Memr[yplot+ix],
+ GM_VEBAR, 2., -6.*Memr[eplot+ix])
+ } else {
+ call gmark (gp, Memr[xplot+ix], Memr[yplot+ix],
+ GM_CROSS, 2., 2.)
+ call gmark (gp, Memr[xplot+ix], Memr[yplot+ix],
+ GM_VEBAR, 1., 6.*Memr[eplot+ix])
+ }
+ }
+ call gpline (gp, Memr[xplot+ix1], Memr[fplot+ix1], ix2-ix1+1)
+ }
+ }
+
+ # To avoid any bias, scale weighted extraction to same total flux
+ # as raw spectrum (with rejected pixels replaced by fit).
+
+ if (total1 * total2 <= 0.) {
+ call sprintf (Memc[str], SZ_LINE,
+ "EXTRACT: WARNING - Aperture %d:")
+ call pargi (AP_ID(ap))
+ call ap_log (Memc[str], YES, NO, YES)
+ call sprintf (Memc[str], SZ_LINE,
+ " Total variance weighted spectrum flux is %g")
+ call pargr (total2)
+ call ap_log (Memc[str], YES, NO, YES)
+ call sprintf (Memc[str], SZ_LINE,
+ " Total unweighted spectrum flux is %g")
+ call pargr (total1)
+ call ap_log (Memc[str], YES, NO, YES)
+ call sprintf (Memc[str], SZ_LINE,
+ " Variance spectrum bias factor ignored")
+ call ap_log (Memc[str], YES, NO, YES)
+ } else {
+ sum = total1 / total2
+ call amulkr (spec, sum, spec, ny * nsubaps)
+ call amulkr (specsig, sum, specsig, ny * nsubaps)
+ if (sum < .5 || sum > 2) {
+ call sprintf (Memc[str], SZ_LINE,
+ "EXTRACT: WARNING - Aperture %d:")
+ call pargi (AP_ID(ap))
+ call ap_log (Memc[str], YES, NO, YES)
+ call sprintf (Memc[str], SZ_LINE,
+ " Total variance weighted spectrum flux is %g")
+ call pargr (total2)
+ call ap_log (Memc[str], YES, NO, YES)
+ call sprintf (Memc[str], SZ_LINE,
+ " Total unweighted spectrum flux is %g")
+ call pargr (total1)
+ call ap_log (Memc[str], YES, NO, YES)
+ call sprintf (Memc[str], SZ_LINE,
+ "EXTRACT: Aperture %d variance spectrum bias factor is %g")
+ call pargi (AP_ID(ap))
+ call pargr (total1 / total2)
+ call ap_log (Memc[str], YES, NO, YES)
+ } else {
+ call sprintf (Memc[str], SZ_LINE,
+ "EXTRACT: Aperture %d variance spectrum bias factor is %g")
+ call pargi (AP_ID(ap))
+ call pargr (total1 / total2)
+ call ap_log (Memc[str], YES, NO, NO)
+ }
+ }
+
+ # Log the number of rejected pixels.
+ if (clean) {
+ call sprintf (Memc[str], SZ_LINE,
+ "EXTRACT: %d pixels rejected from aperture %d")
+ call pargi (nreject)
+ call pargi (AP_ID(ap))
+ call ap_log (Memc[str], YES, NO, NO)
+ }
+
+ call ap_pclose (gp, fd)
+ call sfree (sp)
+end
diff --git a/noao/twodspec/apextract/apwidth.cl b/noao/twodspec/apextract/apwidth.cl
new file mode 100644
index 00000000..94a247d7
--- /dev/null
+++ b/noao/twodspec/apextract/apwidth.cl
@@ -0,0 +1,59 @@
+# APWIDTH -- Script to report widths from APALL database files.
+# The input is the image name and database directory.
+# The output is image name, aperture number, x center, y center, and width.
+#
+# To install this script copy it to a directory, such as your IRAF login
+# directory "home$" in this example. Define the task in your loginuser.cl
+# or login.cl with
+#
+# task apwidth = home$apwidth.cl
+#
+# Note that you can substitute some other path to the script if desired.
+
+procedure apwidth (image)
+
+file image {prompt="Image name"}
+file database = "database" {prompt="Database"}
+
+begin
+ file dbfile
+ string im
+ int ap, axis
+ real xc, yc, aplow1, aphigh1, aplow2, aphigh2, width
+
+ # Form database name from the database and image names.
+ dbfile = database // "/ap" // image
+
+ # Check that the database file actually exists.
+ if (!access(dbfile))
+ error (1, "Databse file not found (" // dbfile // ")")
+
+ # Loop through each line of the database file. Extract information
+ # and print the output line when the axis keyword is found. This
+ # assumes the aperture limits are read before the axis.
+
+ axis = INDEF
+ list = dbfile
+ while (fscan (list, line) != EOF) {
+ if (fscan (line, s1) < 1)
+ next
+ if (s1 == "begin")
+ i = fscan (line, s1, s1, im, ap, xc, yc)
+ else if (s1 == "low")
+ i = fscan (line, s1, aplow1, aplow2)
+ else if (s1 == "high")
+ i = fscan (line, s1, aphigh1, aphigh2)
+ else if (s1 == "axis")
+ i = fscan (line, s1, axis)
+
+ if (axis != INDEF) {
+ if (axis == 1)
+ width = aphigh1 - aplow1
+ else
+ width = aphigh2 - aplow2
+ printf ("%s %2d %8.4g %8.4g %8.4g\n", im, ap, xc, yc, width)
+ axis = INDEF
+ }
+ }
+ list = ""
+end
diff --git a/noao/twodspec/apextract/apylevel.x b/noao/twodspec/apextract/apylevel.x
new file mode 100644
index 00000000..aa208453
--- /dev/null
+++ b/noao/twodspec/apextract/apylevel.x
@@ -0,0 +1,103 @@
+# AP_YLEVEL -- Set the aperture to intercept the specified y level.
+
+procedure ap_ylevel (imdata, npts, ylevel, peak, bkg, grow, center, low, high)
+
+real imdata[npts] # Image data
+int npts # Number of image points
+real ylevel # Y value
+bool peak # Is y a fraction of peak?
+bool bkg # Subtract a background?
+real grow # Grow factor
+real center # Center of aperture
+real low, high # Equal flux points
+
+int i1, i2, j1, j2, k1, k2
+real y, y1, y2, a, b, ycut, x
+
+begin
+ if ((center < 1.) || (center >= npts) || IS_INDEF (ylevel))
+ return
+
+ if (bkg) {
+ i1 = nint (center)
+ i2 = max (1, nint (center + low))
+ for (k1=i1; k1 > i2 && imdata[k1] <= imdata[k1-1]; k1=k1-1)
+ ;
+ for (; k1 > i2 && imdata[k1] >= imdata[k1-1]; k1=k1-1)
+ ;
+
+ i2 = min (npts, nint (center + high))
+ for (k2=i1; k2 < i2 && imdata[k2] <= imdata[k2+1]; k2=k2+1)
+ ;
+ for (; k2 < i2 && imdata[k2] >= imdata[k2+1]; k2=k2+1)
+ ;
+
+ a = imdata[k1]
+ b = (imdata[k2] - imdata[k1]) / (k2 - k1)
+ } else {
+ k1 = center
+ a = 0.
+ b = 0.
+ }
+
+ i1 = center
+ i2 = i1 + 1
+ y1 = imdata[i1] - a - b * (i1 - k1)
+ y2 = imdata[i2] - a - b * (i2 - k1)
+ y = y1 * (i2 - center) + y2 * (center - i1)
+
+ if (peak)
+ ycut = ylevel * y
+ else
+ ycut = ylevel
+
+ if (y > ycut) {
+ for (j1 = i1; j1 >= 1; j1 = j1 - 1) {
+ y1 = imdata[j1] - a - b * (j1 - k1)
+ if (y1 <= ycut)
+ break
+ }
+ if (j1 >= 1) {
+ j2 = j1 + 1
+ y2 = imdata[j2] - a - b * (j2 - k1)
+ x = (ycut + y2 * j1 - y1 * j2) / (y2 - y1) - center
+ low = max (low, (1.+grow)*x)
+ }
+
+ for (j2 = i2; j2 <= npts; j2 = j2 + 1) {
+ y2 = imdata[j2] - a - b * (j2 - k1)
+ if (y2 <= ycut)
+ break
+ }
+ if (j2 <= npts) {
+ j1 = j2 - 1
+ y1 = imdata[j1] - a - b * (j1 - k1)
+ x = (ycut + y2*j1 - y1*j2) / (y2 - y1) - center
+ high = min (high, (1.+grow)*x)
+ }
+ } else {
+ for (j1 = i1; j1 >= 1; j1 = j1 - 1) {
+ y1 = imdata[j1] - a - b * (j1 - k1)
+ if (y1 >= ycut)
+ break
+ }
+ if (j1 >= 1) {
+ j2 = j1 + 1
+ y2 = imdata[j2] - a - b * (j2 - k1)
+ x = (ycut + y2 * j1 - y1 * j2) / (y2 - y1) - center
+ low = max (low, (1.+grow)*x)
+ }
+
+ for (j2 = i2; j2 <= npts; j2 = j2 + 1) {
+ y2 = imdata[j2] - a - b * (j2 - k1)
+ if (y2 >= ycut)
+ break
+ }
+ if (j2 <= npts) {
+ j1 = j2 - 1
+ y1 = imdata[j1] - a - b * (j1 - k1)
+ x = (ycut + y2*j1 - y1*j2) / (y2 - y1) - center
+ high = min (high, (1.+grow)*x)
+ }
+ }
+end
diff --git a/noao/twodspec/apextract/doc/apall.hlp b/noao/twodspec/apextract/doc/apall.hlp
new file mode 100644
index 00000000..c4e50072
--- /dev/null
+++ b/noao/twodspec/apextract/doc/apall.hlp
@@ -0,0 +1,557 @@
+.help apall Sep96 noao.twodspec.apextract
+.ih
+NAME
+apall -- Extract one dimensional sums across the apertures
+.ih
+USAGE
+apall input
+.ih
+PARAMETERS
+.ls input
+List of input images.
+.le
+.ls output = ""
+List of output root names for extracted spectra. If the null
+string is given or the end of the output list is reached before the end
+of the input list then the input image name is used as the output root name.
+This will not conflict with the input image since an aperture number
+extension is added for onedspec format, the extension ".ms" for multispec
+format, or the extension ".ec" for echelle format.
+.le
+.ls apertures = ""
+Apertures to recenter, resize, trace, and extract. This only applies
+to apertures read from the input or reference database. Any new
+apertures defined with the automatic finding algorithm or interactively
+are always selected. The syntax is a list comma separated ranges
+where a range can be a single aperture number, a hyphen separated
+range of aperture numbers, or a range with a step specified by "x<step>";
+for example, "1,3-5,9-12x2".
+.le
+.ls format = "multispec" (onedspec|multispec|echelle|strip)
+Format for output extracted spectra. "Onedspec" format extracts each
+aperture to a separate image while "multispec" and "echelle" extract
+multiple apertures for the same image to a single output image.
+The "multispec" and "echelle" format selections differ only in the
+extension added. The "strip" format produces a separate 2D image in
+which each column or line along the dispersion axis is shifted to
+exactly align the aperture based on the trace information.
+.le
+.ls references = ""
+List of reference images to be used to define apertures for the input
+images. When a reference image is given it supersedes apertures
+previously defined for the input image. The list may be null, "", or
+any number of images less than or equal to the list of input images.
+There are three special words which may be used in place of an image
+name. The word "last" refers to the last set of apertures written to
+the database. The word "OLD" requires that an entry exist
+and the word "NEW" requires that the entry not exist for each input image.
+Input images without/with a database entry are skipped silently.
+.le
+.ls profiles = ""
+List of profile images for variance weighting or cleanning. If variance
+weighting or cleanning a profile of each aperture is computed from the
+input image unless a profile image is specified, in which case the
+profile is computed from the profile image. The profile image must
+have the same dimensions and dispersion and it is assumed that the
+spectra have the same position and profile shape as in the object
+spectra. Use of a profile image is generally not required even for
+faint input spectra but the option is available for those who wish
+to use it.
+.le
+
+.ce
+PROCESSING PARAMETERS
+.ls interactive = yes
+Run this task interactively? If the task is not run interactively then
+all user queries are suppressed and interactive aperture editing, trace
+fitting, and extraction review are disabled.
+.le
+.ls find = yes
+Find the spectra and define apertures automatically? In order for
+spectra to be found automatically there must be no apertures for the
+input image or reference image defined in the database.
+.le
+.ls recenter = yes
+Recenter the apertures?
+.le
+.ls resize = yes
+Resize the apertures?
+.le
+.ls edit = yes
+Edit the apertures? The \fIinteractive\fR parameter must also be yes.
+.le
+.ls trace = yes
+Trace the apertures?
+.le
+.ls fittrace = yes
+Interactively fit the traced positions by a function? The \fIinteractive\fR
+parameter must also be yes.
+.le
+.ls extract = yes
+Extract the one dimensional aperture sums?
+.le
+.ls extras = yes
+Extract the raw spectrum (if variance weighting is used), the sky spectrum
+(if background subtraction is used), and sigma spectrum (if variance
+weighting is used)? This information is extracted to the third dimension
+of the output image.
+.le
+.ls review = yes
+Review the extracted spectra? The \fIinteractive\fR parameter must also be
+yes.
+.le
+
+.ls line = INDEF, nsum = 10
+The dispersion line (line or column perpendicular to the dispersion
+axis) and number of adjacent lines (half before and half after unless
+at the end of the image) used in finding, recentering, resizing,
+and editing operations. A line of INDEF selects the middle of the
+image along the dispersion axis. A positive nsum selects a sum of
+lines and a negative selects a median of lines.
+.le
+
+.ce
+DEFAULT APERTURE PARAMETERS
+.ls lower = -5., upper = 5.
+Default lower and upper aperture limits relative to the aperture center.
+These limits are used for apertures found with \fBapfind\fR and when
+defining the first aperture in \fBapedit\fR.
+.le
+.ls apidtable = ""
+Aperture identification table. This may be either a text file or an
+image. A text file consisting of lines with an aperture number, beam
+number, and aperture title or identification. An image will contain the
+keywords SLFIBnnn with string value consisting of aperture number, beam
+number, optional right ascension and declination, and aperture title. This
+information is used to assign aperture information automatically in
+\fBapfind\fR and \fBapedit\fR.
+.le
+
+.ce
+DEFAULT BACKGROUND PARAMETERS
+.ls b_function = "chebyshev"
+Default background fitting function. The fitting function types are
+"chebyshev" polynomial, "legendre" polynomial, "spline1" linear spline, and
+"spline3" cubic spline.
+.le
+.ls b_order = 1
+Default background function order. The order refers to the number of
+terms in the polynomial functions or the number of spline pieces in the spline
+functions.
+.le
+.ls b_sample = "-10:-6,6:10"
+Default background sample. The sample is given by a set of colon separated
+ranges each separated by either whitespace or commas. The string "*" refers
+to all points. Note that the background coordinates are relative to the
+aperture center and not image pixel coordinates so the endpoints need not
+be integer.
+.le
+.ls b_naverage = -3
+Default number of points to average or median. Positive numbers
+average that number of sequential points to form a fitting point.
+Negative numbers median that number, in absolute value, of sequential
+points. A value of 1 does no averaging and each data point is used in the
+fit.
+.le
+.ls b_niterate = 0
+Default number of rejection iterations. If greater than zero the fit is
+used to detect deviant fitting points and reject them before repeating the
+fit. The number of iterations of this process is given by this parameter.
+.le
+.ls b_low_reject = 3., b_high_reject = 3.
+Default background lower and upper rejection sigmas. If greater than zero
+points deviating from the fit below and above the fit by more than this
+number of times the sigma of the residuals are rejected before refitting.
+.le
+.ls b_grow = 0.
+Default reject growing radius. Points within a distance given by this
+parameter of any rejected point are also rejected.
+.le
+
+.ce
+APERTURE CENTERING PARAMETERS
+.ls width = 5.
+Width of spectrum profiles. This parameter is used for the profile
+centering algorithm in this and other tasks.
+.le
+.ls radius = 10.
+The profile centering error radius for the centering algorithm.
+.le
+.ls threshold = 0.
+Centering threshold for the centering algorithm. The range of pixel intensities
+near the initial centering position must exceed this threshold.
+.le
+
+.ce
+AUTOMATIC FINDING AND ORDERING PARAMETERS
+.ls nfind
+Maximum number of apertures to be defined. This is a query parameter
+so the user is queried for a value except when given explicitly on
+the command line.
+.le
+.ls minsep = 5.
+Minimum separation between spectra. Weaker spectra or noise within this
+distance of a stronger spectrum are rejected.
+.le
+.ls maxsep = 1000.
+Maximum separation between adjacent spectra. This parameter
+is used to identify missing spectra in uniformly spaced spectra produced
+by fiber spectrographs. If two adjacent spectra exceed this separation
+then it is assumed that a spectrum is missing and the aperture identification
+assignments will be adjusted accordingly.
+.le
+.ls order = "increasing"
+When assigning aperture identifications order the spectra "increasing"
+or "decreasing" with increasing pixel position (left-to-right or
+right-to-left in a cross-section plot of the image).
+.le
+
+.ce
+RECENTERING PARAMETERS
+.ls aprecenter = ""
+List of apertures to be used in shift calculation.
+.le
+.ls npeaks = INDEF
+Select the specified number of apertures with the highest peak values
+to be recentered. If the number is INDEF all apertures will be selected.
+If the value is less than 1 then the value is interpreted as a fraction
+of total number of apertures.
+.le
+.ls shift = yes
+Use the average shift from recentering the apertures selected by the
+\fIaprecenter\fR parameter to apply to the apertures selected by the
+\fIapertures\fR parameter. The recentering is then a constant shift for
+all apertures.
+.le
+
+.ce
+RESIZING PARAMETERS
+.ls llimit = INDEF, ulimit = INDEF
+Lower and upper aperture size limits. If the parameter \fIylevel\fR is
+INDEF then these limits are assigned to all apertures. Otherwise
+these parameters are used as limits to the resizing operation.
+A value of INDEF places the aperture limits at the image edge (for the
+dispersion line used).
+.le
+.ls ylevel = 0.1
+Data level at which to set aperture limits. If it is INDEF then the
+aperture limits are set at the values given by the parameters
+\fIllimit\fR and \fIulimit\fR. If it is not INDEF then it is a
+fraction of the peak or an actual data level depending on the parameter
+\fIpeak\fR. It may be relative to a local background or to zero
+depending on the parameter \fIbkg\fR.
+.le
+.ls peak = yes
+Is the data level specified by \fIylevel\fR a fraction of the peak?
+.le
+.ls bkg = yes
+Subtract a simple background when interpreting the \fBylevel\fR parameter.
+The background is a slope connecting the first inflection points
+away from the aperture center.
+.le
+.ls r_grow = 0.
+Change the lower and upper aperture limits by this fractional amount.
+The factor is multiplied by each limit and the result added to limit.
+.le
+.ls avglimits = no
+Apply the average lower and upper aperture limits to all apertures.
+.le
+
+.ce
+TRACING PARAMETERS
+.ls t_nsum = 10
+Number of dispersion lines to be summed at each step along the dispersion.
+.le
+.ls t_step = 10
+Step along the dispersion axis between determination of the spectrum
+positions.
+.le
+.ls t_nlost = 3
+Number of consecutive steps in which the profile is lost before quitting
+the tracing in one direction. To force tracing to continue through
+regions of very low signal this parameter can be made large. Note,
+however, that noise may drag the trace away before it recovers.
+.le
+.ls t_function = "legendre"
+Default trace fitting function. The fitting function types are
+"chebyshev" polynomial, "legendre" polynomial, "spline1" linear spline, and
+"spline3" cubic spline.
+.le
+.ls t_order = 2
+Default trace function order. The order refers to the number of
+terms in the polynomial functions or the number of spline pieces in the spline
+functions.
+.le
+.ls t_sample = "*"
+Default fitting sample. The sample is given by a set of colon separated
+ranges each separated by either whitespace or commas. The string "*" refers
+to all points.
+.le
+.ls t_naverage = 1
+Default number of points to average or median. Positive numbers
+average that number of sequential points to form a fitting point.
+Negative numbers median that number, in absolute value, of sequential
+points. A value of 1 does no averaging and each data point is used in the
+.le
+.ls t_niterate = 0
+Default number of rejection iterations. If greater than zero the fit is
+used to detect deviant traced positions and reject them before repeating the
+fit. The number of iterations of this process is given by this parameter.
+.le
+.ls t_low_reject = 3., t_high_reject = 3.
+Default lower and upper rejection sigma. If greater than zero traced
+points deviating from the fit below and above the fit by more than this
+number of times the sigma of the residuals are rejected before refitting.
+.le
+.ls t_grow = 0.
+Default reject growing radius. Traced points within a distance given by this
+parameter of any rejected point are also rejected.
+.le
+
+.ce
+EXTRACTION PARAMETERS
+.ls background = "none" (none|average|median|minimum|fit)
+Type of background subtraction. The choices are "none" for no background
+subtraction, "average" to average the background within the background
+regions, "median" to use the median in the background regions, "minimum" to
+use the minimum in the background regions, or "fit" to fit across the
+dispersion using the background within the background regions. Note that
+the "average" option does not do any medianing or bad pixel checking,
+something which is recommended. The fitting option is slower than the
+other options and requires additional fitting parameter.
+.le
+.ls skybox = 1
+Box car smoothing length for sky background when using background
+subtraction. Since the background noise is often the limiting factor
+for good extraction one may box car smooth the sky to improve the
+statistics in smooth background regions at the expense of distorting
+the subtraction near spectral features. This is most appropriate when
+the sky regions are limited due to a small slit length.
+.le
+.ls weights = "none" (none|variance)
+Type of extraction weighting. Note that if the \fIclean\fR parameter is
+set then the weights used are "variance" regardless of the weights
+specified by this parameter. The choices are:
+.ls "none"
+The pixels are summed without weights except for partial pixels at the
+ends.
+.le
+.ls "variance"
+The extraction is weighted by the variance based on the data values
+and a poisson/ccd model using the \fIgain\fR and \fIreadnoise\fR
+parameters.
+.le
+.le
+.ls pfit = "fit1d" (fit1d|fit2d)
+Profile fitting algorithm to use with variance weighting or cleaning.
+When determining a profile the two dimensional spectrum is divided by
+an estimate of the one dimensional spectrum to form a normalized two
+dimensional spectrum profile. This profile is then smoothed by fitting
+one dimensional functions, "fit1d", along the lines or columns most closely
+corresponding to the dispersion axis or a special two dimensional
+function, "fit2d", described by Marsh (see \fBapprofile\fR).
+.le
+.ls clean = no
+Detect and replace deviant pixels?
+.le
+.ls saturation = INDEF
+Saturation or nonlinearity level in data units. During variance weighted
+extractions wavelength points having any pixels above this value are
+excluded from the profile determination and the sigma spectrum extraction
+output, if selected by the \fIextras\fR parameter, flags wavelengths with
+saturated pixels with a negative sigma.
+.le
+.ls readnoise = 0.
+Read out noise in photons. This parameter defines the minimum noise
+sigma. It is defined in terms of photons (or electrons) and scales
+to the data values through the gain parameter. A image header keyword
+(case insensitive) may be specified to get the value from the image.
+.le
+.ls gain = 1
+Detector gain or conversion factor between photons/electrons and
+data values. It is specified as the number of photons per data value.
+A image header keyword (case insensitive) may be specified to get the value
+from the image.
+.le
+.ls lsigma = 4., usigma = 4.
+Lower and upper rejection thresholds, given as a number of times the
+estimated sigma of a pixel, for cleaning.
+.le
+.ls nsubaps = 1
+During extraction it is possible to equally divide the apertures into
+this number of subapertures. For multispec format all subapertures will
+be in the same file with aperture numbers of 1000*(subap-1)+ap where
+subap is the subaperture (1 to nsubaps) and ap is the main aperture
+number. For echelle format there will be a separate echelle format
+image containing the same subaperture from each order. The name
+will have the subaperture number appended. For onedspec format
+each subaperture will be in a separate file with extensions and
+aperture numbers as in the multispec format.
+.le
+.ih
+ADDITIONAL PARAMETERS
+Dispersion axis and I/O parameters are taken from the package parameters.
+.ih
+DESCRIPTION
+This task provides functions for defining, modifying, tracing, and
+extracting apertures from two dimensional spectra. The functions
+desired are selected using switch parameters. When the task is
+run interactively queries are made at each step allowing additional
+control of the operations performed on each input image.
+
+The functions, in the order in which they are generally performed, are
+summarized below.
+.ls o
+Automatically find a specified number of spectra and assign default
+apertures. Apertures may also be inherited from another image or
+defined using an interactive graphical interface called the \fIaperture
+editor\fR.
+.le
+.ls o
+Recenter selected reference apertures on the image spectrum profiles.
+.le
+.ls o
+Resize the selected reference apertures based on spectrum profile width.
+.le
+.ls o
+Interactively define or adjust aperture definitions using a graphical
+interface called the \fIaperture editor\fR. All function may also
+be performed from this editor and, so, provides an alternative
+method of processing and extracting spectra.
+.le
+.ls o
+Trace the positions of the selected spectra profiles from a starting image line
+or column to other image lines or columns and fit a smooth function.
+The trace function is used to shift the center of the apertures
+at each dispersion point in the image.
+.le
+.ls o
+Extract the flux in the selected apertures into one dimensional spectra in
+various formats. This includes possible background subtraction, variance
+weighting, and bad pixel rejection.
+.le
+
+Each of these functions has different options and parameters. In
+addition to selecting any of these functions in this task, they may
+also be selected using the aperture editor and as individual
+commands (which themselves allow selection of other functions). When
+broken down into individual tasks the parameters are also sorted by
+their function though there are then some mutual parameter
+interdependencies. This functional decomposition is what was available
+prior to the addition of the \fBapall\fR task. It is recommended that
+this task be used because it collects all the parameters in one
+place eliminating confusion over where a particular parameter
+is defined. However, documenting the various functions
+is better organized in terms of the separate descriptions given for
+each of the functions; namely under the help topics
+\fBapdefault, apfind, aprecenter, apresize, apedit,
+aptrace\fR, and \fBapsum\fR.
+.ih
+EXAMPLES
+1. This example may be executed if desired. First we create an artificial
+spectrum with four spectra and a background. After it is created you
+can display or plot it. Next we define the dispersion axis and set the
+verbose flag to better illustrate what is happening. The task APALL
+is run with the default parameters except for background fitting and
+subtracting added. The text beginning with # are comments of things to
+try and do.
+
+.nf
+ ap> artdata
+ ar> unlearn artdata
+ ar> mk1dspec apdemo1d nl=50
+ ar> mk2dspec apdemo2d model=STDIN
+ apdemo1d 1. gauss 3 0 20 .01
+ apdemo1d .8 gauss 3 0 40 .01
+ apdemo1d .6 gauss 3 0 60 .01
+ apdemo1d .4 gauss 3 0 80 .01
+ [EOF=Control D or Control Z]
+ ar> mknoise apdemo2d background=100. rdnoise=3. poisson+
+ ar> bye
+ # Display or plot the spectrum
+ ap> dispaxis=2; verbose=yes
+ ap> unlearn apall
+ ap> apall apdemo2d back=fit
+ Searching aperture database ...
+ Find apertures for apdemo2d? (yes):
+ Finding apertures ...
+ Number of apertures to be found automatically (1): 4
+ Jul 31 16:55: FIND - 4 apertures found for apdemo2d.
+ Resize apertures for apdemo2d? (yes):
+ Resizing apertures ...
+ Jul 31 16:55: RESIZE - 4 apertures resized for apdemo2d.
+ Edit apertures for apdemo2d? (yes):
+ # Get a list of commands with '?'
+ # See all the parameters settings with :par
+ # Try deleting and marking a spectrum with 'd' and 'm'
+ # Look at the background fitting parameters with 'b' (exit with 'q')
+ # Exit with 'q'
+ Trace apertures for apdemo2d? (yes):
+ Fit traced positions for apdemo2d interactively? (yes):
+ Tracing apertures ...
+ Fit curve to aperture 1 of apdemo2d interactively (yes):
+ # You can use ICFIT commands to adjust the fit.
+ Fit curve to aperture 2 of apdemo2d interactively (yes): n
+ Fit curve to aperture 3 of apdemo2d interactively (no):
+ Fit curve to aperture 4 of apdemo2d interactively (no): y
+ Jul 31 16:56: TRACE - 4 apertures traced in apdemo2d.
+ Write apertures for apdemo2d to apdemosdb (yes):
+ Jul 31 16:56: DATABASE - 4 apertures for apdemo2d written to database.
+ Extract aperture spectra for apdemo2d? (yes):
+ Review extracted spectra from apdemo2d? (yes):
+ Extracting apertures ...
+ Review extracted spectrum for aperture 1 from apdemo2d? (yes):
+ # Type 'q' to quit
+ Jul 31 16:56: EXTRACT - Aperture 1 from apdemo2d --> apdemo2d.ms
+ Review extracted spectrum for aperture 2 from apdemo2d? (yes): N
+ Jul 31 16:56: EXTRACT - Aperture 2 from apdemo2d --> apdemo2d.ms
+ Jul 31 16:56: EXTRACT - Aperture 3 from apdemo2d --> apdemo2d.ms
+ Jul 31 16:57: EXTRACT - Aperture 4 from apdemo2d --> apdemo2d.ms
+.fi
+
+2. To extract a series of similar spectra noninteractively using a
+reference for the aperture definitions, then recentering and resizing
+but not retracing:
+
+.nf
+ ap> apall fib*.imh ref=flat inter- trace-
+.fi
+
+Note that the interactive flag automatically turns off the edit, fittrace,
+and review options and the reference image eliminates the find
+(find only occurs if there are no initial apertures).
+.ih
+REVISIONS
+.ls APALL V2.11
+The "apertures" parameter can be used to select apertures for resizing,
+recentering, tracing, and extraction. This parameter name was previously
+used for selecting apertures in the recentering algorithm. The new
+parameter name for this is now "aprecenter".
+
+The aperture ID table information may now be contained in the
+image header under the keywords SLFIBnnn.
+
+The "nsubaps" parameter now allows onedspec and echelle output formats.
+The echelle format is appropriate for treating each subaperture as
+a full echelle extraction.
+.le
+.ls APALL V2.10.3
+The dispersion axis parameter was moved to purely a package parameter.
+
+As a final step when computing a weighted/cleaned spectrum the total
+fluxes from the weighted spectrum and the simple unweighted spectrum
+(excluding any deviant and saturated pixels) are computed and a
+"bias" factor of the ratio of the two fluxes is multiplied into
+the weighted spectrum and the sigma estimate. This makes the total
+fluxes the same. In this version the bias factor is recorded in the logfile
+if one is kept. Also a check is made for unusual bias factors.
+If the two fluxes disagree by more than a factor of two a warning
+is given on the standard output and the logfile with the individual
+total fluxes as well as the bias factor. If the bias factor is
+negative a warning is also given and no bias factor is applied.
+In the previous version a negative (inverted) spectrum would result.
+.le
+.ih
+SEE ALSO
+apdefault, apfind, aprecenter, apresize, apedit, aptrace, apsum
+.endhelp
diff --git a/noao/twodspec/apextract/doc/apbackground.hlp b/noao/twodspec/apextract/doc/apbackground.hlp
new file mode 100644
index 00000000..93a49e42
--- /dev/null
+++ b/noao/twodspec/apextract/doc/apbackground.hlp
@@ -0,0 +1,79 @@
+.help apbackground Aug90 noao.twodspec.apextract
+
+.ce
+Background Determination
+
+
+Data from slit spectra allow the determination and subtraction
+of the background sky using information from regions near the object
+of interest. Background subtraction may also apply to cases of
+scattered light though other techniques for scattered light removal
+may be more appropriate. The APEXTRACT package provides for determining
+the background level at each wavelength (line or column along the dispersion
+axis) from a set of regions and extrapolating and subtracting the
+background at each pixel extracted from the object profile. The
+type of background used during extraction is specified by the parameter
+\fIbackground\fR. If the value "none" is used then no background is
+subtracted and any background parameters defined for an aperture are
+ignored. If the value is "average", "median", "minimum" or "fit" then a
+background is determined, including a variance estimate when using variance
+weighted extraction (see \fIapvariance\fR), and the subtracted background
+spectrum may be output if the \fIextras\fR parameter is set.
+
+The basic aperture definition structure used in the APEXTRACT package
+includes associated background regions and fitting parameters. The
+background regions are specified by a list of colon delimited ranges
+defined relative to the center of the aperture. There are generally
+two ranges, one on each side of the object, though one sided or more
+complex sets may be used to avoid contaminated or missing parts
+of the slit. The default ranges are defined by the parameter
+\fIb_sample\fR. Often the ranges are better set graphically using a
+cursor by invoking the 'b' option of the aperture editor.
+
+If the background type is "average", "median", or "minimum" then pixels
+occupying these regions are averaged, medianed, or the minimum found to
+produce a single background level for all object pixels at each wavelength.
+Note that the "average" choice does not exclude any pixels which may
+yield a background contaminated by cosmic rays. The "median" or "minimum"
+is recommended instead.
+
+If the background type is "fit" then a function is fit to the pixels in the
+background regions using the ICFIT options (see \fBicfit\fR). The
+parameter \fIb_naverage\fR may be used to compute averages or medians of
+groups or all of the points within each sample region. The fit is defined
+by a function type \fIb_function\fR; one of legendre polynomial, chebyshev
+polynomial, linear spline, or cubic spline, and function order
+\fIb_order\fR (number of polynomial terms or spline pieces). An
+interactive rejection of grossly deviant points from the fit may also be
+used. The fitted function can define a constant, sloped, or higher order
+background for the object pixels.
+
+Note that the background setting function, the 'b' key in \fBapedit\fR,
+may be used to set the background regions for all the background options
+but it will always show the result of a fit regardless of the background
+type.
+
+After determining a background by averaging, medianing, minimizing, or
+fitting, a box car smoothing step may be applied. The box car size is
+given by the parameter \fIskybox\fR. When the number of available
+background pixels is small, due to a small slit for instance, the noise
+introduced to the extracted object spectrum may be unsatisfactorily large.
+By smoothing the background one can reduce the noise when the background
+consists of a smooth continuum. The trade-off, however, is that near sharp
+features the smoothing will smear the features out and give a poorer
+subtraction of these features. One could extract both the object and
+background separately and apply a background smoothing separately using
+other image processing tools. However, this is not possible for variance
+weighted extraction because of the intimate connection between the
+background levels, the profile determination, and the variance estimates
+based on both. Thus, this smoothing feature is included.
+
+The background determined by the methods outlined above is actually
+subtracted as a separate step during extraction. The background
+is also used during profile fitting when cleaning or using variance
+weighted extraction. See \fBapvariance\fR and \fBapprofile\fR for
+further discussion.
+.ih
+SEE ALSO
+approfile apvariance apdefault icfit apall apsum
+.endhelp
diff --git a/noao/twodspec/apextract/doc/apdefault.hlp b/noao/twodspec/apextract/doc/apdefault.hlp
new file mode 100644
index 00000000..e17fe50d
--- /dev/null
+++ b/noao/twodspec/apextract/doc/apdefault.hlp
@@ -0,0 +1,95 @@
+.help apdefault Jul95 noao.twodspec.apextract
+.ih
+NAME
+apdefault -- Set default aperture parameters for the package
+.ih
+USAGE
+apdefault
+.ih
+PARAMETERS
+.ls lower = -5., upper = 5.
+Default lower and upper aperture limits relative to the aperture center.
+These limits are used for apertures found with \fBapfind\fR and when
+defining the first aperture in \fBapedit\fR.
+.le
+.ls apidtable = ""
+Aperture identification table. This may be either a text file or an
+image. A text file consisting of lines with an aperture number, beam
+number, and aperture title or identification. An image will contain the
+keywords SLFIBnnn with string value consisting of aperture number, beam
+number, optional right ascension and declination, and aperture title. This
+information is used to assign aperture information automatically in
+\fBapfind\fR and \fBapedit\fR.
+.le
+
+.ce
+Default Background Subtraction Parameters
+.ls b_function = "chebyshev"
+Default background fitting function. The fitting function types are
+"chebyshev" polynomial, "legendre" polynomial, "spline1" linear spline, and
+"spline3" cubic spline.
+.le
+.ls b_order = 1
+Default background function order. The order refers to the number of
+terms in the polynomial functions or the number of spline pieces in the spline
+functions.
+.le
+.ls b_sample = "-10:-6,6:10"
+Default background sample. The sample is given by a set of colon separated
+ranges each separated by either whitespace or commas. The string "*" refers
+to all points. Note that the background coordinates are relative to the
+aperture center and not image pixel coordinates so the endpoints need not
+be integer.
+.le
+.ls b_naverage = -3
+Default number of points to average or median. Positive numbers
+average that number of sequential points to form a fitting point.
+Negative numbers median that number, in absolute value, of sequential
+points. A value of 1 does no averaging and each data point is used in the
+fit.
+.le
+.ls b_niterate = 0
+Default number of rejection iterations. If greater than zero the fit is
+used to detect deviant fitting points and reject them before repeating the
+fit. The number of iterations of this process is given by this parameter.
+.le
+.ls b_low_reject = 3., b_high_reject = 3.
+Default background lower and upper rejection sigmas. If greater than zero
+points deviating from the fit below and above the fit by more than this
+number of times the sigma of the residuals are rejected before refitting.
+.le
+.ls b_grow = 0.
+Default reject growing radius. Points within a distance given by this
+parameter of any rejected point are also rejected.
+.le
+.ih
+DESCRIPTION
+This task sets the values of the default aperture parameters for the
+tasks \fBapedit\fR and \fBapfind\fR which define new apertures. For a
+description of the components of an aperture see the paper \fBThe
+APEXTRACT Package\fR. In \fBapedit\fR the default aperture limits and
+background parameters are only used if there are no other
+apertures defined. The aperture identification table is used when
+reordering the apertures with the 'o' key. When run the parameters are
+displayed and modified using the \fBeparam\fR task.
+
+The aperture limits and background fitting sample regions are defined
+relative to the center of the aperture. The background fitting parameters
+are those used by the ICFIT package. They may be modified interactively
+with the 'b' key in the task \fBapedit\fR. For more on background fitting
+and subtracting see \fBapbackground\fR.
+.ih
+EXAMPLES
+To review and modify the default aperture parameters:
+
+ cl> apdefault
+.ih
+.ih
+REVISIONS
+.ls APDEFAULT V2.11
+The aperture ID table information may now be contained in the
+image header under the keywords SLFIBnnn.
+.le
+SEE ALSO
+apbackground, apedit, apfind, icfit
+.endhelp
diff --git a/noao/twodspec/apextract/doc/apedit.hlp b/noao/twodspec/apextract/doc/apedit.hlp
new file mode 100644
index 00000000..324f6e5d
--- /dev/null
+++ b/noao/twodspec/apextract/doc/apedit.hlp
@@ -0,0 +1,374 @@
+.help apedit Sep96 noao.twodspec.apextract
+.ih
+NAME
+apedit -- Edit apertures
+.ih
+USAGE
+apedit input
+.ih
+PARAMETERS
+.ls input
+List of input images for which apertures are to be edited.
+.le
+.ls apertures = ""
+Apertures to recenter, resize, trace, and extract. This only applies
+to apertures read from the input or reference database. Any new
+apertures defined with the automatic finding algorithm or interactively
+are always selected. The syntax is a list comma separated ranges
+where a range can be a single aperture number, a hyphen separated
+range of aperture numbers, or a range with a step specified by "x<step>";
+for example, "1,3-5,9-12x2".
+.le
+.ls references = ""
+List of reference images to be used to define apertures for the input
+images. When a reference image is given it supersedes apertures
+previously defined for the input image. The list may be null, "", or
+any number of images less than or equal to the list of input images.
+If the reference image list is shorter than the input image list the
+last reference image is used for the remaining input images.
+There are three special words which may be used in place of an image
+name. The word "last" refers to the last set of apertures written to
+the database. The word "OLD" requires that an entry exist
+and the word "NEW" requires that the entry not exist for each input image.
+.le
+
+.ls interactive = no
+Run this task interactively? If the task is not run interactively then
+all user queries are suppressed and interactive aperture editing is
+disabled.
+.le
+.ls find = no
+Find the spectra and define apertures automatically? In order for
+spectra to be found automatically there must be no apertures for the
+input image or reference image defined in the database.
+.le
+.ls recenter = no
+Recenter the apertures?
+.le
+.ls resize = no
+Resize the apertures?
+.le
+.ls edit = yes
+Edit the apertures? The \fIinteractive\fR parameter must also be yes.
+.le
+
+.ls line = INDEF
+The dispersion line (line or column perpendicular to the dispersion axis) to
+be graphed. A value of INDEF uses the middle of the image.
+.le
+.ls nsum = 10
+Number of dispersion lines to be summed or medianed. The lines are taken
+around the specified dispersion line. A positive nsum selects a sum of
+lines and a negative selects a median of lines.
+.le
+.ls width = 5.
+Width of spectrum profiles. This parameter is used for the profile
+centering algorithm in this and other tasks.
+.le
+.ls radius = 5.
+The profile centering error radius for the centering algorithm.
+.le
+.ls threshold = 0.
+Centering threshold for the centering algorithm. The range of pixel intensities
+near the initial centering position must exceed this threshold.
+.le
+.ih
+ADDITIONAL PARAMETERS
+I/O parameters and the default dispersion axis are taken from the
+package parameters, the default aperture parameters are taken from the
+task \fBapdefault\fR. Parameters for the various functions of finding,
+recentering, and resizing are taken from the parameters for the
+appropriate task.
+
+When this operation is performed from the task \fBapall\fR all parameters
+except the package parameters are included in that task.
+.ih
+CURSOR KEYS
+When editing the apertures interactively the following cursor keys are
+available.
+
+.nf
+? Print help
+a Toggle the ALL flag
+b an Set background fitting parameters
+c an Center aperture(s)
+d an Delete aperture(s)
+e an Extract spectra (see APSUM)
+f Find apertures up to the requested number (see APFIND)
+g an Recenter aperture(s) (see APRECENTER)
+i n Set aperture ID
+j n Set aperture beam number
+l ac Set lower limit of current aperture at cursor position
+m Define and center a new aperture on the profile near the cursor
+n Define a new aperture centered at the cursor
+o n Enter desired aperture number for cursor selected aperture and
+ remaining apertures are reordered using apidtable and maxsep
+ parameters (see APFIND for ordering algorithm)
+q Quit
+r Redraw the graph
+s an Shift the center(s) of the current aperture to the cursor
+ position
+t ac Trace aperture positions (see APTRACE)
+u ac Set upper limit of current aperture at cursor position
+w Window the graph using the window cursor keys
+y an Set aperture limits to intercept the data at the cursor y
+ position
+z an Resize aperture(s) (see APRESIZE)
+. n Select the aperture nearest the cursor for current aperture
++ c Select the next aperture (in ID) to be the current aperture
+- c Select the previous aperture (in ID) to be the current aperture
+I Interrupt task immediately. Database information is not saved.
+.fi
+
+The letter a following the key indicates if all apertures are affected when
+the ALL flag is set. The letter c indicates that the key affects the
+current aperture while the letter n indicates that the key affects the
+aperture whose center is nearest the cursor.
+.ih
+COLON COMMANDS
+
+.nf
+:show [file] Print a list of the apertures (default STDOUT)
+:parameters [file] Print current parameter values (default STDOUT)
+:read [name] Read from database (default current image)
+:write [name] Write to database (default current image)
+.fi
+
+The remaining colon commands are task parameters and print the current
+value if no value is given or reset the current value to that specified.
+Use :parameters to see current parameter values.
+
+.nf
+:apertures :apidtable :avglimits :b_function
+:b_grow :b_high_reject :b_low_reject :b_naverage
+:b_niterate :b_order :b_sample :background
+:bkg :center :clean :database
+:extras :gain :image :line
+:llimit :logfile :lower :lsigma
+:maxsep :minsep :npeaks :nsubaps
+:nsum :order :parameters :peak
+:plotfile :r_grow :radius :read
+:readnoise :saturation :shift :show
+:skybox :t_function :t_grow :t_high_reject
+:t_low_reject :t_naverage :t_niterate :t_nsum
+:t_order :t_sample :t_step :t_width
+:threshold :title :ulimit :upper
+:usigma :weights :width :write
+:ylevel :t_nlost
+.fi
+.ih
+DESCRIPTION
+For each image in the input image list, apertures are defined and edited
+interactively. The aperture editor is invoked when the parameters
+\fIinteractive\fR and \fIedit\fR are both yes. When this is the case
+the task will query whether to edit each image. The responses are
+"yes", "no", "YES", and "NO", where the upper case responses suppress
+queries for all following images.
+
+When the aperture editor is entered a graph of the image lines or
+columns specified by the parameters \fIline\fR and \fInsum\fR is
+drawn. In the \fBapextract\fR package a dispersion line is either a
+line or column in the image at one point along the dispersion axis.
+The dispersion axis may be defined in the image header under the
+keyword DISPAXIS or by the package parameter \fIdispaxis\fR. The
+parameter \fBnsum\fR determines how many dispersion lines surrounding
+the specified dispersion line are summed or medianed. This improves the
+signal in the profiles of weaker spectra. Once the graph is drawn an
+interactive cursor loop is entered. The set of cursor keys and colon
+commands is given above and may be printed when the task is running using
+the '?' key. The CURSOR MODE keys and graph formatting options are also
+available (see \fBcursor\fR and \fBgtools\fR).
+
+A status line, usually at the bottom of the graphics terminal,
+indicates the current aperture and shows the ALL flag, 'a' key, if set. The
+concept of the current aperture is used by several of the aperture
+editing commands. Other commands operate on the aperture whose center
+is nearest the cursor. It is important to know which commands operate
+on the current aperture and which operate on the nearest aperture to
+the cursor.
+
+The cursor keys and colon commands are used to define new apertures,
+delete existing apertures, modify the aperture number, beam number,
+title, center, and limits, set background fitting parameters, trace the
+positions of the spectra in the apertures, and extract aperture
+spectra. When creating new apertures default parameters are supplied
+in two ways; if no apertures are defined then the default parameters
+are taken from the task \fBapdefault\fR while if there is a current
+aperture then a copy of its parameters are made.
+
+The keys for creating a new aperture are 'm' and 'n' and 'f'. The key
+'m' marks a new aperture and centers the aperture on the profile
+nearest the cursor. The centering algorithm is described under the
+help topic \fBcenter1d\fR and the parameters controlling the centering are
+\fIwidth\fR, \fIradius\fR, and \fIthreshold\fR. The key 'n' defines a
+new aperture at the position of the cursor without centering. This is
+used if there is no spectrum profile such as when defining sky apertures
+or when defining apertures in extended profiles. The 'f' key finds new
+apertures using the algorithm described in the task \fBapfind\fR. The
+number of apertures found in this way is limited by the parameter
+\fBnfind\fR and the number includes any previously defined
+apertures. The new aperture number, beam number, and title are assigned using
+the aperture assignment algorithm described in \fBapfind\fR.
+
+The aperture number for the aperture \fInearest\fR the cursor is changed
+with the 'j' key and the beam number is changed with the 'k' key. The
+user is prompted for a new aperture number or beam number. The
+aperture title may be set or changed with the :title colon command.
+
+The 'o' key may be used to reorder or correct the aperture
+identifications and beam numbers. This is useful if the aperture
+numbers become disordered due to deletions and additions or if the
+first spectrum is missing when using the automatic identification
+algorithm. An aperture number is requested for the aperture pointed to
+by the cursor. The remaining apertures are reordered relative to this
+aperture number. There is a aperture number, beam number, and title
+assignment algorithm which uses information about the maximum
+separation between consecutive apertures, the direction of increasing
+aperture numbers, and an optional aperture identification table. See
+\fBapfind\fR for a description of the algorithm.
+
+After defining a new aperture it becomes the current aperture. The
+current aperture is indicated on the status line and the '.', '+', and
+'-' keys are used to select a new current aperture.
+
+Apertures are deleted with 'd' key. The aperture \fInearest\fR the
+cursor is deleted.
+
+The aperture center may be changed with the 'c', 's', and 'g' keys and the
+":center value" colon command. The 'c' key applies the centering algorithm
+to the aperture \fInearest\fR the colon. The 's' key shifts the center
+of the \fIcurrent\fR aperture to the position of the cursor. The 'g'
+applies the \fBaprecenter\fR algorithm. The :center command sets the
+center of the \fIcurrent\fR aperture to the value specified. Except
+for the last option these commands may be applied to all apertures
+if the ALL flag is set.
+
+The aperture limits are defined relative to the aperture center. The
+limits may be changed with the 'l', 'u', 'y', and 'z' keys and with the
+":lower value" and ":upper value" commands. The 'l' and 'u' keys set
+the lower and upper limits of the \fIcurrent\fR aperture at the position
+of the cursor. The colon commands allow setting the limits explicitly.
+The 'y' key defines both limits for the \fInearest\fR aperture as
+points at which the y cursor position intercepts the data profile.
+This requires that the aperture include a spectrum profile and that
+the y cursor value lie below the peak of the profile. The 'z'
+key applies the \fBapresize\fR algorithm. Except for the colon
+commands these commands may be applied to all apertures if the ALL
+flag is set.
+
+The key 'b' modifies the background fitting parameters for the aperture
+\fInearest\fR the cursor. The default background parameters are
+specified by the task \fBapdefault\fR. Note that even though
+background parameters are defined, background subtraction is not
+performed during extraction unless specified.
+When the 'b' key is used the \fBicfit\fR graphical interface is entered
+showing the background regions and function fit for the current image
+line. Note that the background regions are specified relative to
+the aperture center and follows changes in the aperture position.
+
+The two types of
+extraction which may be specified are to average all points within
+a set of background regions or fit a function to the points in
+the background regions. In the first case only the background sample
+parameter is used. In the latter case the other parameters are
+also used in conjunction with the \fBicfit\fR function fitting commands.
+See \fBapbackground\fR for more on the background parameters.
+
+Each aperture may have different background
+fitting parameters but newly defined apertures inherit the background
+fitting parameters of the last current aperture. This will usually be
+satisfactory since the background regions are defined relative to the
+aperture center rather than in absolute coordinates. If the ALL flag
+is set then all apertures will be given the same background
+parameters.
+
+The algorithms used in the tasks \fBapfind, aprecenter, apresize, aptrace\fR,
+and \fBapsum\fR are available from the editor with the keys 'f', 'g', 'z',
+'t', and 'e'
+respectively. Excluding finding, if the ALL flag is not set then the
+nearest aperture
+to the cursor is used. This allows selective recentering, resizing,
+tracing and extracting.
+If the ALL flag is set then all apertures are traced or extracted.
+When extracting the output, rootname and profile name are queried.
+
+Some general purpose keys window the graph 'w' using the \fBgtools\fR
+commands, redraw the graph 'r', and quit 'q'.
+
+The final cursor key is the 'a' key. The cursor keys which modify the
+apertures were defined as operating on either the aperture nearest the
+cursor or the current aperture. The 'a' key allows these keys to
+affect all the apertures simultaneously. The 'a' key sets a flag which
+is shown on the status line when it is set. When set, the operation on
+one aperture is duplicated on the remaining apertures. The operations
+which apply to all apertures are set background 'b', center 'c', delete
+'d', extract 'e', recenter 'g', set lower limit 'l', shift 's', trace
+'t', set upper limit 'u', set limits at the y cursor 'y', and resize
+'z'. The 'b', 'l', 's', and 'u' keys first set the background,
+aperture limits, or shift for the appropriate aperture and then are
+applied to the other apertures relative to their centers.
+
+All the parameters used in any of the operations may be examined or
+changed through colon commands. The :parameters command lists all
+parameter values and :show lists the apertures. The :read and :write
+are used to force an update or save the current apertures and to read
+apertures for the current image or from some other image. The commands
+all have optional arguments. For the commands which show information
+the argument specifies a file to which the information is to be
+written. The default is the standard output. The database read and
+write and the change image commands take an image name. If an image
+name is not given for the read and write commands the
+current image name is used. The change image command default is to
+print the current image name. The remaining commands take a value. If
+a value is not given then the current value is printed.
+
+The aperture editor may be selected from nearly every task using the
+\fBedit\fR parameter.
+.ih
+EXAMPLES
+The aperture editor is a very flexible and interactive tool
+for which it is impossible illustrate all likely uses. The following
+give some simple examples.
+
+1. To define and edit apertures for image "n1.001":
+
+ cl> apedit n1.001
+
+2. To define apertures for one image and then apply them to several other
+images:
+
+.nf
+ cl> apedit n1.* ref=n1.001
+ Edit apertures for n1.001? (yes)
+ Edit apertures for n1.002? (yes) NO
+.fi
+
+Answer "yes" to the first query for editing n1.001. To
+the next query (for n1.002) respond with "NO". The remaining
+images then will not be edited interactively. Note that after
+defining the apertures for n1.001 they are recorded in the database
+and subsequent images will be able to use them as reference apertures.
+
+3. Using the ":image name" and ":read image" colon commands and the
+'f', 'g', 'z', 't' and 'e' keys the user can perform all the functions
+available in the package without ever leaving the editor. The 'a' key
+to set the ALL flag is very useful when dealing with many spectra in a
+single image.
+.ih
+.ih
+REVISIONS
+.ls APEDIT V2.11
+The "apertures" parameter can be used to select apertures for resizing,
+recentering, tracing, and extraction. This parameter name was previously
+used for selecting apertures in the recentering algorithm. The new
+parameter name for this is now "aprecenter".
+
+The aperture ID table information may now be contained in the
+image header under the keywords SLFIBnnn.
+.le
+SEE ALSO
+.nf
+apdefault, apfind, aprecenter, apresize, aptrace, apsum, apall
+center1d, cursor, gtools, icfit
+.fi
+.endhelp
diff --git a/noao/twodspec/apextract/doc/apextract.hlp b/noao/twodspec/apextract/doc/apextract.hlp
new file mode 100644
index 00000000..401d93e7
--- /dev/null
+++ b/noao/twodspec/apextract/doc/apextract.hlp
@@ -0,0 +1,365 @@
+.help package Feb94 noao.twodspec.apextract
+.ih
+NAME
+apextract -- Identify, manipulate, and extract spectra in 2D images
+.ih
+USAGE
+apextract
+.ih
+PARAMETERS
+.ls dispaxis = 2
+Image axis along which the spectra dispersion run. The dispersion axis
+is 1 when the dispersion is along lines so that spectra are horizontal
+when displayed normally. The dispersion axis is 2 when the dispersion
+is along columns so that spectra are vertical when displayed normally.
+This parameter is superseded when the dispersion axis is defined in
+the image header by the parameter DISPAXIS.
+.le
+.ls database = "database"
+Database for storing aperture definitions. Currently the database is
+a subdirectory of text files with prefix "ap" followed by the entry name,
+usually the image name.
+.le
+.ls verbose = no
+Print detailed processing and log information? The output is to the
+standard output stream which is the user's terminal unless redirected.
+.le
+.ls logfile = ""
+Text logfile of operations performed. If a file name is specified
+log and history information produced by all the tasks in the package
+is appended to the file.
+.le
+.ls plotfile = ""
+Binary plot metacode file of aperture locations, traces, rejected points,
+etc. If a file name is given metacode plots are appended. The contents
+of the file may be manipulated with the tasks in the \fBplot\fR package.
+The most common is \fBgkimosaic\fR. Special plotfile names may be used
+to select only particular plots or plots not normally output. These are
+debugall, debugfitspec, debugaps, debugspec, debugfits, debugtrace,
+and debugclean which plot everything, the fitted spectrum, the apertures,
+the extracted spectrum, profile fit plots, the trace, and the rejected
+points during cleaned extraction.
+.le
+.ls version = "APEXTRACT V3.0: August 1990"
+Version of the package. This is the third major version of the package.
+.le
+.ih
+DESCRIPTION
+The primary function of the \fBapextract\fR package is the extraction of
+spectra from two dimensional formats to one dimensional formats. In
+other words, the pixels at each wavelength are summed, possibly
+subtracting a background or sky from other pixels at that wavelength,
+to produce a vector of spectral fluxes as a function of wavelength.
+It has become common to have many spectra in one two dimensional
+image produced by instruments using echelles, fibers, and aperture
+masks. Thus, the package provides many features for the efficient
+extractions of multiple spectra as well as single spectra. There are
+also some additional, special purpose tasks for modeling spectra
+and using the aperture definitions, described below,
+to create masks and modified flat field images.
+
+The package assumes that one of the image axes is the dispersion axis,
+specified by the \fIdispaxis\fR package parameter or image header
+parameter of the same name, and the other is the spatial axes.
+This means that all pixels at the same column or line (the
+orientation may be in either direction) are considered to be at the
+same wavelength. Even if this is not exactly
+true the resolution loss is generally quite small and the simplicity and
+absence of interpolation problems justify this approach. The
+alternatives are to rotate the image with \fBrotate\fR or use the more
+complex \fBlongslit\fR package. Though extraction is strictly along
+lines and columns the position of the spectrum along the spatial axis
+is allowed to shift smoothly with wavelength. This accounts for small
+misalignments and distortions.
+
+The two dimensional regions occupied by the spectra are defined by
+digital apertures having a fixed width but with spatial position smoothly
+varying with wavelength. The apertures have a number of attributes.
+The aperture definitions are created and modified by the tasks in this
+package and stored in a database specified by the parameter \fIdatabase\fR.
+The database is currently a directory containing simple text files
+in a human readable format. The elements of an aperture definition
+are as follows.
+
+
+.ce
+Elements of an Aperture Definition
+.ls aperture
+An integer aperture identification number. The aperture number
+must be unique within a set of apertures. The aperture number is
+the primary means of referencing an aperture and the resulting
+extracted spectra. The aperture numbers are part of the extracted
+spectra image headers. The numbers may be any integer and in any order
+but the most typical case is to have sequential numbers beginning
+with 1.
+.le
+.ls beam
+An integer beam number. The beam number need not be unique; i.e.
+several apertures may have the same beam number. The beam numbers are
+recorded in the image headers of the extracted spectra. The beam
+number is often used to identify types of spectra such as object,
+sky, arc, etc.
+.le
+.ls center
+A pair of numbers specifying the center of the aperture along the spatial
+and dispersion axes in the two dimensional image. The center along
+the dispersion is usually defined as the middle of the image. The
+rest of the aperture parameters are defined relative to the aperture
+center making it easy to move apertures.
+.le
+.ls low, high
+Pairs of numbers specifying the lower and upper limits of the
+aperture relative to the center along the spatial and dispersion axes.
+The lower limits are usually negative and the upper limits positive
+but there is no actual restriction; i.e. the aperture can actually
+be offset from the center position. Currently the dispersion
+aperture limits are such that the entire length of the image along the
+dispersion axis is used. In the future this definition can be
+easily used for objective prism spectra.
+.le
+.ls curve, axis
+An IRAF "curfit" function specifying a shift to be added to the center
+position along the spatial axis, given by the axis parameter which is
+the complement of the dispersion axis parameter \fIdispaxis\fR, as a
+function of the dispersion coordinate. This trace function is one of
+the standard IRAF \fBicfit\fR types; a legendre polynomial, a chebyshev
+polynomial, a linear spline, or a cubic spline.
+.le
+.ls background
+Background definition parameters. For the "average" background subtraction
+option only the set of background sample regions (defined relative to
+the aperture center) are used. For the "fit" option the parameters
+are those used by the \fBicfit\fR package for fitting a function to
+the points in the background sample regions.
+.le
+
+This information as well as the image (or database entry) name are stored
+in a text file, with name given by the prefix "ap" followed by the entry
+name, in the database directory. An example with the special entry name
+"last", stored in the file "database$aplast", is given below. The "begin"
+line marks the beginning of an aperture definition.
+
+
+.ce
+Sample Aperture Database Entry
+
+.nf
+# Fri 17:43:41 03-Aug-90
+begin aperture last 1 70.74564 256.
+ image last
+ aperture 1
+ beam 1
+ center 70.74564 256.
+ low -5. -255.
+ high 5. 256.
+ background
+ xmin -100.
+ xmax 100.
+ function chebyshev
+ order 1
+ sample -10:-6,6:10
+ naverage -3
+ niterate 0
+ low_reject 3.
+ high_reject 3.
+ grow 0.
+ axis 1
+ curve 5
+ 2.
+ 1.
+ 1.
+ 512.
+ 0.
+.fi
+
+There are a number of logical functions which may be performed to
+create, modify, and use the aperture definitions. These functions
+are:
+.ls o
+Automatically find a specified number of spectra and assign default
+apertures. Apertures may also be inherited from another image or
+defined using an interactive graphical interface called the \fIaperture
+editor\fR.
+.le
+.ls o
+Recenter apertures on the image spectrum profiles.
+.le
+.ls o
+Resize apertures based on spectrum profile width.
+.le
+.ls o
+Interactively define or adjust aperture definitions using a graphical
+interface called the \fIaperture editor\fR. All function may also
+be performed from this editor and, so, provides an alternative
+method of processing and extracting spectra.
+.le
+.ls o
+Trace the positions of spectra profiles from a starting image line
+or column to other image lines or columns and fit a smooth function.
+The trace function is used to shift the center of the apertures
+at each dispersion point in the image.
+.le
+.ls o
+Extract the flux in the apertures into one dimensional spectra in various
+formats. This includes possible background subtraction, variance
+weighting, and bad pixel rejection.
+.le
+
+The package is logically organized around these functions. Each
+function has a task devoted to it. The description of the parameters
+and algorithms for each function are organized according to these
+tasks; namely under the help topics \fBapdefault, apfind, aprecenter,
+apresize, apedit, aptrace\fR, and \fBapsum\fR. However, each task has
+parameters to allow selecting some or all of the other functions, hence
+it is not necessary to use the individual tasks and often it is more
+convenient to use just the extraction task for all operations. It is
+also possible to perform all the functions from within a graphical
+interface called the aperture editor. This is usually only used to
+define and modify aperture definitions but it also has the capability
+to trace spectra and extract them.
+
+Each of the functions has many different options and parameters. When
+broken down into individual tasks the parameters are also sorted by
+their function though there are then some mutual interdependencies.
+This parameter decomposition was what was available prior to the
+addition of the task \fBapall\fR. This is the central task of the
+package which performs any and all of the functions required for the
+extraction of spectra and also collects all the parameters into one
+parameter set. It is recommended that \fBapall\fR be used because it
+collects all the parameters in one place eliminating confusion over
+where a particular parameter is defined.
+
+In summary, the package consists of a number of logical functions which
+are documented by the individual tasks named for that function, but the
+functions are also integrated into each task and the aperture editor to
+providing many different ways for the user to choose to perform the
+functions.
+
+The package menu and help summary is shown below.
+
+
+.ce
+The APEXTRACT Package Tasks
+
+.nf
+ apall apedit apflatten aprecenter apsum
+ apdefault apfind apmask apresize aptrace
+ apdemos apfit apnormalize apscatter
+
+ apall - Extract 1D spectra (all parameters in one task)
+ apdefault - Set the default aperture parameters and apidtable
+ apdemos - Various tutorial demonstrations
+ apedit - Edit apertures interactively
+ apfind - Automatically find spectra and define apertures
+ apfit - Fit 2D spectra and output the fit, difference,
+ or ratio
+ apflatten - Remove overall spectral and profile shapes from
+ flat fields
+ apmask - Create and IRAF pixel list mask of the apertures
+ apnormalize - Normalize 2D apertures by 1D functions
+ aprecenter - Recenter apertures
+ apresize - Resize apertures
+ apscatter - Fit and subtract scattered light
+ apsum - Extract 1D spectra
+ aptrace - Trace positions of spectra
+
+ Additional topics
+
+ apbackground - Background subtraction algorithms
+ apextract - Package parameters and general description of
+ package
+ approfiles - Profile determination algorithms
+ apvariance - Extractions, variance weighting, cleaning, and
+ noise model
+.fi
+
+The extracted spectra are recorded in one, two, or three dimensional
+images depending on the \fIformat\fR and \fIextras\fR parameters. If
+the \fIextras\fR parameter is set to yes the formats are three
+dimensional with each plane in the third dimension containing
+associated information for the spectra in the first plane. See
+\fBapsum\fR for further details. When \fIextras\fR=no only the
+extracted spectra are output.
+
+If the format parameter is "onedspec" the output extractions are one
+dimensional images with names formed from an output rootname and an
+aperture number extension; i.e. root.0001 for aperture 1. There will
+be as many output images as there are apertures for each input image,
+all with the same output rootname but with different aperture
+extensions. This format is provided to be compatible with the original
+format used by the \fBonedspec\fR package.
+
+If the format parameter is "echelle" or "multispec" the output aperture
+extractions are put into a two dimensional image with a name formed from
+the output rootname and the extension ".ec" or ".ms". Each line in
+the output image corresponds to one aperture. Thus in this format
+there is one output image for each input image. These are the preferred
+output formats for reasons of compactness, ease of handling, and efficiency.
+These formats are compatible with the \fBonedspec\fR, \fBechelle\fR, and
+\fBmsred\fR packages. The format is a standard IRAF image with
+specialized image header keywords. Below is an example of the keywords.
+
+
+.ce
+MULTISPEC/ECHELLE Format Image Header Keywords
+
+.nf
+ ap> imhead test.ms
+ test.ms[512,2,4][real]: Title
+ BANDID1 = 'spectrum - background fit, weights variance, clean yes'
+ BANDID2 = 'spectrum - background fit, weights none, clean no'
+ BANDID3 = 'background - background fit'
+ BANDID4 = 'sigma - background fit, weights variance, clean yes'
+ APNUM1 = '1 1 87.11 94.79'
+ APNUM2 = '2 1 107.11 114.79'
+ APID1 = 'Galaxy center'
+ APID2 = 'Galaxy edge'
+ WCSDIM = 3
+ CTYPE1 = 'PIXEL '
+ CTYPE2 = 'LINEAR '
+ CTYPE3 = 'LINEAR '
+ CRVAL1 = 1.
+ CRPIX1 = 1.
+ CD1_1 = 1.
+ CD2_2 = 1.
+ CD3_3 = 1.
+ LTM1_1 = 1.
+ LTM2_2 = 1.
+ LTM3_3 = 1.
+ WAT0_001= 'system=equispec
+ WAT1_001= 'wtype=linear label=Pixel
+ WAT2_001= 'wtype=linear
+ WAT3_001= 'wtype=linear
+.fi
+
+The BANDIDn keywords describe the various elements of the 3rd dimension.
+Except for the first one the other bands only occur when \fIextras\fR is
+yes and when sky subtraction and/or variance and cleaning are done. The
+relation between the line and the aperture numbers is given by the header
+parameters APNUMn where n is the line and the value gives extraction and
+coordinate information about the spectrum. The first field is the aperture
+number and the second is the beam number. After dispersion calibration of
+echelle format spectra the beam number becomes the order number. The other
+two numbers are the aperture limits at the line or column at which the
+aperture was defined.
+The APID keywords provide an optional title for each extracted spectrum
+in addition to the overall image title.
+
+The rest of the keywords are part of the IRAF World Coordinate System
+(WCS). If the image being extracted has been previously calibrated
+(say with \fBlongslit.transform\fR) then the dispersion coordinates
+will be carried in CRVAL1 and CD1_1.
+
+There is one other value for the format parameter, "strip". This produces
+two dimensional extractions rather than one dimensional extractions.
+Each aperture is output to a two dimensional image with a width set by the
+nearest integer which includes the aperture. The output names are
+generated in the same way as for "onedspec" format. The aperture is
+shifted by interpolation so that it is exactly aligned with the image
+columns. If not variance weighting the actual image data is output
+with appropriate shifting while for variance weighting and/or cleaning
+the profile model is output (similar to \fBapfit\fR except for being
+aligned). This format is that provided in the previous version of
+the package by the \fBapstrip\fR task. It is now relegated to a
+special case.
+.endhelp
diff --git a/noao/twodspec/apextract/doc/apextractsys.hlp b/noao/twodspec/apextract/doc/apextractsys.hlp
new file mode 100644
index 00000000..a93d9f56
--- /dev/null
+++ b/noao/twodspec/apextract/doc/apextractsys.hlp
@@ -0,0 +1,415 @@
+.help apextract Aug90 noao.twodspec.apextract
+
+.ce
+APEXTRACT System Notes
+
+
+\fBIntroduction\fR
+
+The \fBapextract\fR package is a complex package with a simple
+purpose, the extraction of one dimensional spectra from two dimensional
+images. The complexity arises from the many algorithms and parameters
+involved. To manage the complexity of the algorithms, features, parameters,
+functionality, and documentation the package has been organized in terms
+of logical functions which may be invoked in a number of ways. The
+logical functions are:
+.ls o
+Automatically find a specified number of spectra and assign default
+apertures. Apertures may also be inherited from another image or
+defined using an interactive graphical interface called the \fIaperture
+editor\fR.
+.le
+.ls o
+Recenter apertures on the image spectrum profiles.
+.le
+.ls o
+Resize apertures based on spectrum profile width.
+.le
+.ls o
+Interactively define or adjust aperture definitions using a graphical
+interface called the \fIaperture editor\fR. All function may also
+be performed from this editor and, so, provides an alternative
+method of processing and extracting spectra.
+.le
+.ls o
+Trace the positions of spectra profiles from a starting image line
+or column to other image lines or columns and fit a smooth function.
+The trace function is used to shift the center of the apertures
+at each dispersion point in the image.
+.le
+.ls o
+Extract the flux in the apertures into one dimensional spectra in various
+formats. This includes possible background subtraction, variance
+weighting, and bad pixel rejection.
+.le
+
+The package is logically organized around these functions. Each
+function has a task devoted to it. The description of the parameters
+and algorithms for each function are organized according to these
+tasks; namely under the help topics \fBapdefault, apfind, aprecenter,
+apresize, apedit, aptrace\fR, and \fBapsum\fR. However, each task has
+parameters to allow selecting some or all of the other functions, hence
+it is not necessary to use the individual tasks and often it is more
+convenient to use just the extraction task for all operations. It is
+also possible to perform all the functions from within a graphical
+interface called the aperture editor. This is usually only used to
+define and modify aperture definitions but it also has the capability
+to trace spectra and extract them.
+
+Each of the functions has many different options and parameters. When
+broken down into individual tasks the parameters are also sorted by
+their function though there are then some mutual interdependencies.
+This parameter decomposition was what was available prior to the
+addition of the task \fBapall\fR. This is the central task of the
+package which performs any and all of the functions required for the
+extraction of spectra and also collects all the parameters into one
+parameter set. It is recommended that \fBapall\fR be used because it
+collects all the parameters in one place eliminating confusion over
+where a particular parameter is defined.
+
+In summary, the package consists of a number of logical functions which
+are documented by the individual tasks named for that function, but the
+functions are also integrated into each task and the aperture editor to
+providing many different ways for the user to choose to perform the
+functions.
+
+This document describes some of the implementation details and features
+which are hidden from the normal user.
+
+
+\fBParameters\fR
+
+The tasks actually use hidden parameter sets for almost all parameters.
+To see all the parameter sets type
+
+.nf
+ ap> ?_ apextract
+.fi
+
+The relation between the tasks and the hidden parameter sets is given below.
+
+.nf
+ PSET TASK
+ apparams - apdefault, apfind, aprecenter, apresize,
+ apedit, aptrace, apsum, apmask, apscatter
+ apall1 - apall
+ apfit1 - apfit
+ apflat1 - apflatten
+ apnorm1 - apnormalize
+.fi
+
+The hidden parameter sets may be viewed in any of the normal ways
+\fBeparam\fR, \fBlparam\fR, or just by typing their name, except
+their names may not be abbreviated. Their purpose is to redirect
+parameters to visible parameter sets, to hide some parameters which
+are not meant to be changed by the user, and to include parameters
+used for queries.
+
+Most of the redirected parameters go to a single visible parameter set
+or to package parameters.
+The interesting exception is \fBapparams\fR which provides the
+parameter linkage between the various functional tasks like
+\fBapfind\fR, \fBaptrace\fR, \fBapsum\fR, etc. Below is a reproduction
+of this parameter set.
+
+.ce
+APPARAMS Hidden Parameter Set
+
+.nf
+ I R A F
+ Image Reduction and Analysis Facility
+PACKAGE = apextract
+ TASK = apparams
+
+(format = )_.format) Extracted spectra format
+(extras = )apsum.extras) Extract sky, sigma, etc.?
+(dbwrite= yes) Write to database?
+(initial= yes) Initialize answers?
+(verbose= )_.verbose) Verbose output?
+
+ # DEFAULT APERTURE PARAMETERS
+
+(upper = )apdefault.upper) Upper aperture limit relative to center
+(apidtab= )apdefault.apidtable) Aperture ID table (optional)
+
+ # DEFAULT BACKGROUND PARAMETERS
+
+(b_funct= )apdefault.b_function) Background function
+(b_order= )apdefault.b_order) Background function order
+(b_sampl= )apdefault.b_sample) Background sample regions
+(b_naver= )apdefault.b_naverage) Background average or median
+(b_niter= )apdefault.b_niterate) Background rejection iterations
+(b_low_r= )apdefault.b_low_reject) Background lower rejection sigma
+(b_high_= )apdefault.b_high_reject) Background upper rejection sigma
+(b_grow = )apdefault.b_grow) Background rejection growing radius
+
+ # APERTURE CENTERING PARAMETERS
+
+(width = )apedit.width) Profile centering width
+(radius = )apedit.radius) Profile centering radius
+(thresho= )apedit.threshold) Detection threshold for profile centering
+
+ # AUTOMATIC FINDING AND ORDERING PARAMETERS
+
+(nfind = )apfind.nfind) Number of apertures to be found automatically
+(minsep = )apfind.minsep) Minimum separation between spectra
+(maxsep = )apfind.maxsep) Maximum separation between spectra
+(order = )apfind.order) Order of apertures
+
+ # RECENTERING PARAMETERS
+
+(apertur= )aprecenter.apertures) Select apertures
+(npeaks = )aprecenter.npeaks) Select brightest peaks
+(shift = )aprecenter.shift) Use average shift instead of recentering?
+
+ # RESIZING PARAMETERS
+
+(llimit = )apresize.llimit) Lower aperture limit relative to center
+(ulimit = )apresize.ulimit) Upper aperture limit relative to center
+(ylevel = )apresize.ylevel) Fraction of peak or intensity for automatic widt(peak = )apresize.peak) Is ylevel a fraction of the peak?
+(bkg = )apresize.bkg) Subtract background in automatic width?
+(r_grow = )apresize.r_grow) Grow limits by this factor
+(avglimi= )apresize.avglimits) Average limits over all apertures?
+
+ # EDITING PARAMETERS
+
+e_output= Output spectra rootname
+e_profil= Profile reference image
+(t_nsum = )aptrace.nsum) Number of dispersion lines to sum
+(t_step = )aptrace.step) Tracing step
+(t_width= )apedit.width) Centering width for tracing
+(t_funct= )aptrace.function) Trace fitting function
+(t_order= )aptrace.order) Trace fitting function order
+(t_sampl= )aptrace.sample) Trace sample regions
+(t_naver= )aptrace.naverage) Trace average or median
+(t_niter= )aptrace.niterate) Trace rejection iterations
+(t_low_r= )aptrace.low_reject) Trace lower rejection sigma
+(t_high_= )aptrace.high_reject) Trace upper rejection sigma
+(t_grow = )aptrace.grow) Trace rejection growing radius
+
+ # EXTRACTION PARAMETERS
+
+(backgro= )apsum.background) Background to subtract (none|average|fit)
+(skybox = )apsum.skybox) Box car smoothing length for sky
+(weights= )apsum.weights) Extraction weights (none|variance)
+(clean = )apsum.clean) Detect and replace bad pixels?
+(niterat= 2) Number of profile fitting iterations
+(saturat= )apsum.saturation) Saturation level
+(readnoi= )apsum.readnoise) Read out noise sigma (photons)
+(gain = )apsum.gain) Photon gain (photons/data number)
+(lsigma = )apsum.lsigma) Lower rejection threshold
+(usigma = )apsum.usigma) Upper rejection threshold
+(maxtilt= 3) Maximum excursion for line/column fitting
+(polysep= 0.95) Marsh algorithm polynomial spacing
+(polyord= 10) Marsh algorithm polynomial order
+(nsubaps= )apsum.nsubaps) Number of subapertures per aperture
+
+ # ANSWER PARAMETERS
+
+(ansclob= no)
+(ansclob= no)
+(ansdbwr= yes)
+(ansdbwr= yes)
+(ansedit= yes)
+(ansextr= yes)
+(ansfind= yes)
+(ansfit = yes)
+(ansfits= yes)
+(ansfits= yes)
+(ansfits= yes)
+(ansfits= yes)
+(ansfitt= yes)
+(ansfitt= yes)
+(ansflat= yes)
+(ansmask= yes)
+(ansnorm= yes)
+(ansrece= yes)
+(ansresi= yes)
+(ansrevi= yes)
+(ansrevi= yes)
+(ansscat= yes)
+(anssmoo= yes)
+(anstrac= no)
+(mode = q)
+.fi
+
+Note how the parameters are redirected to a variety of tasks.
+
+
+\fBInvisible Parameters\fR
+
+The following algorithm parameters are not visible to the normal user
+and are described only here.
+.ls dbwrite = yes
+Write to database? Writing to the database is a function just like
+find, edit, extract, etc. When the task is interactive a query is
+made whether to write to the database which may be answered with the
+usual four values. When noninteractive the database writing is automatic.
+This parameter provides the possibility of turning off database writing.
+.le
+.ls initialize = yes
+Initialize default queries? Normally each invocation of a task results
+in new queries independent of the last responses in a prior invocation
+and based only on the functions selected; NO for those not selected and
+yes for those selected. By setting this to no either the prior values
+may be used or the response values may be set independently of the
+function flags. This is used in scripts to tie together different
+invocations of the task and to finely control the queries.
+.le
+.ls e_output, e_profile
+These are query parameters used when extraction is invoked from the
+aperture editor.
+.le
+
+The following parameters are part of the variance weighted and cleaning
+extractions. They are described further in \fBapprofiles\fR.
+.ls niterate = 2
+Number of rejection iterations in the profile determination when cleaning.
+Iteration of the profile is slow and the low order fitting function
+is not very sensitive to deviant points.
+.le
+.ls maxtilt = 3
+Maximum excursion separating the two profile fitting algorithms.
+.le
+.ls polysep = 0.95
+Marsh algorithm polynomial spacing.
+.le
+.ls polyorder = 10
+Marsh algorithm polynomial order.
+.le
+
+
+\fBQuery Mechanism and Invisible Query Parameters\fR
+
+The querying mechanism of the \fBapextract\fR package is a nice feature
+but has some complexities in implementation. At the bottom of the
+mechanism are CL checks of the parameters described below. The parameter
+is accessed first as a hidden parameter. If the value is YES or NO
+then the appropriate function is performed or not. If the value is
+lower case then the task supplies a prompt string, which varies by
+including the image and/or aperture involved, the mode of the
+parameter is changed to query, and the parameter is requested again
+leading to a CL query of the user with the current default value.
+Finally, the parameter is returned to hidden mode.
+
+If the \fIinitialize\fR parameter is no then the initial default
+query values are those set before the task is invoked. This provides
+very fine control of the query mechanism and linking different
+invocations of the tasks to previous user responses. It is intended
+only for complex scripts such as those in the spectroscopic \fBimred\fR
+packages. Normally the initial values of the parameters are set
+during task startup based on the function flags. If a flag is no
+then the related query parameter is NO. If the function flag is yes
+then when the task is interactive the initial value is yes otherwise
+it is YES. The solely interactive functions, such as editing, are
+set to NO when the task is noninteractive regardless of the function
+selection.
+.ls ansclobber, ansclobber1
+Used to define the action to be taken if an output image would be clobbered.
+Normally the action is to query if interactive and not clobber if
+noninteractive. The first parameter acts as the function switch and
+the second as the actual query.
+.le
+.ls ansdbwrite, ansdbwrite1
+The second parameter is used by the task to mark whether any changes have
+been made that might require a database update. The first parameter is
+the actual query parameter for the \fIdbwrite\fR function flag.
+.le
+.ls ansedit
+Query parameter for the interactive editing function.
+.le
+.ls ansextract
+Query parameter for the extraction function.
+.le
+.ls ansfind
+Query parameter for the find function.
+.le
+.ls ansfit
+Query parameter for the fit function of \fBapfit\fR.
+.le
+.ls ansfitscatter
+Query parameter for the interactive fitscatter function of \fBapscatter\fR.
+.le
+.ls ansfitsmooth
+Query parameter for the interactive fitsmooth function of \fBapscatter\fR.
+.le
+.ls ansfitspec
+Query parameter for the interactive fitspec function of \fBapflatten\fR
+and \fBapnormalize\fR. This applies to each image.
+.le
+.ls ansfitspec1
+Query parameter for the interactive fitspec function of \fBapflatten\fR
+and \fBapnormalize\fR. This applies to each aperture in an image.
+.le
+.ls ansfittrace
+Query parameter for the interactive fittrace function.
+This applies to each image.
+.le
+.ls ansfittrace1
+Query parameter for the interactive fittrace function.
+This applies to each aperture in an image.
+.le
+.ls ansflat
+Query parameter for the flatten function of \fBapflatten\fR.
+.le
+.ls ansmask
+Query parameter for the mask function of \fBapmask\fR.
+.le
+.ls ansnorm
+Query parameter for the normalize function of \fBapnormalize\fR.
+.le
+.ls ansrecenter
+Query parameter for the recenter function.
+.le
+.ls ansresize
+Query parameter for the resize function.
+.le
+.ls ansreview
+Query parameter for the interactive extraction review function.
+This applies to each image.
+.le
+.ls ansreview1
+Query parameter for the interactive extraction review function.
+This applies to each aperture in an image.
+.le
+.ls ansscat
+Query parameter for the subtract function of \fBapscatter\fR.
+.le
+.ls anssmooth
+Query parameter for the smooth function of \fBapscatter\fR.
+.le
+.ls anstrace
+Query parameter for the trace function.
+.le
+
+
+\fBTask Entry Points\fR
+
+Logical tasks in IRAF are organized as multiple procedures in one physical
+task selected by the IRAF main. The \fBapextract\fR package extends
+this concept to a lower level. All of the package tasks go through
+one procedure, \fBapall\fR. This procedure handles all of the
+startup details and breaks the logical task down into selected
+functions which are implemented as other procedures. There are
+a couple of interesting and unusual features of this organization.
+
+IRAF physical tasks may map multiple logical task names to the same
+procedure. However, the procedure will not know under what name it
+was called. In this package we want to know the logical task name
+in order to select the appropriate hidden parameter set and to
+make minor adjustments in what the tasks do while maintaining the
+same basic logical flow and source code. To do this dummy entry
+points are used whose only function is to call \fBapall\fR and
+pass an indication of the task name.
+
+Based on the task name a named parameter set is opened with \fBclopset\fR
+and then all CLIO calls use the returned pointer and can be blind to the
+actual parameter set used.
+
+In addition to the tasks defined in the package and their associated
+parameter sets there is one more task entry point called \fBapscript\fR
+with parameter set \fBapscript\fR. It is intended for use in scripts
+as it's name implies. For this reason it does not need an intermediate
+hidden parameter set. For examples of it's use see the \fBimred\fR
+packages such as \fBnessie\fR.
+.endhelp
diff --git a/noao/twodspec/apextract/doc/apextras.hlp b/noao/twodspec/apextract/doc/apextras.hlp
new file mode 100644
index 00000000..36a51b26
--- /dev/null
+++ b/noao/twodspec/apextract/doc/apextras.hlp
@@ -0,0 +1,61 @@
+.help extras Sep95 noao.twodspec.apextract
+.ih
+NAME
+extras -- Information about the extra bands in 3D output
+.ih
+DESCRIPTION
+When one dimensional spectra are extracted by the tasks in the
+\fBapextract\fR package the user may specify that additional
+extra associated information be extracted at the same time. This
+information is produced when the \fIextras\fR parameter is "yes".
+
+The associated information is recorded as additional "bands" (the IRAF term
+for the third dimension of a three dimensional image) of the output
+extracted spectral image. Extracted spectra are currently stored as IRAF
+images with dispersion information given in the image header. The
+image axes for such images are:
+
+.nf
+ 1 (columns) - dispersion axis
+ 2 (lines) - spectrum axis (each line is a separate spectrum)
+ 3 (bands) - extras axis (each band is associated data)
+.fi
+
+The lengths of the second and third axes, that is the number of
+lines and bands, may be one or more. If there is only one band
+the image will be two dimensional and if there is only one line
+and one band the image will be one dimensional. Note that the
+\fIformat\fR parameter controls whether multiple apertures are
+written to separate images or to a single image. Thus, if
+the format is "onedspec" this means that the second dimension
+will always be of length one and, if the \fIextras\fR parameter
+is no, the output images will be one dimensional.
+
+The associated data in the image bands depends on which extraction
+options are performed. The various types of data are:
+
+.nf
+ The primary spectrum flux values.
+ Simple aperture sum if variance weighting or cleaning was done.
+ Background spectrum if background subtraction was done.
+ Sigma spectrum if variance weighting or cleaning was done.
+.fi
+
+The primary spectrum is always the first band and will be the cleaned
+and/or variance weighted and/or background subtracted spectrum. The
+simple aperture sum spectrum allows comparing against the results of the
+variance weighting or pixel rejection options. When background
+subtraction is performed the subtracted background is recorded in
+one of the bands. When variance weighting or pixel rejection is
+performed the software generates an estimate of the uncertainty
+in the extracted flux as a sigma.
+
+The identity of the various bands is given by the image header
+keywords BANDIDn (where n is the band number). This also serves
+to document which extraction options were used.
+
+For more information get help under the topic "apextract.package".
+.ih
+SEE ALSO
+apextract.package
+.endhelp
diff --git a/noao/twodspec/apextract/doc/apfind.hlp b/noao/twodspec/apextract/doc/apfind.hlp
new file mode 100644
index 00000000..65260394
--- /dev/null
+++ b/noao/twodspec/apextract/doc/apfind.hlp
@@ -0,0 +1,180 @@
+.help apfind Sep96 noao.twodspec.apextract
+.ih
+NAME
+apfind -- Find spectra and define apertures automatically
+.ih
+USAGE
+apfind input
+.ih
+PARAMETERS
+.ls input
+List of input images in which spectra are to be identified and
+apertures defined automatically.
+.le
+.ls apertures = ""
+Apertures to recenter, resize, trace, and extract. This only applies
+to apertures read from the input or reference database. Any new
+apertures defined with the automatic finding algorithm or interactively
+are always selected. The syntax is a list comma separated ranges
+where a range can be a single aperture number, a hyphen separated
+range of aperture numbers, or a range with a step specified by "x<step>";
+for example, "1,3-5,9-12x2".
+.le
+.ls references = ""
+List of reference images to be used to define apertures for the input
+images. When a reference image is given it supersedes apertures
+previously defined for the input image. The list may be null, "", or
+any number of images less than or equal to the list of input images.
+There are three special words which may be used in place of an image
+name. The word "last" refers to the last set of apertures written to
+the database. The word "OLD" requires that an entry exist
+and the word "NEW" requires that the entry not exist for each input image.
+.le
+
+.ls interactive = no
+Run this task interactively? If the task is not run interactively then
+all user queries are suppressed and interactive aperture editing is
+disabled.
+.le
+.ls find = yes
+Find the spectra and define apertures automatically? In order for
+spectra to be found automatically there must be no apertures for the
+input image or reference image defined in the database and the
+parameter \fInfind\fR must be greater than zero.
+.le
+.ls recenter = no
+Recenter the apertures?
+.le
+.ls resize = no
+Resize the apertures?
+.le
+.ls edit = yes
+Edit the apertures? The \fIinteractive\fR parameter must also be yes.
+.le
+
+.ls line = INDEF
+The dispersion line (line or column perpendicular to the dispersion axis) to
+be used in finding the spectra. A value of INDEF selects the middle of the
+image.
+.le
+.ls nsum = 1
+Number of dispersion lines to be summed or medianed. The lines are taken
+around the specified dispersion line. A positive value sums lines and
+a negative value medians lines.
+.le
+.ls nfind = 1
+Maximum number of apertures to be defined. This is a query parameter
+so the user is queried for a value except when given explicitly on
+the command line.
+.le
+.ls minsep = 5.
+Minimum separation between spectra. Weaker spectra or noise within this
+distance of a stronger spectrum are rejected.
+.le
+.ls maxsep = 1000.
+Maximum separation between adjacent spectra. This parameter
+is used to identify missing spectra in uniformly spaced spectra produced
+by fiber spectrographs. If two adjacent spectra exceed this separation
+then it is assumed that a spectrum is missing and the aperture identification
+assignments will be adjusted accordingly.
+.le
+.ls order = "increasing"
+When assigning aperture identifications order the spectra "increasing"
+or "decreasing" with increasing pixel position (left-to-right or
+right-to-left in a cross-section plot of the image).
+.le
+.ih
+ADDITIONAL PARAMETERS
+I/O parameters and the default dispersion axis are taken from the
+package parameters, the default aperture parameters are taken from the
+task \fBapdefault\fR, and parameters used for centering and editing the
+apertures are taken from \fBapedit\fR.
+
+When this operation is performed from the task \fBapall\fR all parameters
+except the package parameters are included in that task.
+.ih
+DESCRIPTION
+For each image in the input image list spectra are identified and
+default apertures defined. The automatic aperture finding is performed
+only if 1) there are no apertures defined for the reference image, 2)
+there are no apertures defined for the input image, 3) the parameter
+\fIfind\fR is yes, and 4) the parameter \fInfind\fR is greater than
+zero.
+
+The automatic finding algorithm uses the following steps. First, all local
+maxima are found. The maxima are sorted by peak value and the weaker
+of the peaks separated by less than the value given by the parameter
+\fIminsep\fR are rejected. Finally, at most the \fInfind\fR strongests
+peaks are kept. \fBNfind\fR is a query parameter, so if it is not
+specified explicitly on the command line, the desired number of spectra
+to be found is requested. After the peaks have been found the
+\fBcenter1d\fR algorithm is used to refine the centers of the
+profiles. Apertures having the default parameters set with the task
+\fBapdefault\fR are defined at each center. This algorithm is also
+available with the 'f' key in the task \fBapedit\fR with the change that
+existing apertures are kept and count toward the maximum number
+specified by \fBnfind\fR.
+
+The automatic assignment of aperture numbers, beam numbers, and titles
+has several options. The simplest is when no aperture identification
+table, parameter \fIapidtable\fR, is specified and the maximum separation
+parameter, \fImaxsep\fR, is very large. In this case the aperture and
+beam numbers are sequential starting from one and numbered either from
+left-to-right or right-to-left depending on the \fIorder\fR parameter.
+There are no aperture titles in this case. If two adjacent spectra are
+separated by more than the specified maximum then the aperture numbers
+jump by the integer part of the ratio of the separation to the
+specified maximum separation. This is used when the image is expected
+to have evenly spaced spectra, such as in multifiber spectrographs, in
+which some may be missing due to broken fibers. Finally, the
+aperture identification table (either a text file or an image
+having a set of SLFIBnnn keyowrds) may contain lines with aperture number,
+beam number, and (optional) title. The sequential numbers are then
+indices into this table. Note that the skipping of missing spectra and
+the ordering applies to entries in this table as well.
+
+The ways in which the automatic method can fail for evenly spaced
+spectra with missing members are when the first spectrum is missing on
+the side from which the ordering begins and when the expected rather
+the actual number of spectra is used. In the first case one can use
+the interactive 'o' key of the aperture editing facility to specify the
+identity of any aperture and then all other apertures will be
+appropriately reidentified. If more spectra are sought than actually
+exist then noise spikes may be mistakenly found. This problem can be
+eliminated by specifying the actual number of spectra or minimized by
+using the threshold centering parameter.
+
+The \fIrecenter\fR parameter allows recentering apertures if defined by
+a reference image. Since the purpose of this task is to find new
+apertures it is usually the case that there are no reference images and
+recentering is not done. The default apertures are of fixed width.
+The \fIresize\fR parameter may be used to adjust the widths in a
+variety of ways. The aperture positions and any other parameters may
+also be edited with the aperture editing function if selected by the
+\fIapedit\fR parameter and the task is run interactively.
+
+If the task is interactive the user is queried whether to perform
+various steps on each image. The queries may be answered with one of
+the four values "yes", "no", "YES" and "NO", where an upper case
+response suppresses all further queries to this question.
+
+The aperture finding algorithm may be selected from nearly every task
+in the package.
+.ih
+EXAMPLES
+ cl> apfind image nfind=10
+.ih
+.ih
+REVISIONS
+.ls APFIND V2.11
+The "apertures" parameter can be used to select apertures for resizing,
+recentering, tracing, and extraction. This parameter name was previously
+used for selecting apertures in the recentering algorithm. The new
+parameter name for this is now "aprecenter".
+
+The aperture ID table information may now be contained in the
+image header under the keywords SLFIBnnn.
+.le
+SEE ALSO
+center1d, apdefault, aprecenter, apresize, apedit, apall
+.endhelp
diff --git a/noao/twodspec/apextract/doc/apfit.hlp b/noao/twodspec/apextract/doc/apfit.hlp
new file mode 100644
index 00000000..60dd9b4c
--- /dev/null
+++ b/noao/twodspec/apextract/doc/apfit.hlp
@@ -0,0 +1,263 @@
+.help apfit Sep96 noao.twodspec.apextract
+.ih
+NAME
+apfit -- Fit 2D spectra using APEXTRACT profile algorithms
+.ih
+USAGE
+apfit input output fittype
+.ih
+PARAMETERS
+.ls input
+List of input images to be fit.
+.le
+.ls output = ""
+List of output images to be created with the fitting results. If the null
+string is given or the end of the output list is reached before the end
+of the input list then the input image name is used and an extension
+of ".fit", ".diff", or ".ratio" is added based on the type of fit.
+.le
+.ls apertures = ""
+Apertures to recenter, resize, trace, and fit. This only applies
+to apertures read from the input or reference database. Any new
+apertures defined with the automatic finding algorithm or interactively
+are always selected. The syntax is a list comma separated ranges
+where a range can be a single aperture number, a hyphen separated
+range of aperture numbers, or a range with a step specified by "x<step>";
+for example, "1,3-5,9-12x2".
+.le
+.ls fittype = "difference"
+Type of fitted output. The choices are:
+.ls "fit"
+The fitted spectra are output.
+.le
+.ls "difference"
+The difference (or residuals) of the data and the fit (data - fit).
+.le
+.ls "ratio"
+The ratio of the data to the fit. If a fitted pixel goes below a specified
+threshold the ratio is set to 1.
+.le
+.le
+.ls references = ""
+List of reference images to be used to define apertures for the input
+images. When a reference image is given it supersedes apertures
+previously defined for the input image. The list may be null, "", or
+any number of images less than or equal to the list of input images.
+There are three special words which may be used in place of an image
+name. The word "last" refers to the last set of apertures written to
+the database. The word "OLD" requires that an entry exist
+and the word "NEW" requires that the entry not exist for each input image.
+.le
+
+.ls interactive = yes
+Run this task interactively? If the task is not run interactively then
+all user queries are suppressed and interactive aperture editing and trace
+fitting are disabled.
+.le
+.ls find = yes
+Find the spectra and define apertures automatically? In order for
+spectra to be found automatically there must be no apertures for the
+input image or reference image defined in the database.
+.le
+.ls recenter = yes
+Recenter the apertures?
+.le
+.ls resize = yes
+Resize the apertures?
+.le
+.ls edit = yes
+Edit the apertures? The \fIinteractive\fR parameter must also be yes.
+.le
+.ls trace = yes
+Trace the apertures?
+.le
+.ls fittrace = yes
+Interactively fit the traced positions by a function? The \fIinteractive\fR
+parameter must also be yes.
+.le
+.ls fit = yes
+Fit the spectra and produce a fitted output image?
+.le
+
+The following two parameters are used in the finding, recentering, resizing,
+editing, and tracing operations.
+.ls line = INDEF
+The starting dispersion line (line or column perpendicular to the dispersion
+axis) for the tracing. A value of INDEF starts at the middle of the image.
+.le
+.ls nsum = 1
+Number of dispersion lines to be summed or medianed at each step along
+the dispersion. For tracing only summing is done and the sign is
+ignored.
+.le
+
+.ls threshold = 10.
+Division threshold for ratio fit type. If a pixel in the fitted spectrum
+is less than this value then a ratio of 1 is output.
+.le
+
+The following parameters control the profile and spectrum fitting.
+.ls background = "none"
+Type of background subtraction. The choices are "none" for no
+background subtraction, "average" to average the background within the
+background regions, or "fit" to fit across the dispersion using the
+background within the background regions. Note that the "average"
+option does not do any medianing or bad pixel checking; it is faster
+than fitting however. Background subtraction also requires that the
+background fitting parameters are properly defined. For the "average"
+option only the background sample regions parameter is used.
+.le
+.ls pfit = "fit1d" (fit1d|fit2d)
+Profile fitting algorithm to use with variance weighting or cleaning.
+When determining a profile the two dimensional spectrum is divided by
+an estimate of the one dimensional spectrum to form a normalized two
+dimensional spectrum profile. This profile is then smoothed by fitting
+one dimensional functions, "fit1d", along the lines or columns most closely
+corresponding to the dispersion axis or a special two dimensional
+function, "fit2d", described by Marsh (see \fBapprofile\fR).
+.le
+.ls clean = no
+Detect and replace deviant pixels?
+.le
+.ls skybox = 1
+Box car smoothing length for sky background when using background
+subtraction. Since the background noise is often the limiting factor
+for good extraction one may box car smooth the sky to improve the
+statistics in smooth background regions at the expense of distorting
+the subtraction near spectral features. This is most appropriate when
+the sky regions are limited due to a small slit length.
+.le
+.ls saturation = INDEF
+Saturation or nonlinearity level. During variance weighted extractions
+wavelength points having any pixels above this value are excluded from the
+profile determination.
+.le
+.ls readnoise = 0.
+Read out noise in photons. This parameter defines the minimum noise
+sigma. It is defined in terms of photons (or electrons) and scales
+to the data values through the gain parameter. A image header keyword
+(case insensitive) may be specified to get the value from the image.
+.le
+.ls gain = 1
+Detector gain or conversion factor between photons/electrons and
+data values. It is specified as the number of photons per data value.
+A image header keyword (case insensitive) may be specified to get the value
+from the image.
+.le
+.ls lsigma = 3., usigma = 3.
+Lower and upper rejection thresholds, given as a number of times the
+estimated sigma of a pixel, for cleaning.
+.le
+.ih
+ADDITIONAL PARAMETERS
+I/O parameters and the default dispersion axis are taken from the
+package parameters, the default aperture parameters from
+\fBapdefault\fR, automatic aperture finding parameters from
+\fBapfind\fR, recentering parameters from \fBaprecenter\fR, resizing
+parameters from \fBapresize\fR, parameters used for centering and
+editing the apertures from \fBapedit\fR, and tracing parameters from
+\fBaptrace\fR.
+.ih
+DESCRIPTION
+The two dimensional spectra within the defined apertures of the input
+images are fit by a model and new output images are created with either
+the model spectra, the difference between the input and model spectra,
+or the ratio of input and model spectra. The type of output is
+selected by the parameter \fIfittype\fR which may have one of the
+values "fit", "difference", or "ratio".
+
+Aperture definitions may be inherited from those of other images by
+specifying a reference image with the \fBreferences\fR parameter.
+Images in the reference list are matched with those in the
+input list in order. If the reference image list is shorter than the
+number of input images, the last reference image is used for all
+remaining input images. Thus, a single reference image may be given
+for all the input images or different reference images may be given for
+each input image. The special reference name "last" may be used to
+select the last set apertures used in any of the \fBapextract\fR tasks.
+
+If an aperture reference image is not specified or no apertures are
+found for the specified reference image, previously defined apertures
+for the input image are sought in the aperture database. Note that
+reference apertures supersede apertures for the input image. If no
+apertures are defined they may be created automatically, the \fIfind\fR
+option, or interactively in the aperture editor, if the
+\fIinteractive\fR and \fIedit\fR options are set.
+
+The functions performed by the task are selected by a set of flag
+parameters. The functions are an automatic spectrum finding and
+aperture defining algorithm (see \fBapfind\fR) which is ignored if
+apertures are already defined, automatic recentering and resizing
+algorithms (see \fBaprecenter\fR and \fBapresize\fR), an interactive
+aperture editing function (see \fBapedit\fR), a spectrum position tracing
+and trace function fit (see \fBaptrace\fR), and the main function of
+this task, two dimensional model fitting.
+
+Each function selection will produce a query for each input spectrum if
+the \fIinteractive\fR parameter is set. The queries are answered by
+"yes", "no", "YES", or "NO", where the upper case responses suppress
+the query for following images. There are other queries associated
+with tracing which first ask whether the operation is to be done
+interactively and, if yes, lead to queries for each aperture. If the
+\fIinteractive\fR parameter is not set then aperture editing and
+interactive trace fitting are ignored.
+
+The two dimensional spectrum model consists of a smooth two dimensional
+normalized profile multiplied by the variance weighted one dimensional
+spectrum. The profile is computed by dividing the data within the aperture
+by the one dimensional spectrum, smoothing with either low order function
+fits parallel to the dispersion axis or a special two dimensional function
+as selected by the \fIpfit\fR parameter. The smooth profile is then used
+to improve the spectrum estimate using variance weighting and to eliminate
+deviant or cosmic ray pixels by sigma tests. The profile algorithm is
+described in detail in \fBapprofiles\fR and the variance weighted spectrum
+is described in \fBapvariance\fR.
+
+The process of determining the profile and variance weighted spectrum,
+and hence the two dimensional spectrum model, is identical to that used
+for variance weighted extraction of the one dimensional spectra in the
+tasks \fBapall\fR or \fBapsum\fR. Most of the parameters of in this
+task are the same as those in the extraction tasks and so further
+information about them may be found in the descriptions of those tasks.
+
+Because of the connection with variance weighted extraction and cleaning
+of one dimensional spectra, this task is useful as a diagnostic tool for
+understanding and evaluating the variance weighting algorithm.
+For example the "difference" image provides the residuals in a
+two dimensional visual form.
+
+The "fit" output image does not include any background determination;
+i.e the fit is background subtracted. Pixels outside the modeled
+spectra are set to zero.
+
+The "difference" output image is simply the difference between the
+background subtracted "fit" and the data. Thus the difference within
+the apertures should approximate the background and outside the
+apertures the difference will be identical with the input image.
+
+The "ratio" output image does include any background in the model
+before taking the ratio of the data and model. If a model pixel
+is less than the given \fIthreshold\fR parameter the output ratio
+is set to one. This is used to avoid division by zero and set a
+limit to noise in ratio image. Outside of the apertures the ratio
+output pixels are set to one.
+.ih
+EXAMPLES
+1. To compute the residuals of a model fit where the image already has
+aperture defined:
+
+ cl> apfit ls1 inter- rec- res- trace- read=3 gain=1 back=fit
+
+.ih
+REVISIONS
+.ls APFIND V2.11
+The "apertures" parameter can be used to select apertures for resizing,
+recentering, tracing, and extraction. This parameter name was previously
+used for selecting apertures in the recentering algorithm. The new
+parameter name for this is now "aprecenter".
+.le
+.ih
+SEE ALSO
+apbackground, approfile, apvariance,
+apdefault, apfind, aprecenter, apresize, apedit, aptrace, apsum, apall
+.endhelp
diff --git a/noao/twodspec/apextract/doc/apflatten.hlp b/noao/twodspec/apextract/doc/apflatten.hlp
new file mode 100644
index 00000000..f7e1b8c0
--- /dev/null
+++ b/noao/twodspec/apextract/doc/apflatten.hlp
@@ -0,0 +1,304 @@
+.help apflatten Sep96 noao.twodspec.apextract
+.ih
+NAME
+apflatten -- Create flat fields for fiber or narrow aperture spectra
+.ih
+USAGE
+apflatten input output
+.ih
+PARAMETERS
+.ls input
+List of input flat field observations.
+.le
+.ls output = ""
+List of output flat field images. If no output name is given then the
+input name is used as a root with the extension ".flat".
+.le
+.ls apertures = ""
+Apertures to recenter, resize, trace, and flatten. This only applies
+to apertures read from the input or reference database. Any new
+apertures defined with the automatic finding algorithm or interactively
+are always selected. The syntax is a list comma separated ranges
+where a range can be a single aperture number, a hyphen separated
+range of aperture numbers, or a range with a step specified by "x<step>";
+for example, "1,3-5,9-12x2".
+.le
+.ls references = ""
+List of reference images to be used to define apertures for the input
+images. When a reference image is given it supersedes apertures
+previously defined for the input image. The list may be null, "", or
+any number of images less than or equal to the list of input images.
+There are three special words which may be used in place of an image
+name. The word "last" refers to the last set of apertures written to
+the database. The word "OLD" requires that an entry exist
+and the word "NEW" requires that the entry not exist for each input image.
+.le
+
+.ls interactive = yes
+Run this task interactively? If the task is not run interactively then
+all user queries are suppressed and interactive aperture editing and trace
+fitting are disabled.
+.le
+.ls find = yes
+Find the spectra and define apertures automatically? In order for
+spectra to be found automatically there must be no apertures for the
+input image or reference image defined in the database.
+.le
+.ls recenter = yes
+Recenter the apertures?
+.le
+.ls resize = yes
+Resize the apertures?
+.le
+.ls edit = yes
+Edit the apertures? The \fIinteractive\fR parameter must also be yes.
+.le
+.ls trace = yes
+Trace the apertures?
+.le
+.ls fittrace = yes
+Interactively fit the traced positions by a function? The \fIinteractive\fR
+parameter must also be yes.
+.le
+.ls flatten = yes
+Remove the profile shape and flat field spectrum leaving only
+sensitivity variations?
+.le
+.ls fitspec = yes
+Fit normalization spectrum interactively? The \fIinteractive\fR
+parameter must also be yes.
+.le
+
+.ls line = INDEF, nsum = 1
+The dispersion line (line or column perpendicular to the dispersion
+axis) and number of adjacent lines (half before and half after unless
+at the end of the image) used in finding, recentering, resizing,
+and editing operations. For tracing this is the starting line and
+the same number of lines are summed at each tracing point. A line of
+INDEF selects the middle of the image along the dispersion axis.
+A positive nsum sums the lines and a negative value takes the median.
+However, for tracing only sums are allowed and the absolute value
+is used.
+.le
+.ls threshold = 10.
+Division threshold. If a pixel in the two dimensional normalization spectrum
+is less than this value then a flat field value of 1 is output.
+.le
+
+The following parameters control the profile and spectrum fitting.
+.ls pfit = "fit1d" (fit1d|fit2d)
+Profile fitting algorithm to use with variance weighting or cleaning.
+When determining a profile the two dimensional spectrum is divided by
+an estimate of the one dimensional spectrum to form a normalized two
+dimensional spectrum profile. This profile is then smoothed by fitting
+one dimensional functions, "fit1d", along the lines or columns most closely
+corresponding to the dispersion axis or a special two dimensional
+function, "fit2d", described by Marsh (see \fBapprofile\fR).
+.le
+.ls clean = no
+Detect and replace deviant pixels?
+.le
+.ls saturation = INDEF
+Saturation or nonlinearity level. During variance weighted extractions
+wavelength points having any pixels above this value are excluded from the
+profile determination.
+.le
+.ls readnoise = 0.
+Read out noise in photons. This parameter defines the minimum noise
+sigma. It is defined in terms of photons (or electrons) and scales
+to the data values through the gain parameter. A image header keyword
+(case insensitive) may be specified to get the value from the image.
+.le
+.ls gain = 1
+Detector gain or conversion factor between photons/electrons and
+data values. It is specified as the number of photons per data value.
+A image header keyword (case insensitive) may be specified to get the value
+from the image.
+.le
+.ls lsigma = 3., usigma = 3.
+Lower and upper rejection thresholds, given as a number of times the
+estimated sigma of a pixel, for cleaning.
+.le
+
+The following parameters are used to fit the normalization spectrum using
+the ICFIT routine.
+.ls function = "legendre"
+Fitting function for the normalization spectra. The choices are "legendre"
+polynomial, "chebyshev" polynomial, linear spline ("spline1"), and
+cubic spline ("spline3").
+.le
+.ls order = 1
+Number of polynomial terms or number of spline pieces for the fitting function.
+.le
+.ls sample = "*"
+Sample regions for fitting points. Intervals are separated by "," and an
+interval may be one point or a range separated by ":".
+.le
+.ls naverage = 1
+Number of points within a sample interval to be subaveraged or submedianed to
+form fitting points. Positive values are for averages and negative points
+for medians.
+.le
+.ls niterate = 0
+Number of sigma clipping rejection iterations.
+.le
+.ls low_reject = 3. , high_reject = 3.
+Lower and upper sigma clipping rejection threshold in units of sigma determined
+from the RMS sigma of the data to the fit.
+.le
+.ls grow = 0.
+Growing radius for rejected points (in pixels). That is, any rejected point
+also rejects other points within this distance of the rejected point.
+.le
+.ih
+ADDITIONAL PARAMETERS
+I/O parameters and the default dispersion axis are taken from the
+package parameters, the default aperture parameters from
+\fBapdefault\fR, automatic aperture finding parameters from
+\fBapfind\fR, recentering parameters from \fBaprecenter\fR, resizing
+parameters from \fBapresize\fR, parameters used for centering and
+editing the apertures from \fBapedit\fR, and tracing parameters from
+\fBaptrace\fR.
+.ih
+DESCRIPTION
+It is sometimes the case that it is undesirable to simply divide
+two dimensional format spectra taken through fibers, aperture masks
+with small apertures such as holes and slitlets, or small slits in
+echelle formats by a flat field observation of a lamp. This is due
+to the sharp dropoff of the flat field and object profiles and
+absence of signal outside of the profile. Slight shifts or changes
+in profile shape introduce bad edge effects, unsightly "grass" is
+produced where there is no signal (which may also confuse extraction
+programs), and the division will also remove the characteristic
+profile of the object which might be needed for tracking the
+statistical significance, variance weighted extraction, and more.
+A straight flat field division also has the problem of changing the
+shape of the spectrum in wavelength, again compromising the
+poisson statistics and artificially boosting low signal regions.
+
+There are three approaches to consider. First, the
+flat field correction can be done after extraction to one dimension.
+This is valid provided the flat field and object profiles don't shift
+much. However, for extractions that depend on a smooth profile,
+such as the variance weighting algorithms of this package, the sensitivity
+corrections must remain small; i.e. no large fringes or other
+small scale variations that greatly perturb the true photon profile.
+The second approach is to divide out the overall spectral shape of
+the flat field spectrum, fill regions outside of the signal with
+one and leave the profile shape intact. This will still cause profile
+division problems described earlier but is mentioned here since it
+implemented in a related task called \fBapnormalize\fR. The last
+approach is to model both the profile and overall spectrum shape and
+remove it from the flat field leaving only the sensitivity variations.
+This is what the task \fBapflatten\fR does.
+
+The two dimensional flat field spectra within the defined apertures of
+the input images are fit by a model having the profile of the data and
+a smooth spectral shape. This model is then divided into the flat
+field image within the aperture, replacing points of low signal, set
+with the \fIthreshold\fR parameter, within the aperture and all points
+outside the aperture by one to produce an output sensitivity variation
+only flat field image.
+
+A two dimensional normalized profile is computed by dividing the data
+within the aperture by the one dimensional spectrum and smoothing with
+low order function fits parallel to the dispersion axis if the aperture
+is well aligned with the axis or parallel to the traced aperture center
+if the trace is tilted relative to the dispersion axis. The smooth
+profile is then used to improve the spectrum estimate using variance
+weighting and to eliminate deviant or cosmic ray pixels by sigma
+tests. The profile algorithm is described in detail in
+\fBapprofiles\fR and the variance weighted spectrum is described in
+\fBapvariance\fR.
+
+The process of determining the profile and variance weighted spectrum,
+and hence the two dimensional spectrum model, is identical to that used
+for variance weighted extraction of the one dimensional spectra in the
+tasks \fBapall\fR or \fBapsum\fR and in making a two dimensional
+spectrum model in the task \fBapfit\fR. Most of the parameters in
+this task are the same in those tasks and so further information about
+them may be found in their descriptions. In fact, up to this point the
+task is the same as \fBapfit\fR and, if the flat field were normalized
+by this model it would produce the "ratio" output of that task.
+
+This task deviates from \fBapfit\fR in that the final variance weighted
+one dimensional spectrum of the flat field is subjected to a smoothing
+operation. This is done by fitting a function to the spectrum using
+the \fBicfit\fR routine. This may be done interactively or
+noninteractively depending on the \fBinteractive\fR parameter. The
+default fitting parameters are part of this task. The goal of the
+fitting is to follow the general spectral shape of the flat field light
+(usually a lamp) but not the small bumps and wiggles which are the one
+dimensional projection of sensitivity variations. When the fitted
+function is multiplied into the normalize profile and then the two
+dimensional model divided into the data the sensitivity variations not
+part of the fitted spectrum are what is left in the final output flat
+field.
+
+The remainder of this description covers the basic steps defining the
+apertures to be used. These steps and parameter are much the same as
+in any of the other \fBapextract\fR tasks.
+
+Aperture definitions may be inherited from those of other images by
+specifying a reference image with the \fBreferences\fR parameter.
+Images in the reference list are matched with those in the input list
+in order. If the reference image list is shorter than the number of
+input images, the last reference image is used for all remaining input
+images. Thus, a single reference image may be given for all the input
+images or different reference images may be given for each input
+image. The special reference name "last" may be used to select the
+last set apertures used in any of the \fBapextract\fR tasks.
+
+If an aperture reference image is not specified or no apertures are
+found for the specified reference image, previously defined apertures
+for the input image are sought in the aperture database. Note that
+reference apertures supersede apertures for the input image. If no
+apertures are defined they may be created automatically, the \fIfind\fR
+option, or interactively in the aperture editor, if the
+\fIinteractive\fR and \fIedit\fR options are set.
+
+The functions performed by the task are selected by a set of flag
+parameters. The functions are an automatic spectrum finding and
+aperture defining algorithm (see \fBapfind\fR) which is ignored if
+apertures are already defined, automatic recentering and resizing
+algorithms (see \fBaprecenter\fR and \fBapresize\fR), an interactive
+aperture editing function (see \fBapedit\fR), a spectrum position tracing
+and trace function fit (see \fBaptrace\fR), and the main function of
+this task, the flat field profile and spectral shape modeling and removal.
+
+Each function selection will produce a query for each input spectrum if
+the \fIinteractive\fR parameter is set. The queries are answered by
+"yes", "no", "YES", or "NO", where the upper case responses suppress
+the query for following images. There are other queries associated
+with tracing which first ask whether the operation is to be done
+interactively and, if yes, lead to queries for each aperture. If the
+\fIinteractive\fR parameter is not set then aperture editing
+interactive trace fitting, and interactive spectrum shape fitting are ignored.
+.ih
+REVISIONS
+.ls APFLATTEN V2.11
+The "apertures" parameter can be used to select apertures for resizing,
+recentering, tracing, and extraction. This parameter name was previously
+used for selecting apertures in the recentering algorithm. The new
+parameter name for this is now "aprecenter".
+.le
+.ih
+EXAMPLES
+1. To make a two dimensional flat field from a lamp observation:
+
+.nf
+ cl> apflatten fiber1 flat read=3 gain=1 back=fit
+ Yes find
+ No resize
+ No edit
+ Yes trace
+ Yes trace interactively
+ NO
+ Yes flatten
+ Yes fit interactively
+.fi
+.ih
+SEE ALSO
+apbackground, approfile, apvariance, apfit, icfit,
+apdefault, apfind, aprecenter, apresize, apedit, aptrace, apsum
+.endhelp
diff --git a/noao/twodspec/apextract/doc/apmask.hlp b/noao/twodspec/apextract/doc/apmask.hlp
new file mode 100644
index 00000000..78d775f9
--- /dev/null
+++ b/noao/twodspec/apextract/doc/apmask.hlp
@@ -0,0 +1,123 @@
+.help apmask Sep96 noao.twodspec.apextract
+.ih
+NAME
+apmask -- Make pixel mask from apertures definitions
+.ih
+USAGE
+apfind input
+.ih
+PARAMETERS
+.ls input
+List of input images with aperture definitions.
+.le
+.ls output
+List of output mask names. As a convention the extension ".pl" (pixel
+list) should be used.
+.le
+.ls apertures = ""
+Apertures to recenter, resize, trace, and create a mask. This only applies
+to apertures read from the input or reference database. Any new
+apertures defined with the automatic finding algorithm or interactively
+are always selected. The syntax is a list comma separated ranges
+where a range can be a single aperture number, a hyphen separated
+range of aperture numbers, or a range with a step specified by "x<step>";
+for example, "1,3-5,9-12x2".
+.le
+.ls references = ""
+List of reference images to be used to define apertures for the input
+images. When a reference image is given it supersedes apertures
+previously defined for the input image. The list may be null, "", or
+any number of images less than or equal to the list of input images.
+There are three special words which may be used in place of an image
+name. The word "last" refers to the last set of apertures written to
+the database. The word "OLD" requires that an entry exist
+and the word "NEW" requires that the entry not exist for each input image.
+.le
+
+.ls interactive = no
+Run this task interactively? If the task is not run interactively then
+all user queries are suppressed and interactive aperture editing is
+disabled.
+.le
+.ls find = yes
+Find the spectra and define apertures automatically? In order for
+spectra to be found automatically there must be no apertures for the
+input image or reference image defined in the database and the
+parameter \fInfind\fR must be greater than zero.
+.le
+.ls recenter = no
+Recenter the apertures?
+.le
+.ls resize = no
+Resize the apertures?
+.le
+.ls edit = yes
+Edit the apertures? The \fIinteractive\fR parameter must also be yes.
+.le
+.ls trace = yes
+Trace apertures?
+.le
+.ls fittrace = yes
+Fit the traced points interactively? The \fIinteractive\fR parameter
+must also be yes.
+.le
+.ls mask = yes
+Create mask images?
+.le
+
+.ls line = INDEF
+The dispersion line (line or column perpendicular to the dispersion axis) to
+be used in finding, recentering, resizing, editing, and starting to
+trace spectra. A value of INDEF selects the middle of the image.
+.le
+.ls nsum = 1
+Number of dispersion lines to be summed or medianed. The lines are taken
+around the specified dispersion line. A positive value takes the
+sum and a negative value selects a median.
+.le
+.ls buffer = 0.
+Buffer to add to aperture limits. One use for this is to increase
+the width of the apertures when a mask is used to fit data between
+the apertures.
+.le
+.ih
+ADDITIONAL PARAMETERS
+I/O parameters and the default dispersion axis are taken from the
+package parameters, the default aperture parameters from
+\fBapdefault\fR, automatic aperture finding parameters from
+\fBapfind\fR, recentering parameters from \fBaprecenter\fR, resizing
+parameters from \fBapresize\fR, parameters used for centering and
+editing the apertures from \fBapedit\fR, and tracing parameters from
+\fBaptrace\fR.
+.ih
+DESCRIPTION
+Pixel list masks are created from the aperture definitions in the input
+images. Pixel list masks are a compact way to define arbitrary
+regions of an image. The masks may be used directly as an image with values
+of 1 (in an aperture) and 0 (outside an aperture). Alternatively,
+some tasks may use a mask to define regions to be operated upon.
+When this task was written there were no such tasks though eventually
+some tasks will be converted to use this general format. The intent
+of making an aperture mask is to someday allow using it with the task
+\fBimsurfit\fR to fit a background or scattered light surface.
+(See \fBapscatter\fR for an alternative method).
+.ih
+EXAMPLES
+1. To replace all data outside the apertures by zero:
+
+.nf
+ cl> apmask image image.pl nfind=10
+ cl> imarith image * image.pl image1
+.fi
+.ih
+REVISIONS
+.ls APMASK V2.11
+The "apertures" parameter can be used to select apertures for resizing,
+recentering, tracing, and extraction. This parameter name was previously
+used for selecting apertures in the recentering algorithm. The new
+parameter name for this is now "aprecenter".
+.le
+.ih
+SEE ALSO
+apdefault, aprecenter, apresize, apedit, aptrace, apall
+.endhelp
diff --git a/noao/twodspec/apextract/doc/apnoise.hlp b/noao/twodspec/apextract/doc/apnoise.hlp
new file mode 100644
index 00000000..a4f69f83
--- /dev/null
+++ b/noao/twodspec/apextract/doc/apnoise.hlp
@@ -0,0 +1,231 @@
+.help apnoise Sep96 noao.twodspec.apextract
+.ih
+NAME
+apnoise -- Compute and examine noise characteristics of spectra
+.ih
+USAGE
+apnoise input dmin dmax nbins
+.ih
+PARAMETERS
+.ls input
+List of input spectra to examine.
+.le
+.ls apertures = ""
+Apertures to recenter, resize, trace, and extract. This only applies
+to apertures read from the input or reference database. Any new
+apertures defined with the automatic finding algorithm or interactively
+are always selected. The syntax is a list comma separated ranges
+where a range can be a single aperture number, a hyphen separated
+range of aperture numbers, or a range with a step specified by "x<step>";
+for example, "1,3-5,9-12x2".
+.le
+.ls references = ""
+List of reference images to be used to define apertures for the input
+images. When a reference image is given it supersedes apertures
+previously defined for the input image. The list may be null, "", or
+any number of images less than or equal to the list of input images.
+There are three special words which may be used in place of an image
+name. The word "last" refers to the last set of apertures written to
+the database. The word "OLD" requires that an entry exist
+and the word "NEW" requires that the entry not exist for each input image.
+.le
+
+.ls dmin, dmax, nbins
+The noise sigma is computed in a set of bins over the specified
+range of image data numbers.
+.le
+
+.ls interactive = yes
+Run this task interactively? If the task is not run interactively then
+all user queries are suppressed and interactive aperture editing and trace
+fitting are disabled.
+.le
+.ls find = yes
+Find the spectra and define apertures automatically? In order for
+spectra to be found automatically there must be no apertures for the
+input image or reference image defined in the database.
+.le
+.ls recenter = yes
+Recenter the apertures?
+.le
+.ls resize = yes
+Resize the apertures?
+.le
+.ls edit = yes
+Edit the apertures? The \fIinteractive\fR parameter must also be yes.
+.le
+.ls trace = yes
+Trace the apertures?
+.le
+.ls fittrace = yes
+Interactively fit the traced positions by a function? The \fIinteractive\fR
+parameter must also be yes.
+.le
+
+.ls line = INDEF, nsum = 1
+The dispersion line (line or column perpendicular to the dispersion
+axis) and number of adjacent lines (half before and half after unless
+at the end of the image) used in finding, recentering, resizing,
+and editing operations. For tracing this is the starting line and
+the same number of lines are summed at each tracing point. A line of
+INDEF selects the middle of the image along the dispersion axis.
+A positive nsum sums the lines and a negative value takes the median.
+However, for tracing only sums are allowed and the absolute value
+is used.
+.le
+.ls threshold = 10.
+Division threshold. If a pixel in the two dimensional normalization spectrum
+is less than this value then a flat field value of 1 is output.
+.le
+
+The following parameters control the profile and spectrum fitting.
+.ls background = "none"
+Type of background subtraction. The choices are "none" for no
+background subtraction, "average" to average the background within the
+background regions, or "fit" to fit across the dispersion using the
+background within the background regions. Note that the "average"
+option does not do any medianing or bad pixel checking; it is faster
+than fitting however. Background subtraction also requires that the
+background fitting parameters are properly defined. For the "average"
+option only the background sample regions parameter is used.
+.le
+.ls pfit = "fit1d" (fit1d|fit2d)
+Profile fitting algorithm to use with variance weighting or cleaning.
+When determining a profile the two dimensional spectrum is divided by
+an estimate of the one dimensional spectrum to form a normalized two
+dimensional spectrum profile. This profile is then smoothed by fitting
+one dimensional functions, "fit1d", along the lines or columns most closely
+corresponding to the dispersion axis or a special two dimensional
+function, "fit2d", described by Marsh (see \fBapprofile\fR).
+.le
+.ls clean = no
+Detect and replace deviant pixels?
+.le
+.ls skybox = 1
+Box car smoothing length for sky background when using background
+subtraction. Since the background noise is often the limiting factor
+for good extraction one may box car smooth the sky to improve the
+statistics in smooth background regions at the expense of distorting
+the subtraction near spectral features. This is most appropriate when
+the sky regions are limited due to a small slit length.
+.le
+.ls saturation = INDEF
+Saturation or nonlinearity level. During variance weighted extractions
+wavelength points having any pixels above this value are excluded from the
+profile determination.
+.le
+.ls readnoise = "0."
+Read out noise in photons. This parameter defines the minimum noise
+sigma. It is defined in terms of photons (or electrons) and scales
+to the data values through the gain parameter. A image header keyword
+(case insensitive) may be specified to get the value from the image.
+.le
+.ls gain = "1."
+Detector gain or conversion factor between photons/electrons and
+data values. It is specified as the number of photons per data value.
+A image header keyword (case insensitive) may be specified to get the value
+from the image.
+.le
+.ls lsigma = 3., usigma = 3.
+Lower and upper rejection thresholds, given as a number of times the
+estimated sigma of a pixel, for cleaning.
+.le
+.ih
+ADDITIONAL PARAMETERS
+I/O parameters and the default dispersion axis are taken from the
+package parameters, the default aperture parameters from
+\fBapdefault\fR, automatic aperture finding parameters from
+\fBapfind\fR, recentering parameters from \fBaprecenter\fR, resizing
+parameters from \fBapresize\fR, parameters used for centering and
+editing the apertures from \fBapedit\fR, and tracing parameters from
+\fBaptrace\fR.
+.ih
+CURSOR COMMANDS
+The following cursor keys and colon commands are available during the
+display of the noise sigmas and noise model. See \fBapedit\fR for
+the commands for that mode.
+
+.nf
+? Print command help
+q Quit
+r Redraw
+w Window the graph (see :/help)
+I Interupt immediately
+
+:gain <value> Check or set the gain model parameter
+:readnoise <value> Check or set the read noise model parameter
+
+Also see the CURSOR MODE commands (:.help) and the windowing commands
+(:/help).
+.fi
+.ih
+DESCRIPTION
+\fBApnoise\fR computes the noise sigma as a function of data value
+using the same profile model used for weighted extraction and
+cosmic ray cleanning. In particular, the residuals used in computing the
+noise sigma are the same as those during cleanning. By looking
+at the noise sigma as a function of data value as compared to that
+predicted by the noise model based on the read out noise and gain
+parameters one can then better refine these values for proper
+rejection of cosmic rays without rejection of valid data.
+So this task can be used to check or deduce these values and also
+to adjust them to include additional sources of error such as
+flat field noise and, especially, an additional source of noise due
+to the accuracy of the profile modeling.
+
+The first part of this task follows the standard model of allowing
+one to define apertures by finding, recentering, editing, and
+tracing. If one has previously defined apertures then these
+steps can be skipped. Once the apertures are defined the apertures
+are internally extracted using the profile modeling (see \fBapprofile\fR)
+with the optional background subtraction, cleanning, and choices of
+profile fitting algorithm, "fit1d" or "fit2d". But rather than
+outputing the extracted spectrum as in \fBapsum\fR or \fBapall\fR
+or various functions of the data and profile model as in \fBapfit\fR,
+\fBapnormalize\fR, or \fBapflatten\fR, the task computes the
+residuals for all points in all apertures (essentially the same
+as the difference output of \fBapfit\fR) and determines the
+sigma (population corrected RMS) as a function of model data value
+in the specified bins. The bins are defined by a minimum and
+maximum data value (found using \fBminmax\fR, \fBimplot\fR, or
+\fBimexamine\fR) and the number of bins.
+
+The noise sigma values, with their estimated uncertainties, are then
+plotted as a function of data numer. A curve representing the specified
+read out noise and gain is also plotted. The user then has the
+option of varying these two parameters with colon commands. The
+aim of this is to find a noise model which either represents the
+measure noise sigmas or at least exceeds them so that only valid
+outliers such as cosmic rays will be rejected during cleanning.
+The interactive graphical mode only has this function. The other
+keys and colon commands are the standard ones for redrawing, windowing,
+and quitting.
+.ih
+EXAMPLES
+1. To check that the read noise and gain parameters are reasonable for
+cleaning \fBapnoise\fR is run. In this case it is assumed that the
+apertures have already been defined and traced.
+
+.nf
+ cl> minmax lsobj
+ lsobj -2.058870315551758 490.3247375488282
+ cl> apnoise lsobj 0 500 50 rece- resi- edit- trace-
+ A graph of the noise sigma for data between 0 and 500
+ data numbers is given with a line showing the
+ expected value for the current read noise and gain.
+ The read noise and gain may be varied if desired.
+ Exit with 'q'
+.fi
+.ih
+REVISIONS
+.ls APNOISE V2.11
+The "apertures" parameter can be used to select apertures for resizing,
+recentering, tracing, and extraction. This parameter name was previously
+used for selecting apertures in the recentering algorithm. The new
+parameter name for this is now "aprecenter".
+.le
+.ih
+SEE ALSO
+apbackground, approfile, apvariance, apfit, icfit, minmax,
+apdefault, apfind, aprecenter, apresize, apedit, aptrace, apsum
+.endhelp
diff --git a/noao/twodspec/apextract/doc/apnormalize.hlp b/noao/twodspec/apextract/doc/apnormalize.hlp
new file mode 100644
index 00000000..fda3fd31
--- /dev/null
+++ b/noao/twodspec/apextract/doc/apnormalize.hlp
@@ -0,0 +1,324 @@
+.help apnormalize Sep96 noao.twodspec.apextract
+.ih
+NAME
+apnormalize -- Normalize 2D apertures by 1D functions
+.ih
+USAGE
+apnormalize input output
+.ih
+PARAMETERS
+.ls input
+List of input images to be normalized.
+.le
+.ls output
+List of output image names for the normalized input images. If no output
+name is given then the input name is used as a root with the extension
+".norm" added.
+.le
+.ls apertures = ""
+Apertures to recenter, resize, trace, and normalize. This only applies
+to apertures read from the input or reference database. Any new
+apertures defined with the automatic finding algorithm or interactively
+are always selected. The syntax is a list comma separated ranges
+where a range can be a single aperture number, a hyphen separated
+range of aperture numbers, or a range with a step specified by "x<step>";
+for example, "1,3-5,9-12x2".
+.le
+.ls references = ""
+List of reference images to be used to define apertures for the input
+images. When a reference image is given it supersedes apertures
+previously defined for the input image. The list may be null, "", or
+any number of images less than or equal to the list of input images.
+There are three special words which may be used in place of an image
+name. The word "last" refers to the last set of apertures written to
+the database. The word "OLD" requires that an entry exist
+and the word "NEW" requires that the entry not exist for each input image.
+.le
+
+.ls interactive = yes
+Run this task interactively? If the task is not run interactively then
+all user queries are suppressed and interactive aperture editing and trace
+fitting are disabled.
+.le
+.ls find = yes
+Find the spectra and define apertures automatically? In order for
+spectra to be found automatically there must be no apertures for the
+input image or reference image defined in the database.
+.le
+.ls recenter = yes
+Recenter the apertures?
+.le
+.ls resize = yes
+Resize the apertures?
+.le
+.ls edit = yes
+Edit the apertures? The \fIinteractive\fR parameter must also be yes.
+.le
+.ls trace = yes
+Trace the apertures?
+.le
+.ls fittrace = yes
+Interactively fit the traced positions by a function? The \fIinteractive\fR
+parameter must also be yes.
+.le
+.ls normalize = yes
+Normalize the aperture spectra by a one dimensional function?
+.le
+.ls fitspec = yes
+Fit normalization spectrum interactively? The \fIinteractive\fR
+parameter must also be yes.
+.le
+
+.ls line = INDEF, nsum = 1
+The dispersion line (line or column perpendicular to the dispersion
+axis) and number of adjacent lines (half before and half after unless
+at the end of the image) used in finding, recentering, resizing,
+and editing operations. For tracing this is the starting line and
+the same number of lines are summed at each tracing point. A line of
+INDEF selects the middle of the image along the dispersion axis.
+A negative nsum selects a median rather than a sum except that
+tracing always uses a sum.
+.le
+.ls cennorm = no
+Normalize to the aperture center rather than the mean?
+.le
+.ls threshold = 10.
+All pixels in the normalization spectrum less than this value are replaced
+by this value.
+.le
+
+The following parameters control the normalization spectrum extraction.
+.ls background = "none"
+Type of background subtraction. The choices are "none" for no
+background subtraction, "average" to average the background within the
+background regions, or "fit" to fit across the dispersion using the
+background within the background regions. Note that the "average"
+option does not do any medianing or bad pixel checking; it is faster
+than fitting however. Background subtraction also requires that the
+background fitting parameters are properly defined. For the "average"
+option only the background sample regions parameter is used.
+.le
+.ls weights = "none"
+Type of extraction weighting. Note that if the \fIclean\fR parameter is
+set then the weights used are "variance" regardless of the weights
+specified by this parameter. The choices are:
+.ls "none"
+The pixels are summed without weights except for partial pixels at the
+ends.
+.le
+.ls "variance"
+The extraction is weighted by estimated variances of the pixels using
+a poisson noise model.
+.le
+.le
+.ls pfit = "fit1d" (fit1d|fit2d)
+Profile fitting algorithm to use with variance weighting or cleaning.
+When determining a profile the two dimensional spectrum is divided by
+an estimate of the one dimensional spectrum to form a normalized two
+dimensional spectrum profile. This profile is then smoothed by fitting
+one dimensional functions, "fit1d", along the lines or columns most closely
+corresponding to the dispersion axis or a special two dimensional
+function, "fit2d", described by Marsh (see \fBapprofile\fR).
+.le
+.ls clean = no
+Detect and replace deviant pixels?
+.le
+.ls skybox = 1
+Box car smoothing length for sky background when using background
+subtraction. Since the background noise is often the limiting factor
+for good extraction one may box car smooth the sky to improve the
+statistics in smooth background regions at the expense of distorting
+the subtraction near spectral features. This is most appropriate when
+the sky regions are limited due to a small slit length.
+.le
+.ls saturation = INDEF
+Saturation or nonlinearity level. During variance weighted extractions
+wavelength points having any pixels above this value are excluded from the
+profile determination.
+.le
+.ls readnoise = 0.
+Read out noise in photons. This parameter defines the minimum noise
+sigma. It is defined in terms of photons (or electrons) and scales
+to the data values through the gain parameter. A image header keyword
+(case insensitive) may be specified to get the value from the image.
+.le
+.ls gain = 1
+Detector gain or conversion factor between photons/electrons and
+data values. It is specified as the number of photons per data value.
+A image header keyword (case insensitive) may be specified to get the value
+from the image.
+.le
+.ls lsigma = 3., usigma = 3.
+Lower and upper rejection thresholds, given as a number of times the
+estimated sigma of a pixel, for cleaning.
+.le
+
+The following parameters are used to fit the normalization spectrum using
+the ICFIT routine.
+.ls function = "legendre"
+Fitting function for the normalization spectra. The choices are "legendre"
+polynomial, "chebyshev" polynomial, linear spline ("spline1"), and
+cubic spline ("spline3").
+.le
+.ls order = 1
+Number of polynomial terms or number of spline pieces for the fitting function.
+.le
+.ls sample = "*"
+Sample regions for fitting points. Intervals are separated by "," and an
+interval may be one point or a range separated by ":".
+.le
+.ls naverage = 1
+Number of points within a sample interval to be subaveraged or submedianed to
+form fitting points. Positive values are for averages and negative points
+for medians.
+.le
+.ls niterate = 0
+Number of sigma clipping rejection iterations.
+.le
+.ls low_reject = 3. , high_reject = 3.
+Lower and upper sigma clipping rejection threshold in units of sigma determined
+from the RMS sigma of the data to the fit.
+.le
+.ls grow = 0.
+Growing radius for rejected points (in pixels). That is, any rejected point
+also rejects other points within this distance of the rejected point.
+.le
+.ih
+ADDITIONAL PARAMETERS
+I/O parameters and the default dispersion axis are taken from the
+package parameters, the default aperture parameters from
+\fBapdefault\fR, automatic aperture finding parameters from
+\fBapfind\fR, recentering parameters from \fBaprecenter\fR, resizing
+parameters from \fBapresize\fR, parameters used for centering and
+editing the apertures from \fBapedit\fR, and tracing parameters from
+\fBaptrace\fR.
+.ih
+DESCRIPTION
+For each image in the input image list the two dimensional spectra
+defined by a set of apertures are normalized by a one dimensional
+normalization function derived by extracting and smoothing the spectrum
+by fitting a function with the \fBicfit\fR procedure. The value of the
+fitting function at each point along the dispersion, divided by the
+aperture width to form a mean or scaled to the same mean as the center
+pixel of the aperture depending on the \fIcennorm\fR parameter, is
+divided into the two dimensional input aperture. All points outside
+the apertures are set to unity.
+
+The purpose of this task is to remove a general shape from the aperture
+spectra. If low order (order = 1 for instance) functions are used then
+only the amplitudes of the spectra are affected, shifting each aperture
+to approximately unit intensity per pixel. If high order functions are
+used only the small spatial scale variations are preserved. This
+is useful for making flat field images with the spectral signature of the
+continuum source removed or for producing two dimensional normalized
+spectra similar to the task \fBonedspec.continuum\fR. For flat fields
+this algorithm retains the profile shape which may be useful for
+removing the profile response in short slit data. However, often
+one does not want the profile of the flat fielded observation to be
+modified in which case the task \fBapflatten\fR should be used.
+
+The normalization spectrum is first extracted in the same way as is
+the one dimensional extraction in \fBapsum\fR or \fBapall\fR. In
+particular the same parameters for selecting weighting and cleaning
+are available. After extraction the spectrum is fit using the
+\fBicfit\fR routine. This may be done interactively or noninteractively
+depending on the \fIinteractive\fR parameter. The default fitting
+parameters are part of this task. The goal of the fitting depends
+on the application. One may be trying to simply continuum normalize,
+in which case one wants to iteratively reject and grow the rejected
+points to exclude the lines and fit the continuum with a
+moderate order function (see \fBcontinuum\fR for more discussion).
+If one wants to simply normalize all spectra to a common flux, say to
+remove a blaze function in echelle data, then an order of 1 will
+normalize by a constant. For flat field and profile correction of
+small slits one wants to fit the large scale shape of the
+spectrum but not fit the small bumps and wiggles due to sensitivity
+variations and fringing.
+
+The smoothed extracted spectrum represents the total flux within the
+aperture. There are two choices for scaling to a normalization per
+pixel. One is to divide by the aperture width, thus computing an average
+flux normalization. In this case the peak of the spectrum will be
+greater than unity. This is done when \fIcennorm\fR = no. When this
+parameter has the value yes then the mean of the normalization spectrum
+is scaled to the mean of the aperture center, computed by linearly
+interpolating the two pixels about the traced center. This will give
+values near one for the pixels at the center of the aperture in the
+final output image.
+
+Before division of each pixel by the appropriate dispersion point in
+the normalization spectrum, all pixels below the value specified by the
+\fIthreshold\fR parameter in the normalization spectrum are replaced by
+the threshold value. This suppresses division by very small numbers.
+Finally, the pixels within the aperture are divided by the normalization
+function and the pixels outside the apertures are set to 1.
+
+The remainder of this description covers the basic steps defining the
+apertures to be used. These steps and parameter are much the same as
+in any of the other \fBapextract\fR tasks.
+
+Aperture definitions may be inherited from those of other images by
+specifying a reference image with the \fBreferences\fR parameter.
+Images in the reference list are matched with those in the input list
+in order. If the reference image list is shorter than the number of
+input images, the last reference image is used for all remaining input
+images. Thus, a single reference image may be given for all the input
+images or different reference images may be given for each input
+image. The special reference name "last" may be used to select the
+last set apertures used in any of the \fBapextract\fR tasks.
+
+If an aperture reference image is not specified or no apertures are
+found for the specified reference image, previously defined apertures
+for the input image are sought in the aperture database. Note that
+reference apertures supersede apertures for the input image. If no
+apertures are defined they may be created automatically, the \fIfind\fR
+option, or interactively in the aperture editor, if the
+\fIinteractive\fR and \fIedit\fR options are set.
+
+The functions performed by the task are selected by a set of flag
+parameters. The functions are an automatic spectrum finding and
+aperture defining algorithm (see \fBapfind\fR) which is ignored if
+apertures are already defined, automatic recentering and resizing
+algorithms (see \fBaprecenter\fR and \fBapresize\fR), an interactive
+aperture editing function (see \fBapedit\fR), a spectrum position tracing
+and trace function fit (see \fBaptrace\fR), and the main function of
+this task, the one dimensional normalization of the aperture
+profiles.
+
+Each function selection will produce a query for each input spectrum if
+the \fIinteractive\fR parameter is set. The queries are answered by
+"yes", "no", "YES", or "NO", where the upper case responses suppress
+the query for following images. There are other queries associated
+with tracing which first ask whether the operation is to be done
+interactively and, if yes, lead to queries for each aperture. If the
+\fIinteractive\fR parameter is not set then aperture editing,
+interactive trace fitting, and interactive spectrum shape fitting are ignored.
+.ih
+EXAMPLES
+To make a flat field image which leaves the total counts of the object
+images approximately unchanged from a quartz echelle or slitlet image:
+
+.nf
+ cl> apnormalize qtz001,qtz002 flat001,flat002
+ Yes find
+ No resize
+ No edit
+ Yes trace
+ Yes trace interactively
+ NO
+ Yes flatten
+ Yes fit interactively
+.fi
+.ih
+REVISIONS
+.ls APNORMALIZE V2.11
+The "apertures" parameter can be used to select apertures for resizing,
+recentering, tracing, and extraction. This parameter name was previously
+used for selecting apertures in the recentering algorithm. The new
+parameter name for this is now "aprecenter".
+.le
+.ih
+SEE ALSO
+apbackground, approfile, apvariance, apfit, icfit,
+apdefault, apfind, aprecenter, apresize, apedit, aptrace, apsum
+.endhelp
diff --git a/noao/twodspec/apextract/doc/approfiles.hlp b/noao/twodspec/apextract/doc/approfiles.hlp
new file mode 100644
index 00000000..43ae774a
--- /dev/null
+++ b/noao/twodspec/apextract/doc/approfiles.hlp
@@ -0,0 +1,131 @@
+.help approfiles Feb93 noao.twodspec.apextract
+
+.ce
+Spectrum Profile Determinations
+
+
+The foundation of variance weighted or optimal extraction, cosmic ray
+detection and removal, two dimensional flat field normalization, and
+spectrum fitting and modeling is the accurate determination of the
+spectrum profile across the dispersion as a function of wavelength.
+The previous version of the APEXTRACT package accomplished this by
+averaging a specified number of profiles in the vicinity of each
+wavelength after correcting for shifts in the center of the profile.
+This technique was sensitive to perturbations from cosmic rays
+and the exact choice of averaging parameters. The current version of
+the package uses two different algorithm which are much more stable.
+
+The basic idea is to normalize each profile along the dispersion to
+unit flux and then fit a low order function to sets of unsaturated
+points at nearly the same point in the profile parallel to the
+dispersion. The important point here is that points at the same
+distance from the profile center should have the nearly the same values
+once the continuum shape and spectral features have been divided out.
+Any variations are due to slow changes in the shape of the profile with
+wavelength, differences in the exact point on the profile, pixel
+binning or sampling, and noise. Except for the noise, the variations
+should be slow and a low order function smoothing over many points will
+minimize the noise and be relatively insensitive to bad pixels such as
+cosmic rays. Effects from bad pixels may be further eliminated by
+chi-squared iteration and clipping. Since there will be many points
+per degree of freedom in the fitting function the clipping may even be
+quite aggressive without significantly affecting the profile
+estimates. Effects from saturated pixels are minimized by excluding
+from the profile determination any profiles containing one or more
+saturated pixels as defined by the \fIsaturation\fR parameter.
+
+The normalization is, in fact, the one dimensional spectrum. Initially
+this is the simple sum across the aperture which is then updated by the
+variance weighted sum with deviant pixels possibly removed. This updated
+one dimensional spectrum is what is meant by the profile normalization
+factor in the discussion below. The two dimensional spectrum model or
+estimate is the product of the normalization factor and the profile. This
+model is used for estimating the pixel intensities and, thence, the
+variances.
+
+There are two important requirements that must be met by the profile fitting
+algorithm. First it is essential that the image data not be
+interpolated. Any interpolation introduces correlated errors and
+broadens cosmic rays to an extent that they may be confused with the
+spectrum profile, particularly when the profile is narrow. This was
+one of the problems limiting the shift and average method used
+previously. The second requirement is that data fit by the smoothing
+function vary slowly with wavelength. This is what precludes, for
+instance, fitting profile functions across the dispersion since narrow,
+marginally sampled profiles require a high order function using only a
+very few points. One exception to this, which is sometimes useful but
+of less generality, is methods which assume a model for the profile
+shape such as a gaussian. In the methods used here there is no
+assumption made about the underlying profile other than it vary
+smoothly with wavelength.
+
+These requirements lead to two fitting algorithms which the user
+selects with the \fIpfit\fR parameter. The primary method, "fit1d",
+fits low order, one dimensional functions to the lines or columns
+most nearly parallel to the dispersion. While this is intended for
+spectra which are well aligned with the image axes, even fairly large
+excursions or tilts can be adequately fit in this
+way. When the spectra become strongly tilted then single lines or
+columns may cross the actual profile relatively quickly causing the
+requirement of a slow variation to be violated. One thought is to use
+interpolation to fit points always at the same distance from the
+profile. This is ruled out by the problems introduced by
+image interpolation. However, there is a clever method which, in
+effect, fits low order polynomials parallel to the direction defined by
+tracing the spectrum but which does not interpolate the image data.
+Instead it weights and couples polynomial coefficients. This
+method was developed by Tom Marsh and is described in detail in the
+paper, "The Extraction of Highly Distorted Spectra", PASP 101, 1032,
+Nov. 1989. Here we refer to this method as the Marsh or "fit2d"
+algorithm and do not attempt to explain it further.
+
+The choice of when to use the one dimensional or the two dimensional
+fitting is left to the user. The "fit1d" algorithm is preferable since it
+is faster, easier to understand, and has proved to be very robust. The
+"fit2d" algorithm usually works just as well but is slower and has been
+seen to fail on some data. The user may simply try both to achieve the
+best results.
+
+What follows are some implementation details of the preceding ideas in the
+APEXTRACT package. For column/line fitting, the fitting function is a
+cubic spline. A base number of spline pieces is set by rounding up the
+maximum trace excursion; an excursion of 1.2 pixels would use a spline of 2
+pieces. To this base number is added the number of coefficients in the
+trace function in excess of two; i.e. the number of terms in excess of a
+linear function. This is done because if the trace wiggles a large amount
+then a higher order function will be needed to fit a line or column as the
+profile shifts under it. Finally the number of pieces is doubled
+because experience shows that for low tilts it doesn't matter but for
+large tilts this improves the results dramatically.
+
+For the Marsh algorithm there are two parameters to be set, the
+polynomial order parallel to the dispersion and the spacing between
+parallel, coupled polynomials. The algorithm requires that the spacing
+be less than a pixel to provide sufficient sampling. The spacing is
+arbitrarily set at 0.95 pixels. Because the method always fits
+polynomials to points at the same position of the profile the order
+should be 1 except for variations in the profile shape with
+wavelength. To allow for this the profile order is set at 10; i.e. a
+9th order function. A final parameter in the algorithm is the number
+of polynomials across the profile but this is obviously determined
+from the polynomial spacing and the width of the aperture including an
+extra pixel on either side.
+
+Both fitting algorithms weight the pixels by their variance as computed
+from the background and background variance if background subtraction
+is specified, the spectrum estimate from the profile and the spectrum
+normalization, and the detector noise parameters. A poisson
+plus constant gaussian readout noise model is used. The noise model is
+described further in \fBapvariance\fR.
+
+As mentioned earlier, the profile fitting can be iterated to remove
+deviant pixels. This is done by rejecting pixels greater than a
+specified number of sigmas above or below the expected value based
+on the profile, the normalization factor, the background, the
+detector noise parameters, and the overall chi square of the residuals.
+Rejected points are removed from the profile normalization and
+from the fits.
+.ih
+SEE ALSO
+apbackground apvariance apall apsum apfit apflatten
+.endhelp
diff --git a/noao/twodspec/apextract/doc/aprecenter.hlp b/noao/twodspec/apextract/doc/aprecenter.hlp
new file mode 100644
index 00000000..5a05cb36
--- /dev/null
+++ b/noao/twodspec/apextract/doc/aprecenter.hlp
@@ -0,0 +1,148 @@
+.help aprecenter Sep96 noao.twodspec.apextract
+.ih
+NAME
+aprecenter -- Recenter apertures automatically
+.ih
+USAGE
+aprecenter input
+.ih
+PARAMETERS
+.ls input
+List of input images in which apertures are to be recentered.
+.le
+.ls apertures = ""
+Apertures to recenter, resize, trace, and extract. This only applies
+to apertures read from the input or reference database. Any new
+apertures defined with the automatic finding algorithm or interactively
+are always selected. The syntax is a list comma separated ranges
+where a range can be a single aperture number, a hyphen separated
+range of aperture numbers, or a range with a step specified by "x<step>";
+for example, "1,3-5,9-12x2".
+.le
+.ls references = ""
+List of reference images to be used to define apertures for the input
+images. When a reference image is given it supersedes apertures
+previously defined for the input image. The list may be null, "", or
+any number of images less than or equal to the list of input images.
+There are three special words which may be used in place of an image
+name. The word "last" refers to the last set of apertures written to
+the database. The word "OLD" requires that an entry exist
+and the word "NEW" requires that the entry not exist for each input image.
+.le
+.ls interactive = no
+Run this task interactively? If the task is not run interactively then
+all user queries are suppressed and interactive aperture editing is
+disabled.
+.le
+.ls find = yes
+Find the spectra and define apertures automatically? In order for
+spectra to be found automatically there must be no apertures for the
+input image or reference image defined in the database.
+.le
+.ls recenter = yes
+Recenter the apertures?
+.le
+.ls resize = no
+Resize the apertures?
+.le
+.ls edit = yes
+Edit the apertures? The \fIinteractive\fR parameter must also be yes.
+.le
+
+.ls line = INDEF
+The dispersion line (line or column perpendicular to the dispersion axis) to
+be used in recentering the spectra. A value of INDEF selects the middle of the
+image.
+.le
+.ls nsum = 1
+Number of dispersion lines to be summed or medianed. The lines are taken
+around the specified dispersion line. A positive value takes a sum
+and a negative values selects a median.
+.le
+.ls aprecenter = ""
+List of apertures to be used in shift calculation.
+.le
+.ls npeaks = INDEF
+Select the specified number of apertures with the highest peak values
+to be recentered. If the number is INDEF all apertures will be selected.
+If the value is less than 1 then the value is interpreted as a fraction
+of total number of apertures.
+.le
+.ls shift = yes
+Use the median shift from recentering the selected apertures to apply to
+all apertures. The recentering is then a constant shift for all apertures.
+The median is the average of the two central values for an even number
+of apertures.
+.le
+.ih
+ADDITIONAL PARAMETERS
+I/O parameters and the default dispersion axis are taken from the
+package parameters, the default aperture parameters are taken from the
+task \fBapdefault\fR, automatic aperture finding parameters are taken
+from \fBapfind\fR, and parameters used for centering and editing the
+apertures are taken from \fBapedit\fR.
+
+When this operation is performed from the task \fBapall\fR all parameters
+except the package parameters are included in that task.
+.ih
+DESCRIPTION
+For each image in the input image list, the aperture center positions
+are redefined by centering at the specified dispersion line using the
+\fBcenter1d\fR algorithm with centering parameters from \fBapedit\fR.
+Normally this is done when inheriting apertures from an aperture
+reference image. The recentering does not change the "trace" of the
+aperture but simple adds a shift across the dispersion axis.
+
+There are a several recentering options. Each selected aperture may be
+recentered independently. However, if some or all of the spectra are
+relatively weak this may actually be worse than using the reference
+apertures defined by strong spectra or flat fields in the case of
+fibers or aperture masks. One may select a subset of apertures to be
+used in calculating shift. This is done with a the \fIaprecenter\fR
+list of aperture numbers (see
+\fBranges\fR for the syntax) and/or by selecting a specific number or
+fraction of the apertures with the strongest peak values. The list
+selection is done first and the strongest remaining apertures are used
+to satisfy the \fBnpeaks\fR value. Though some or all of the apertures
+may be recentered independently the most common case of recentering
+reference apertures is to account for detector shifts. In this case
+one expects that any shift should be common to all apertures. The
+\fIshift\fR parameter allows using the new centers for all selected
+apertures to compute a median shift to be added to ALL apertures. Using
+a median shift for all apertures is the default.
+
+The \fIfind\fR parameter allows automatically finding apertures if none
+are defined for the image or by a reference image. Since the purpose
+of this task is to recenter reference apertures it is usually the case
+that reference images are used and apertures are not defined by this
+task. One case in which the apertures from the image itself might be
+recentered is if one wants to use a different dispersion line. The
+\fIresize\fR parameter may be used to adjust the widths in a variety
+of ways based on the spectra profiles specific to each image. The
+aperture positions and any other parameters may also be edited with the
+aperture editing function if selected by the \fIapedit\fR parameter and
+the task is run interactively. The recentering algorithm may be run
+from the aperture editor using the 'g' keystroke.
+
+If the task is interactive the user is queried whether to perform
+various steps on each image. The queries may be answered with one of
+the four values "yes", "no", "YES" and "NO", where an upper case
+response suppresses all further queries to this question.
+
+The aperture recentering algorithm may be selected from nearly every task
+in the package.
+.ih
+EXAMPLES
+ cl> aprecenter newimage reference=flat
+.ih
+REVISIONS
+.ls APRECENTER V2.11
+The "apertures" parameter can be used to select apertures for resizing,
+recentering, tracing, and extraction. This parameter name was previously
+used for selecting apertures in the recentering algorithm. The new
+parameter name for this is now "aprecenter".
+.le
+.ih
+SEE ALSO
+center1d, ranges, apfind, apresize, apedit, apall
+.endhelp
diff --git a/noao/twodspec/apextract/doc/apresize.hlp b/noao/twodspec/apextract/doc/apresize.hlp
new file mode 100644
index 00000000..d8ab4774
--- /dev/null
+++ b/noao/twodspec/apextract/doc/apresize.hlp
@@ -0,0 +1,201 @@
+.help apresize Sep96 noao.twodspec.apextract
+.ih
+NAME
+apresize -- Resize apertures automatically
+.ih
+USAGE
+apresize input
+.ih
+PARAMETERS
+.ls input
+List of input images in which apertures are to be resized.
+.le
+.ls apertures = ""
+Apertures to recenter, resize, trace, and extract. This only applies
+to apertures read from the input or reference database. Any new
+apertures defined with the automatic finding algorithm or interactively
+are always selected. The syntax is a list comma separated ranges
+where a range can be a single aperture number, a hyphen separated
+range of aperture numbers, or a range with a step specified by "x<step>";
+for example, "1,3-5,9-12x2".
+.le
+.ls references = ""
+List of reference images to be used to define apertures for the input
+images. When a reference image is given it supersedes apertures
+previously defined for the input image. The list may be null, "", or
+any number of images less than or equal to the list of input images.
+There are three special words which may be used in place of an image
+name. The word "last" refers to the last set of apertures written to
+the database. The word "OLD" requires that an entry exist
+and the word "NEW" requires that the entry not exist for each input image.
+.le
+
+.ls interactive = no
+Run this task interactively? If the task is not run interactively then
+all user queries are suppressed and interactive aperture editing is
+disabled.
+.le
+.ls find = yes
+Find the spectra and define apertures automatically? In order for
+spectra to be found automatically there must be no apertures for the
+input image or reference image defined in the database.
+.le
+.ls recenter = no
+Recenter the apertures?
+.le
+.ls resize = yes
+Resize the apertures?
+.le
+.ls edit = yes
+Edit the apertures? The \fIinteractive\fR parameter must also be yes.
+.le
+
+.ls line = INDEF
+The dispersion line (line or column perpendicular to the dispersion axis) to
+be used in resizing the spectra. A value of INDEF selects the middle of the
+image.
+.le
+.ls nsum = 1
+Number of dispersion lines to be summed or medianed. The lines are taken
+around the specified dispersion line. A positive value takes a
+sum and a negative value selects a median.
+.le
+.ls llimit = INDEF, ulimit = INDEF
+Lower and upper aperture size limits. If the parameter \fIylevel\fR is
+INDEF then these limits are assigned to all apertures. Otherwise
+these parameters are used as limits to the resizing operation.
+A value of INDEF places the aperture limits at the image edge (for the
+dispersion line used).
+.le
+.ls ylevel = 0.1
+Data level at which to set aperture limits. If it is INDEF then the
+aperture limits are set at the values given by the parameters
+\fIllimit\fR and \fIulimit\fR. If it is not INDEF then it is a
+fraction of the peak or an actual data level depending on the parameter
+\fIpeak\fR. It may be relative to a local background or to zero
+depending on the parameter \fIbkg\fR.
+.le
+.ls peak = yes
+Is the data level specified by \fIylevel\fR a fraction of the peak?
+.le
+.ls bkg = yes
+Subtract a simple background when interpreting the \fBylevel\fR parameter.
+The background is a slope connecting the first minima
+away from the aperture center.
+.le
+.ls r_grow = 0.
+Change the lower and upper aperture limits by this fractional amount.
+The factor is multiplied by each limit and the result added to limit.
+.le
+.ls avglimits = no
+Apply the average lower and upper aperture limits to all apertures.
+.le
+.ih
+ADDITIONAL PARAMETERS
+I/O parameters and the default dispersion axis are taken from the
+package parameters, the default aperture parameters are taken from the
+task \fBapdefault\fR, automatic aperture finding parameters are taken
+from \fBapfind\fR, and parameters used for centering and editing the
+apertures are taken from \fBapedit\fR.
+
+When this operation is performed from the task \fBapall\fR all parameters
+except the package parameters are included in that task.
+.ih
+DESCRIPTION
+For each image in the input image list, the aperture limits are
+redefined to be either specified values or by finding the points at
+which the spectrum profile, linearly interpolated, first crosses a
+specified value moving away from the aperture center at the specified
+dispersion line. In the latter case the limits may then be increased
+or decreased by a specified percentage, a maximum lower and upper limit,
+may be imposed, and the independent limits may be averaged and the
+single values applied to all the apertures.
+
+The simplest resizing choice is to reset all the aperture limits to
+the values specified by \fIllimit\fR and \fIulimit\fR. This option
+is selected if the parameter \fIylevel\fR is INDEF.
+
+There are several options for specifying a data level at which an
+aperture is sized. The most common method (the default) is to specify
+a fraction of the peak value since this is data independent and physically
+reasonable. This is done by setting the fraction with the parameter
+\fIylevel\fR and the parameter \fIpeak\fR to yes. If the peak parameter
+is no then the level is a data value.
+
+The levels may be relative to zero, as might be used with fibers or
+high dispersion / high signal-to-noise data, or relative to a local
+linear background, as would be appropriate for slit data having a
+significant background. A background is found and used if the
+parameter \fIbkg\fR is set. The background determination is very
+simple. Starting at the peak two background points are found, one in
+each direction, which are inflection points; i.e. the first pixels
+which are less than their two neighbors. A linear slope is fit and
+subtracted for the purposes of measuring the peak and setting the
+aperture limits. Note that if the slope is significant the actual
+limits may not correspond to the intercepts of a line at constant data
+value.
+
+Once aperture limits, a distance relative to the center, are determined
+they are increased or decreased by a percentage, expressed as a fraction,
+given by the parameter \fIr_grow\fR. To illustrate the operation,
+if xlow is the initial lower limit then the final lower limit will be:
+
+ xlow final = xlow * (1 + r_grow)
+
+A value of zero leaves the aperture limits unchanged.
+
+After the aperture limits are found, based on the above steps, a fixed lower
+limit, given by the parameter \fIllimit\fR, is applied to the lower
+aperture points and, similarly, a fixed upper limit is applied to the
+upper aperture points. This feature protects against absurdly wide apertures.
+
+Finally, if the parameter \fIavglimits\fR is set the individual aperture
+limits are averaged to form an average aperture. This average aperture
+is then assigned to all apertures. This option allows keeping common
+aperture sizes but allowing variation due to seeing changes.
+
+The resizing algorithm is available in the interactive aperture editor.
+Here one may select individual apertures or all apertures using the
+'a' switch. The resizing algorithm described above is selected using
+the 'z' key. An simple alternative is the 'y' key which resizes
+apertures to the y level marked by the cursor.
+
+If the task is interactive the user is queried whether to perform
+various steps on each image. The queries may be answered with one of
+the four values "yes", "no", "YES" and "NO", where an upper case
+response suppresses all further queries to this question.
+
+The aperture resizing algorithm may be selected from nearly every task
+in the package with the \fIresize\fR parameter.
+.ih
+EXAMPLES
+1. To resize all apertures to the range -4 to 4:
+
+ cl> apresize image llimit=-4 ulimit=4 ylevel=INDEF
+
+2. To resize all aperture to a point which is 5% of the peak relative
+to a local background:
+
+ cl> apresize image ylevel=.05 peak+ bkg+
+
+3. To resize all apertures to the point where the data exceeds 100
+data units:
+
+ cl> apresize image ylevel=100 peak- bkg-
+
+4. To resize all apertures to default values of the task except
+averaging all the results at the end:
+
+ cl> apresize image avg+
+.ih
+REVISIONS
+.ls APRESIZE V2.11
+The "apertures" parameter can be used to select apertures for resizing,
+recentering, tracing, and extraction. This parameter name was previously
+used for selecting apertures in the recentering algorithm. The new
+parameter name for this is now "aprecenter".
+.le
+.ih
+SEE ALSO
+center1d, ranges, apfind, aprecenter, apedit, apall
+.endhelp
diff --git a/noao/twodspec/apextract/doc/apscatter.hlp b/noao/twodspec/apextract/doc/apscatter.hlp
new file mode 100644
index 00000000..902c57a8
--- /dev/null
+++ b/noao/twodspec/apextract/doc/apscatter.hlp
@@ -0,0 +1,253 @@
+.help apscatter Sep96 noao.twodspec.apextract
+.ih
+NAME
+apscatter -- Fit and subtract scattered light
+.ih
+USAGE
+apscatter input output
+.ih
+PARAMETERS
+.ls input
+List of input images in which to determine and subtract scattered light.
+.le
+.ls output
+List of output scattered light subtracted images. If no output images
+are specified or the end of the output list is reached before the end
+of the input list then the output image will overwrite the input image.
+.le
+.ls apertures = ""
+Apertures to recenter, resize, trace, and extract. All apertures are
+used to define the scattered light region. This only applies
+to apertures read from the input or reference database. Any new
+apertures defined with the automatic finding algorithm or interactively
+are always selected. The syntax is a list comma separated ranges
+where a range can be a single aperture number, a hyphen separated
+range of aperture numbers, or a range with a step specified by "x<step>";
+for example, "1,3-5,9-12x2".
+.le
+.ls scatter = ""
+List of scattered light images. This is the scattered light subtracted
+from the input image. If no list is given or the end of the list is
+reached before the end of the input list then no scattered light image
+is created.
+.le
+.ls references = ""
+List of reference images to be used to define apertures for the input
+images. When a reference image is given it supersedes apertures
+previously defined for the input image. The list may be null, "", or
+any number of images less than or equal to the list of input images.
+There are three special words which may be used in place of an image
+name. The word "last" refers to the last set of apertures written to
+the database. The word "OLD" requires that an entry exist
+and the word "NEW" requires that the entry not exist for each input image.
+.le
+
+.ls interactive = yes
+Run this task interactively? If the task is not run interactively then
+all user queries are suppressed and interactive aperture editing, trace
+fitting, and interactive scattered light fitting are disabled.
+.le
+.ls find = yes
+Find the spectra and define apertures automatically? In order for
+spectra to be found automatically there must be no apertures for the
+input image or reference image defined in the database.
+.le
+.ls recenter = yes
+Recenter the apertures?
+.le
+.ls resize = yes
+Resize the apertures?
+.le
+.ls edit = yes
+Edit the apertures? The \fIinteractive\fR parameter must also be yes.
+.le
+.ls trace = yes
+Trace the apertures?
+.le
+.ls fittrace = yes
+Interactively fit the traced positions by a function? The \fIinteractive\fR
+parameter must also be yes.
+.le
+.ls subtract = yes
+Subtract the scattered light from the input images?
+.le
+.ls smooth = yes
+Smooth the cross-dispersion fits along the dispersion?
+.le
+.ls fitscatter = yes
+Fit the scattered light across the dispersion interactively?
+The \fIinteractive\fR parameter must also be yes.
+.le
+.ls fitsmooth = yes
+Smooth the cross-dispersion fits along the dispersion?
+The \fIinteractive\fR parameter must also be yes.
+.le
+
+.ls line = INDEF, nsum = 1
+The dispersion line (line or column perpendicular to the dispersion
+axis) and number of adjacent lines (half before and half after unless
+at the end of the image) used in finding, recentering, resizing,
+and editing operations. For tracing this is the starting line and
+the same number of lines are summed at each tracing point. This is
+also the initial line for interactive fitting of the scattered light.
+A line of INDEF selects the middle of the image along the dispersion
+axis. A positive nsum takes a sum and a negative value selects a
+median except that tracing always uses a sum.
+.le
+
+.ls buffer = 1.
+Buffer distance from the aperture edges to be excluded in selecting the
+scattered light pixels to be used.
+.le
+.ls apscat1 = ""
+Fitting parameters across the dispersion. This references an additional
+set of parameters for the ICFIT package. The default is the "apscat1"
+parameter set. See below for additional information.
+.le
+.ls apscat2 = ""
+Fitting parameters along the dispersion. This references an additional
+set of parameters for the ICFIT package. The default is the "apscat2"
+parameter set. See below for additional information.
+.le
+.ih
+ICFIT PARAMETERS FOR FITTING THE SCATTERED LIGHT
+There are two additional parameter sets which define the parameters used
+for fitting the scattered light across the dispersion and along the
+dispersion. The default parameter sets are \fBapscat1\fR and \fBapscat2\fR.
+The parameters may be examined and edited by either typing their names
+or by typing ":e" when editing the main parameter set with \fBeparam\fR
+and with the cursor pointing at the appropriate parameter set name.
+These parameters are used by the ICFIT package and a further
+description may be found there.
+
+.ls function = "spline3" (apscat1 and apscat2)
+Fitting function for the scattered light across and along the dispersion.
+The choices are "legendre" polynomial, "chebyshev" polynomial,
+linear spline ("spline1"), and cubic spline ("spline3").
+.le
+.ls order = 1 (apscat1 and apscat2)
+Number of polynomial terms or number of spline pieces for the fitting function.
+.le
+.ls sample = "*" (apscat1 and apscat2)
+Sample regions for fitting points. Intervals are separated by "," and an
+interval may be one point or a range separated by ":".
+.le
+.ls naverage = 1 (apscat1 and apscat2)
+Number of points within a sample interval to be subaveraged or submedianed to
+form fitting points. Positive values are for averages and negative points
+for medians.
+.le
+.ls niterate = 5 (apscat1), niterate = 0 (apscat2)
+Number of sigma clipping rejection iterations.
+.le
+.ls low_reject = 5. (apscat1) , low_reject = 3. (apscat2)
+Lower sigma clipping rejection threshold in units of sigma determined
+from the RMS sigma of the data to the fit.
+.le
+.ls high_reject = 2. (apscat1) , high_reject = 3. (apscat2)
+High sigma clipping rejection threshold in units of sigma determined
+from the RMS sigma of the data to the fit.
+.le
+.ls grow = 0. (apscat1 and apscat2)
+Growing radius for rejected points (in pixels). That is, any rejected point
+also rejects other points within this distance of the rejected point.
+.le
+.ih
+ADDITIONAL PARAMETERS
+I/O parameters and the default dispersion axis are taken from the
+package parameters, the default aperture parameters from
+\fBapdefault\fR, automatic aperture finding parameters from
+\fBapfind\fR, recentering parameters from \fBaprecenter\fR, resizing
+parameters from \fBapresize\fR, parameters used for centering and
+editing the apertures from \fBapedit\fR, and tracing parameters from
+\fBaptrace\fR.
+.ih
+DESCRIPTION
+The scattered light outside the apertures defining the two dimensional
+spectra is extracted, smoothed, and subtracted from each input image. The
+approach is to first select the pixels outside the defined apertures
+and outside a buffer distance from the edge of any aperture at each
+point along the dispersion independently. A one dimensional function
+is fit using the \fBicfit\fR package. This fitting uses an iterative
+algorithm to further reject high values and thus fit the minima between
+the spectra. (This even works reasonably well if no apertures are
+defined). Because each fit is done independently the scattered light
+thus determined will not be smooth along the dispersion. If desired
+each line along the dispersion in the scattered light surface may then
+be smoothed by again fitting a one dimensional function using the
+\fBicfit\fR package. The final scattered light surface is then
+subtracted from the input image to form the output image. The
+scattered light surface may be output if desired.
+
+The reason for using two one dimensional fits as opposed to a surface fit
+is that the actual shape of the scattered light is often not easily modeled
+by a simple two dimensional function. Also the one dimensional function
+fitting offers more flexibility in defining functions and options as
+provided by the \fBicfit\fR package.
+
+The organization of the task is like the other tasks in the package
+which has options for defining apertures using a reference image,
+defining apertures through an automatic finding algorithm (see
+\fBapfind\fR), automatically recentering or resizing the apertures (see
+\fBaprecenter\fR and \fBapresize\fR), interactively editing the
+apertures (see \fBapedit\fR), and tracing the positions of the spectra
+as a function of dispersion position (see \fBaptrace\fR). Though
+unlikely, the actual scattered light subtraction operation may be
+suppressed when the parameter \fIsubtract\fR is no. If the scattered
+light determination and fitting is done interactively (the
+\fIinteractive\fR parameter set to yes) then the user is queried
+whether or not to do the fitting and subtraction for each image. The
+responses are "yes", "no", "YES", or "NO", where the upper case
+queries suppress this query for the following images. When the task is
+interactive there are further queries for each step of the operation
+which may also be answered both individually or collectively for all
+other input images using the four responses.
+
+When the scattered light operation is done interactively the user may
+set the fitting parameters for the scattered light functions both
+across and along the dispersion interactively. Initially the central
+line or column is used but after exiting (with 'q') a prompt is given
+for selecting additional lines or columns and for changing the buffer
+distance. Note that the point of the interactive stage is to set the
+fitting parameters. When the entire image is finally fit the last set
+of fitting parameters are used for all lines or columns.
+
+The default fitting parameters are organized as separate parameter sets
+called \fBapscat1\fR for the first fits across the dispersion and
+\fBapscat2\fR for the second smoothing fits along the dispersion.
+Changes to these parameters made interactively during execution of
+this task are updated in the parameter sets. The general idea for
+these parameters is that when fitting the pixels from between the
+apertures the iteration and rejection thresholds are set to eliminate
+high values while for smoothing along the dispersion a simple smooth
+function is all that is required.
+.ih
+EXAMPLES
+1. To subtract the scattered light from a set of images to form a
+new set of images:
+
+ cl> apscatter raw* %raw%new%*
+
+This example uses a substitution in the names from raw to new.
+By default this would be done interactively
+
+2. To subtract the scattered light in place and save the scattered light
+images:
+
+ cl> apscatter im* "" scatter="s//im*" ref=im1 interact-
+
+The prefix s is added to the original names for the scattered light.
+This operation is done noninteractively using a reference spectrum
+to define the apertures.
+.ih
+REVISIONS
+.ls APSCATTER V2.11
+The "apertures" parameter can be used to select apertures for resizing,
+recentering, tracing, and extraction. This parameter name was previously
+used for selecting apertures in the recentering algorithm. The new
+parameter name for this is now "aprecenter".
+.le
+.ih
+SEE ALSO
+apfind, aprecenter, apresize, apedit, aptrace, apsum, apmask, icfit
+.endhelp
diff --git a/noao/twodspec/apextract/doc/apsum.hlp b/noao/twodspec/apextract/doc/apsum.hlp
new file mode 100644
index 00000000..6fa7ad0e
--- /dev/null
+++ b/noao/twodspec/apextract/doc/apsum.hlp
@@ -0,0 +1,402 @@
+.help apsum Sep96 noao.twodspec.apextract
+.ih
+NAME
+apsum -- Extract one dimensional sums across the apertures
+.ih
+USAGE
+apsum input
+.ih
+PARAMETERS
+.ls input
+List of input images containing apertures to be extracted.
+.le
+.ls output = ""
+List of output rootnames for the extracted spectra. If the null
+string is given or the end of the output list is reached before the end
+of the input list then the input image name is used as the output rootname.
+This will not conflict with the input image since an aperture number
+extension is added for onedspec format, the extension ".ms" for multispec
+format, or the extension ".ec" for echelle format.
+.le
+.ls apertures = ""
+Apertures to recenter, resize, trace, and extract. This only applies
+to apertures read from the input or reference database. Any new
+apertures defined with the automatic finding algorithm or interactively
+are always selected. The syntax is a list comma separated ranges
+where a range can be a single aperture number, a hyphen separated
+range of aperture numbers, or a range with a step specified by "x<step>";
+for example, "1,3-5,9-12x2".
+.le
+.ls format = "multispec" (onedspec|multispec|echelle|strip)
+Format for output extracted spectra. "Onedspec" format extracts each
+aperture to a separate image while "multispec" and "echelle" extract
+multiple apertures for the same image to a single output image.
+The "multispec" and "echelle" format selections differ only in the
+extension added. The "strip" format produces a separate 2D image in
+which each column or line along the dispersion axis is shifted to
+exactly align the aperture based on the trace information.
+.le
+.ls references = ""
+List of reference images to be used to define apertures for the input
+images. When a reference image is given it supersedes apertures
+previously defined for the input image. The list may be null, "", or
+any number of images less than or equal to the list of input images.
+There are three special words which may be used in place of an image
+name. The word "last" refers to the last set of apertures written to
+the database. The word "OLD" requires that an entry exist
+and the word "NEW" requires that the entry not exist for each input image.
+.le
+.ls profiles = ""
+List of profile images for variance weighting or cleanning. If variance
+weighting or cleanning a profile of each aperture is computed from the
+input image unless a profile image is specified, in which case the
+profile is computed from the profile image. The profile image must
+have the same dimensions and dispersion and it is assumed that the
+spectra have the same position and profile shape as in the object
+spectra. Use of a profile image is generally not required even for
+faint input spectra but the option is available for those who wish
+to use it.
+.le
+
+.ls interactive = yes
+Run this task interactively? If the task is not run interactively then
+all user queries are suppressed and interactive aperture editing, trace
+fitting, and extraction review are disabled.
+.le
+.ls find = yes
+Find the spectra and define apertures automatically? In order for
+spectra to be found automatically there must be no apertures for the
+input image or reference image defined in the database.
+.le
+.ls recenter = no
+Recenter the apertures?
+.le
+.ls resize = no
+Resize the apertures?
+.le
+.ls edit = yes
+Edit the apertures? The \fIinteractive\fR parameter must also be yes.
+.le
+.ls trace = yes
+Trace the apertures?
+.le
+.ls fittrace = yes
+Interactively fit the traced positions by a function? The \fIinteractive\fR
+parameter must also be yes.
+.le
+.ls extract = yes
+Extract the one dimensional aperture sums?
+.le
+.ls extras = no
+Extract the raw spectrum (if variance weighting is used), the sky spectrum
+(if background subtraction is used), and variance spectrum (if variance
+weighting is used)? This information is extracted to the third dimension
+of the output image.
+.le
+.ls review = yes
+Review the extracted spectra? The \fIinteractive\fR parameter must also be
+yes.
+.le
+
+.ls line = INDEF, nsum = 10
+The dispersion line (line or column perpendicular to the dispersion
+axis) and number of adjacent lines (half before and half after unless
+at the end of the image) used in finding, recentering, resizing,
+and editing operations. For tracing this is the starting line and
+the same number of lines are summed at each tracing point. A line of
+INDEF selects the middle of the image along the dispersion axis.
+A positive nsum takes a sum while a negative value selects a median
+except that tracing always uses a sum.
+.le
+
+.ls background = "none" (none|average|median|minimum|fit)
+Type of background subtraction. The choices are "none" for no background
+subtraction, "average" to average the background within the background
+regions, "median" to use the median in the background regions, "minimum" to
+use the minimum in the background regions, or "fit" to fit across the
+dispersion using the background within the background regions. Note that
+the "average" option does not do any medianing or bad pixel checking,
+something which is recommended. The fitting option is slower than the
+other options and requires additional fitting parameter.
+.le
+.ls weights = "none"
+Type of extraction weighting. Note that if the \fIclean\fR parameter is
+set then the weights used are "variance" regardless of the weights
+specified by this parameter. The choices are:
+.ls "none"
+The pixels are summed without weights except for partial pixels at the
+ends.
+.le
+.ls "variance"
+The extraction is weighted by the variance based on the data values
+and a poisson/ccd model using the \fIgain\fR and \fIreadnoise\fR
+parameters.
+.le
+.le
+.ls pfit = "fit1d" (fit1d|fit2d)
+Profile fitting algorithm to use with variance weighting or cleaning.
+When determining a profile the two dimensional spectrum is divided by
+an estimate of the one dimensional spectrum to form a normalized two
+dimensional spectrum profile. This profile is then smoothed by fitting
+one dimensional functions, "fit1d", along the lines or columns most closely
+corresponding to the dispersion axis or a special two dimensional
+function, "fit2d", described by Marsh (see \fBapprofile\fR).
+.le
+.ls clean = no
+Detect and replace deviant pixels?
+.le
+.ls skybox = 1
+Box car smoothing length for sky background when using background
+subtraction. Since the background noise is often the limiting factor
+for good extraction one may box car smooth the sky to improve the
+statistics in smooth background regions at the expense of distorting
+the subtraction near spectral features. This is most appropriate when
+the sky regions are limited due to a small slit length.
+.le
+.ls saturation = INDEF
+Saturation or nonlinearity level in data units. During variance weighted
+extractions wavelength points having any pixels above this value are
+excluded from the profile determination and the sigma spectrum extraction
+output, if selected by the \fIextras\fR parameter, flags wavelengths with
+saturated pixels with a negative sigma.
+.le
+.ls readnoise = 0.
+Read out noise in photons. This parameter defines the minimum noise
+sigma. It is defined in terms of photons (or electrons) and scales
+to the data values through the gain parameter. A image header keyword
+(case insensitive) may be specified to get the value from the image.
+.le
+.ls gain = 1
+Detector gain or conversion factor between photons/electrons and
+data values. It is specified as the number of photons per data value.
+A image header keyword (case insensitive) may be specified to get the value
+from the image.
+.le
+.ls lsigma = 4., usigma = 4.
+Lower and upper rejection thresholds, given as a number of times the
+estimated sigma of a pixel, for cleaning.
+.le
+.ls nsubaps = 1
+During extraction it is possible to equally divide the apertures into
+this number of subapertures. For multispec format all subapertures will
+be in the same file with aperture numbers of 1000*(subap-1)+ap where
+subap is the subaperture (1 to nsubaps) and ap is the main aperture
+number. For echelle format there will be a separate echelle format
+image containing the same subaperture from each order. The name
+will have the subaperture number appended. For onedspec format
+each subaperture will be in a separate file with extensions and
+aperture numbers as in the multispec format.
+.le
+.ih
+ADDITIONAL PARAMETERS
+I/O parameters and the default dispersion axis are taken from the
+package parameters, the default aperture parameters from
+\fBapdefault\fR, automatic aperture finding parameters from
+\fBapfind\fR, recentering parameters from \fBaprecenter\fR, resizing
+parameters from \fBapresize\fR, parameters used for centering and
+editing the apertures from \fBapedit\fR, and tracing parameters from
+\fBaptrace\fR.
+
+When this operation is performed from the task \fBapall\fR all
+parameters except the package parameters are included in that task.
+.ih
+DESCRIPTION
+For each image in the input image list, the two dimensional spectra are
+extracted to one dimensional spectra by summing the pixels across the
+dispersion axis at each wavelength along the dispersion axis within a
+set of defined apertures. The extraction apertures consist of an
+aperture number, a beam number, a title, a center, limits relative to
+the center, a curve describing shifts of the aperture center across the
+dispersion axis as a function of the wavelength, and parameters for
+background fitting and subtraction. See \fBapextract\fR for a more
+detailed discussion of the aperture structures.
+
+The extracted spectra are recorded in one, two, or three dimensional
+images depending on the \fIformat\fR and \fIextras\fR parameters. The
+output image rootnames are specified by the \fIoutput\fR list. If the
+list is empty or shorter than the input list the missing names are
+taken to be the same as the input image names. Because the rootnames
+have extensions added it is common to default to the input names in
+order to preserve a naming relation between the input two dimensional
+spectra and the extracted spectra.
+
+When the parameter \fIextras\fR=no only the extracted spectra are
+output. If the format parameter \fIformat\fR="onedspec" the output
+aperture extractions are one dimensional images with names formed from
+the output rootname and a numeric extension given by the aperture
+number; i.e. root.0001 for aperture 1. Note that there will be as many
+output images as there are apertures for each input image, all with the
+same output rootname but with different aperture extensions. The
+aperture beam number associated with each aperture is recorded in the
+output image under the keyword BEAM-NUM. The output image name format
+and the BEAM-NUM entry in the image are chosen to be compatible with
+the \fBonedspec\fR package.
+
+If the format parameter is "echelle" or "multispec" the output aperture
+extractions are put into a two dimensional image with a name formed from
+the output rootname and the extension ".ech" or ".ms". Each line in
+the output image corresponds to one aperture. Thus in this format
+there is one output image for each input image. These are the preferred
+output formats for reasons of compactness and ease of handling. These
+formats are compatible with the \fBonedspec\fR, \fBechelle\fR, and
+\fBmsred\fR packages. The relation between the line and the aperture
+numbers is given by the header parameter APNUMn where n is the line and
+the value is the aperture number and other numeric information.
+
+If the \fIextras\fR parameter is set to yes then the above formats
+become three dimensional. Each plane in the third dimension contains
+associated information for the spectra in the first plane. If variance
+weighted extractions are done the unweighted spectra are recorded. If
+background subtraction is done the background spectra are recorded. If
+variance weighted extractions are done the sigma spectrum (the
+estimated sigma of each spectrum pixel based on the individual
+variances of the pixels summed) is recorded. The order of the
+additional information is as given above. For example, an unweighted
+extraction with background subtraction will have one additional plane
+containing the sky spectra while a variance weighted extraction with
+background subtractions will have the variance weighted spectra, the
+unweighted spectra, the background spectra, and the sigma spectra in
+consecutive planes.
+
+Aperture definitions may be inherited from those of other images by
+specifying a reference image with the \fBreferences\fR parameter.
+Images in the reference list are matched with those in the
+input list in order. If the reference image list is shorter than the
+number of input images, the last reference image is used for all
+remaining input images. Thus, a single reference image may be given
+for all the input images or different reference images may be given for
+each input image. The special reference name "last" may be used to
+select the last set apertures used in any of the \fBapextract\fR tasks.
+
+If an aperture reference image is not specified or no apertures are
+found for the specified reference image, previously defined apertures
+for the input image are sought in the aperture database. Note that
+reference apertures supersede apertures for the input image. If no
+apertures are defined they may be created automatically, the \fIfind\fR
+option, or interactively in the aperture editor, if the
+\fIinteractive\fR and \fIedit\fR options are set.
+
+The functions performed by the task are selected by a set of flag
+parameters. The functions are an automatic spectrum finding and
+aperture defining algorithm (see \fBapfind\fR) which is ignored if
+apertures are already defined, automatic recentering and resizing
+algorithms (see \fBaprecenter\fR and \fBapresize\fR), an interactive
+aperture editing function (see \fBapedit\fR), a spectrum position tracing
+and trace function fit (see \fBaptrace\fR), and the main function of
+this task, one dimensional spectrum extraction.
+
+Each function selection will produce a query for each input spectrum if
+the \fIinteractive\fR parameter is set. The queries are answered by
+"yes", "no", "YES", or "NO", where the upper case responses suppress
+the query for following images. There are other queries associated
+with tracing and extracted spectrum review which first ask whether the
+operation is to be done interactively and, if yes, lead to queries for
+each aperture. The cursor keys available during spectrum review are
+minimal, only the CURSOR MODE keys for expanding and adjusting the
+graph are available and the quit key 'q'. If the \fIinteractive\fR
+parameter is not set then aperture editing, interactive trace fitting,
+and spectrum review are ignored.
+
+Background sky subtraction is done during the extraction based on
+background regions and parameters defined by the default parameters or
+changed during the interactive setting of the apertures. The background
+subtraction options are to do no background subtraction, subtract the
+average, median, or minimum of the pixels in the background regions, or to
+fit a function and subtract the function from under the extracted object
+pixels. The background regions are specified in pixels from
+the aperture center and follow changes in center of the spectrum along the
+dispersion. The syntax is colon separated ranges with multiple ranges
+separated by a comma or space. The background fitting uses the \fBicfit\fR
+routines which include medians, iterative rejection of deviant points, and
+a choice of function types and orders. Note that it is important to use a
+method which rejects cosmic rays such as using either medians over all the
+background regions (\fIbackground\fR = "median") or median samples during
+fitting (\fIb_naverage\fR < -1). The background subtraction algorithm and
+options are described in greater detail in \fBapsum\fR and
+\fBapbackground\fR.
+
+Since the background noise is often the limiting factor for good
+extraction one may box car smooth the sky to improve the statistics in
+smooth background regions at the expense of distorting the subtraction
+near spectra features. This is most appropriate when the sky region is
+limited due to small slit length. The smoothing length is specified by
+the parameter \fIskybox\fR.
+
+For a more extended discussion about the background determination see
+\fBapbackground\fR.
+
+The aperture extractions consists of summing all the background
+subtracted pixel values at a given wavelength within the aperture
+limits. The aperture limits form a fixed width aperture but the center
+varies smoothly to follow changes in the position of the spectrum
+across the dispersion axis. At the ends of the aperture partial pixels
+are used.
+
+The pixels in the sum may be weighted as specified by the \fIweights\fR
+parameter. If the weights parameter is "none" and the \fIclean\fR
+parameter is no then the simple sum of the pixels (with fractional
+endpoints) is extracted. If the weights parameter is "variance" or if
+the \fBclean\fR parameter is yes the pixels are weighted by their
+estimated variance derived from a noise model based on the \fIgain\fR
+and \fIreadnoise\fR parameters and a smooth profile function. Normally
+the profile function is determined from the data being extracted.
+However, one may substitute a "profile" image as specified by the
+\fIprofiles\fR parameter for computing the profile. This requires that
+the profile image have spectra of identical position and profile as
+the image being extracted. For example, this would likely be the case
+with fiber spectra and an off-telescope spectrograph and a strong flat
+field or object spectrum could be used for weak spectra. Note that
+experience has shown that even for very weak spectra there is little
+improvement with using a separate profile image but the user is free
+to experiment.
+
+When the \fIclean\fR parameter is set pixels deviating by more than a
+specified number of sigma from the profile function are excluded from the
+variance weighted sum. Note that the \fIclean\fR parameter always selects
+variance weights. For a more complete discussion of the extraction sums,
+variance weighting, cleaning, the noise model, and profile function
+determination see \fBapvariance\fR and \fBapprofiles\fR.
+.ih
+EXAMPLES
+1. To simply extract the spectra from a multislit observation:
+
+ cl> apsum multislit1
+
+The positions of the slits are defined using either automatic finding
+or with the aperture editor. The positions of the slits are traced if
+necessary and then the apertures are extracted to the image
+"multslit1.ms". The steps of defining the slit positions and tracing
+can be done as part of this command or previously using the other tasks
+in the \fBapextract\fR package.
+.ih
+REVISIONS
+.ls APSUM V2.11
+The "apertures" parameter can be used to select apertures for resizing,
+recentering, tracing, and extraction. This parameter name was previously
+used for selecting apertures in the recentering algorithm. The new
+parameter name for this is now "aprecenter".
+
+The "nsubaps" parameter now allows onedspec and echelle output formats.
+The echelle format is appropriate for treating each subaperture as
+a full echelle extraction.
+
+The dispersion axis parameter was moved to purely a package parameter.
+
+As a final step when computing a weighted/cleaned spectrum the total
+fluxes from the weighted spectrum and the simple unweighted spectrum
+(excluding any deviant and saturated pixels) are computed and a
+"bias" factor of the ratio of the two fluxes is multiplied into
+the weighted spectrum and the sigma estimate. This makes the total
+fluxes the same. In this version the bias factor is recorded in the logfile
+if one is kept. Also a check is made for unusual bias factors.
+If the two fluxes disagree by more than a factor of two a warning
+is given on the standard output and the logfile with the individual
+total fluxes as well as the bias factor. If the bias factor is
+negative a warning is also given and no bias factor is applied.
+In the previous version a negative (inverted) spectrum would result.
+.le
+.ih
+SEE ALSO
+apbackground, apvariance, approfile,
+apdefault, apfind, aprecenter, apresize, apedit, aptrace, apall
+.endhelp
diff --git a/noao/twodspec/apextract/doc/aptrace.hlp b/noao/twodspec/apextract/doc/aptrace.hlp
new file mode 100644
index 00000000..3b9ddd38
--- /dev/null
+++ b/noao/twodspec/apextract/doc/aptrace.hlp
@@ -0,0 +1,354 @@
+.help aptrace Sep96 noao.twodspec.apextract
+.ih
+NAME
+aptrace -- Trace spectra for aperture extraction
+.ih
+USAGE
+.nf
+aptrace images
+.fi
+.ih
+PARAMETERS
+.ls input
+List of input images to be traced.
+.le
+.ls apertures = ""
+Apertures to recenter, resize, trace, and extract. This only applies
+to apertures read from the input or reference database. Any new
+apertures defined with the automatic finding algorithm or interactively
+are always selected. The syntax is a list comma separated ranges
+where a range can be a single aperture number, a hyphen separated
+range of aperture numbers, or a range with a step specified by "x<step>";
+for example, "1,3-5,9-12x2".
+.le
+.ls references = ""
+List of reference images to be used to define apertures for the input
+images. When a reference image is given it supersedes apertures
+previously defined for the input image. The list may be null, "", or
+any number of images less than or equal to the list of input images.
+There are three special words which may be used in place of an image
+name. The word "last" refers to the last set of apertures written to
+the database. The word "OLD" requires that an entry exist
+and the word "NEW" requires that the entry not exist for each input image.
+.le
+
+.ls interactive = yes
+Run this task interactively? If the task is not run interactively then
+all user queries are suppressed and interactive aperture editing and trace
+fitting are disabled.
+.le
+.ls find = yes
+Find the spectra and define apertures automatically? In order for
+spectra to be found automatically there must be no apertures for the
+input image or reference image defined in the database.
+.le
+.ls recenter = no
+Recenter the apertures?
+.le
+.ls resize = yes
+Resize the apertures?
+.le
+.ls edit = yes
+Edit the apertures? The \fIinteractive\fR parameter must also be yes.
+.le
+.ls trace = yes
+Trace the apertures?
+.le
+.ls fittrace = yes
+Interactively fit the traced positions by a function? The \fIinteractive\fR
+parameter must also be yes.
+.le
+
+.ls line = INDEF, nsum = 1
+The dispersion line (line or column perpendicular to the dispersion
+axis) and number of adjacent lines (half before and half after unless
+at the end of the image) used in finding, recentering, resizing,
+and editing operations. For tracing this is the starting line and
+the same number of lines are summed at each tracing point. A line of
+INDEF selects the middle of the image along the dispersion axis.
+A positive nsum selects the number of lines to sum while a negative
+value selects a median. Tracing always uses a sum.
+.le
+.ls step = 10
+Step along the dispersion axis between determination of the spectrum
+positions.
+.le
+.ls nlost = 3
+Number of consecutive steps in which the profile is lost before quitting
+the tracing in one direction. To force tracing to continue through
+regions of very low signal this parameter can be made large. Note,
+however, that noise may drag the trace away before it recovers.
+.le
+
+The following parameters are the defaults used to fit the traced positions
+by a function of the dispersion line. These parameters are those used by
+the ICFIT package.
+.ls function = "legendre"
+Default trace fitting function. The fitting function types are
+"chebyshev" polynomial, "legendre" polynomial, "spline1" linear spline, and
+"spline3" cubic spline.
+.le
+.ls order = 2
+Default trace function order. The order refers to the number of
+terms in the polynomial functions or the number of spline pieces in the spline
+functions.
+.le
+.ls sample = "*"
+Default fitting sample. The sample is given by a set of colon separated
+ranges each separated by either whitespace or commas. The string "*" refers
+to all points.
+.le
+.ls naverage = 1
+Default number of points to average or median. Positive numbers
+average that number of sequential points to form a fitting point.
+Negative numbers median that number, in absolute value, of sequential
+points. A value of 1 does no averaging and each data point is used in the
+.le
+.ls niterate = 0
+Default number of rejection iterations. If greater than zero the fit is
+used to detect deviant traced positions and reject them before repeating the
+fit. The number of iterations of this process is given by this parameter.
+.le
+.ls low_reject = 3., high_reject = 3.
+Default lower and upper rejection sigma. If greater than zero traced
+points deviating from the fit below and above the fit by more than this
+number of times the sigma of the residuals are rejected before refitting.
+.le
+.ls grow = 0.
+Default reject growing radius. Traced points within a distance given by this
+parameter of any rejected point are also rejected.
+.le
+.ih
+ADDITIONAL PARAMETERS
+I/O parameters and the default dispersion axis are taken from the
+package parameters, the default aperture parameters from
+\fBapdefault\fR, automatic aperture finding parameters from
+\fBapfind\fR, recentering parameters from \fBaprecenter\fR, resizing
+parameters from \fBapresize\fR, and parameters used for centering and
+editing the apertures from \fBapedit\fR.
+
+When this operation is performed from the task \fBapall\fR all parameters
+except the package parameters are included in that task.
+.ih
+DESCRIPTION
+For each image in the input image list the position of the spectrum
+within each aperture are determined at a number of points along the
+dispersion axis and a smooth function is fit to these positions. The
+fitted curve defines a shift to be added to the aperture center at each
+wavelength. Other options allow defining apertures using a reference
+image, defining apertures through an automatic finding algorithm (see
+\fBapfind\fR), automatically recentering apertures (see
+\fBaprecenter\fR), automatically resizing apertures (see
+\fBapresize\fR), and interactively editing the apertures prior to
+tracing (see \fBapedit\fR). Tracing is selected with the parameter
+\fItrace\fR. If the tracing is done interactively (the
+\fIinteractive\fR parameter set to yes) then the user is queried
+whether or not to trace each image. The responses are "yes", "no",
+"YES", or "NO", where the upper case queries suppress this query
+for the following images.
+
+The tracing begins with the specified dispersion line. A dispersion
+line is a line or column of the image perpendicular to the dispersion
+axis. The dispersion axis is defined in the image header or by the
+package parameter \fIdispaxis\fR. If the starting dispersion line is
+INDEF then the middle dispersion line of the image is used. The
+positions of the spectra are determined using the \fBcenter1d\fR
+algorithm and the centering parameters from the \fBapedit\fR task.
+(See help under \fBcenter1d\fR for a description of the one dimensional
+position measuring algorithm.) The positions are redetermined at other
+points along the dispersion axis by stepping from the starting line in
+steps specified by the user. A number of dispersion lines around each
+dispersion line to be measured may be summed to improve the position
+determinations, particularly for weak profiles. This number usually is
+set equal to the tracing step.
+
+It is important to understand how to set the step size and the
+relationship between the step size and the centering error radius.
+Larger steps reduce the computational time, which is an important
+consideration. However, if the step is too large then the tracing may
+fail to follow the systematic changes in the positions of the
+spectrum. The centering error radius, \fIradius\fR, is used to limit
+the maximum position change between two successive steps. If the
+positions of a spectrum changes by more than the specified amount or
+the data contrast falls below the \fIthreshold\fR parameter then
+the position is marked as lost.
+
+The centering radius should be large enough to follow changes in the
+spectrum positions from point to point but small enough to detect an error
+in the tracing by a sudden abrupt change in position, such as caused by
+crowding with other spectra or by the disappearance of the spectrum. The
+\fInlost\fR parameter determines how many consecutive steps the position
+may fail to be found before tracing in that direction is stopped. If this
+parameter is small the trace will stop quickly upon loss of the profile
+while if it is very large it will continue to try and recover the profile.
+
+The parameter \fIthreshold\fR checks for the vanishing of a spectrum by
+requiring a minimum range in the data used for centering. If the
+tracing fails when the spectra are strong and well defined the problem
+is usually that the step size is too large and/or the centering error
+radius is too small.
+
+The traced positions of a spectrum include some measurement variation
+from point to point. Since the actual position of the spectrum in the
+image should be a smooth curve, a function of the dispersion line is fit
+to the measured points. The fitted function is stored as part of the
+aperture description. It is an offset to be added to the aperture's
+center as a function of the dispersion line. Even if the fitting is not
+done interactively plots of the trace and the fit are recorded in the
+plot file or device specified by the parameter \fIplotfile\fR.
+
+Fitting the traced spectrum positions with a smooth function may be
+performed interactively when parameters \fIfittrace\fR and
+\fIinteractive\fR are yes. This allows changing the default fitting
+parameters. The function fitting is done with the interactive curve
+fitting tools described under the help topic \fBicfit\fR. There are
+two levels of queries when fitting the spectrum positions
+interactively; prompts for each image and prompts for each aperture in
+an image. These prompts may be answered individually with the lower
+case responses "yes" or "no" or answered for all further prompts with
+the responses "YES" or "NO". Responding with "yes" or "YES" to the
+image prompt allows interactive fitting of the traced positions for the
+spectra. Prompts are then given for each aperture in the image. When
+an spectrum is not fit interactively the last set of fitting parameters
+are used (initially the default function and order given by the task
+parameters). Note that answering "YES" or "NO" to a aperture prompt
+applies to all further aperture in the current image only. Responding
+with "no" or "NO" to the image prompt fits the spectrum positions for
+all apertures in all images with the last set of fitting parameters.
+
+The tracing may also be done from the interactive aperture editor with
+the 't' key. The aperture tracing algorithm may be selected from many
+of the tasks in the package with the \fItrace\fR parameter.
+.ih
+APTRACE DATABASE COEFFICIENTS
+The path of an aperture is described by a function that gives an additive
+offset relative to the aperture center as stored under the database keyword
+center. The function is saved in the database as a series of
+coefficients. The section containing the coefficients starts with the
+keyword "curve" and the number of coefficients.
+
+The first four coefficients define the type of function, the order
+or number of spline pieces, and the range of the independent variable
+(the line or column coordinate along the dispersion). The first
+coefficient is the function type code with values:
+
+.nf
+ Code Type
+ 1 Chebyshev polynomial
+ 2 Legendre polynomial
+ 3 Cubic spline
+ 4 Linear spline
+.fi
+
+The second coefficient is the order (actually the number of terms) of
+the polynomial or the number of pieces in the spline.
+
+The next two coefficients are the range of the independent variable over
+which the function is defined. These values are used to normalize the
+input variable to the range -1 to 1 in the polynomial functions. If the
+independent variable is x and the normalized variable is n, then
+
+.nf
+ n = (2 * x - (xmax + xmin)) / (xmax - xmin)
+.fi
+
+where xmin and xmax are the two coefficients.
+
+The spline functions divide the range into the specified number of
+pieces. A spline coordinate s and the nearest integer below s,
+denoted as j, are defined by
+
+.nf
+ s = (x - xmin) / (xmax - xmin) * npieces
+ j = integer part of s
+.fi
+
+where npieces are the number of pieces.
+
+The remaining coefficients are those for the appropriate function.
+The number of coefficients is either the same as the function order
+for the polynomials, npieces+1 for the linear spline, or npieces + 3
+for the cubic spline.
+
+1. Chebyshev Polynomial
+
+The polynomial can be expressed as the sum
+
+.nf
+ y = sum from i=1 to order {c_i * z_i}
+.fi
+
+where the c_i are the coefficients and the z_i are defined
+interactively as:
+
+.nf
+ z_1 = 1
+ z_2 = n
+ z_i = 2 * n * z_{i-1} - z_{i-2}
+.fi
+
+2. Legendre Polynomial
+
+The polynomial can be expressed as the sum
+
+.nf
+ y = sum from i=1 to order {c_i * z_i}
+.fi
+
+where the c_i are the coefficients and the z_i are defined
+interactively as:
+
+.nf
+ z_1 = 1
+ z_2 = n
+ z_i = ((2*i-3) * n * z_{i-1} - (i-2) * z_{i-2}) / (i - 1)
+.fi
+
+3. Linear Spline
+
+The linear spline is evaluated as
+
+.nf
+ y = c_j * a + c_{j+1} * b
+.fi
+
+where j is as defined earlier and a and b are fractional difference
+between s and the nearest integers above and below
+
+.nf
+ a = (j + 1) - s
+ b = s - j
+.fi
+
+4. Cubic Spline
+
+The cubic spline is evaluated as
+
+.nf
+ y = sum from i=0 to 3 {c_{i+j} * z_i}
+.fi
+
+where j is as defined earlier. The term z_i are computed from
+a and b, as defined earlier, as follows
+
+.nf
+ z_0 = a**3
+ z_1 = 1 + 3 * a * (1 + a * b)
+ z_2 = 1 + 3 * b * (1 + a * b)
+ z_3 = b**3
+.fi
+.ih
+EXAMPLES
+.ih
+REVISIONS
+.ls APTRACE V2.11
+The "apertures" parameter can be used to select apertures for resizing,
+recentering, tracing, and extraction. This parameter name was previously
+used for selecting apertures in the recentering algorithm. The new
+parameter name for this is now "aprecenter".
+.le
+.ih
+SEE ALSO
+apdefault, apfind, aprecenter, apresize, apedit, apall,
+center1d, icfit, gtools
+.endhelp
diff --git a/noao/twodspec/apextract/doc/apvariance.hlp b/noao/twodspec/apextract/doc/apvariance.hlp
new file mode 100644
index 00000000..6ff1e073
--- /dev/null
+++ b/noao/twodspec/apextract/doc/apvariance.hlp
@@ -0,0 +1,159 @@
+.help apvariance Aug90 noao.twodspec.apextract
+
+.ce
+Variance Weighted and Cleaned Extractions
+
+
+There are two types of aperture extraction (estimating the background
+subtracted flux across a fixed width aperture at each image line or
+column) in the APEXTRACT package. One is a simple sum of pixel values
+across an aperture. It is selected by specifying "none" for the
+\fIweights\fR parameter. The second type weights each pixel in the sum
+by it's estimated variance based on a spectrum model and detector noise
+parameters. This type of extraction is selected by specifying
+"variance" for the weighting parameter. These two extractions are
+defined by the following equations.
+
+.nf
+ none: S = sum { I - B }
+ variance: S = sum { (P**2 / V) (I - B) / P } / sum { P**2 / V }
+.fi
+
+S is the one dimensional spectrum flux at a particular wavelength (line
+or column along the dispersion axis). The sum is over all pixels at
+that wavelength within the aperture limits. If the aperture endpoints
+occupy only a fraction of a pixel then the pixel value above the
+background is multiplied by the fraction. I is the pixel value and B
+is the estimated background at that pixel (see \fBapbackground\fR), P
+is estimated normalized profile value for that pixel (see
+\fBapprofile\fR), and V is the estimated variance of the pixel based on
+the noise model described below. Note that the quantity (I-B)/P is an
+independent estimate of the total flux from one pixel since the
+integral of P is one and it is these estimates that are variance
+weighted.
+
+Variance weighting is often called "optimal" extraction since it
+produces the best unbiased signal-to-noise estimate of the flux in the
+two dimensional profile. The theory and application of this type of
+weighting has been described in several papers. The ones which were
+closely examined and used as a model for the algorithms in this
+software are "An Optimal Extraction Algorithm for CCD Spectroscopy",
+PASP 98, 609, 1986, by Keith Horne and "The Extraction of Highly
+Distorted Spectra", PASP 100, 1032, 1989, by Tom Marsh.
+
+The noise model for the image data used in the variance weighting,
+cleaning, and profile fitting consists of a constant gaussian noise and
+a photon count dependent poisson noise. The signal is related to the
+number of photons detected in a pixel by a \fRgain\fR parameter given
+as the number of photons per data number. The gaussian noise is given
+by a \fIreadnoise\fR parameter which is a defined as a sigma in
+photons. The poisson noise is approximated as gaussian with sigma
+given by the number of photons.
+
+Some additional effects which should be considered in principle, and
+which are possibly important in practice, are that the variance
+estimate should be based on the actual number of photons detected before
+correction for pixel sensitivity; i.e. before flat field correction.
+Furthermore the uncertainty in the flat field should also be included
+in the weighting. However, the profile must be determined free of
+sensitivity effects including rapid larger scale variations such as
+fringing. Thus, ideally one should input the unflat-fielded
+observation and the flat field data and carry out the extractions with
+the above points in mind. However, due to the complexity often
+involved in basic CCD reductions and special steps required for
+producing spectroscopic flat fields this level of sophistication is not
+provided by the current package. The package does provide, however,
+for propagation of an approximate uncertainty in the background
+estimate when using background subtraction.
+
+The noise model is described by the following equations.
+
+.nf
+ (1) V = max (VMIN, (R**2 + I + VB) / G**2)
+ max (VMIN, (R**2 + S * P + B + VB) / G**2)
+
+ (2) VB = 0. if (B = 0)
+ = B / (N - 1) if (B > 0)
+
+ (3) VMIN = 1 / G**2 if (R = 0)
+ R**2 / G**2 if (R > 0)
+.fi
+
+V is the desired variance of a pixel to use for variance weighting. R
+is the photon read out noise specified by the parameter \fIreadnoise\fR
+and G is the photon per data value gain specified by the parameter
+\fIgain\fR. There are two forms to (1). The first is used in the
+initial pass of estimating the spectrum flux S and the actual pixel
+value I (which includes any background) is used for the poisson term.
+The other form is used in a second pass (and further passes if
+cleaning) using the estimated data value based on the normalized
+profile P scaled to the estimated total flux plus the estimated
+background B; i.e. I estimated = S * P + B.
+
+The background variance VB is computed using the poisson noise model
+based on the estimated background counts. If no background subtraction
+is done then both B and VB are set to zero. If a background is
+determined the background is either an average or function fit to
+pixels in defined background regions. If a fit is used B need not be a
+constant. Because the background estimate is based on a finite number of
+pixels, the poisson variance estimate is divided by the number N (minus
+one) of pixels used in determining the background. The number of
+pixels used includes any box car smoothing. Thus, the larger the
+number of background pixels the smaller the background noise
+contribution to the variance weighting. This method is only
+approximate since no correction is made for the number of degrees of
+freedom and correlations when using the fitting method of background
+estimation.
+
+VMIN is a minimum variance need to avoid generating zero or negative
+variances from the data. The definition of VMIN is such that if a zero
+read out noise is specified (which is certainly possible such as with
+photon counting detectors) then a minimum of 1 photon is imposed.
+Otherwise the minimum is set by the read out noise even if the poisson
+count part is (unphysically) negative.
+
+One deviation from the linear photon response mode which is considered
+is saturation. A data level specified by the parameter
+\fIsaturation\fR is used to exclude data from the profile fitting.
+During extraction the saturated pixels are not treated any differently
+than unsaturated pixels except that dispersion points with saturated
+pixels are flagged by reversing the sign of the final estimated sigma;
+the sigma output is enabled with the \fIextras\fR parameter. Exclusion
+of saturated pixels from the extraction, as is done with deviant
+pixels, was tried but this resulted in higher noise in the spectrum.
+
+If removal of cosmic rays and other deviant pixels is desired, called
+cleaning and selected with a \fIclean\fR parameter, they are
+iteratively rejected based on the estimated variance and excluded from
+the weighted sum. Note that a cleaned extraction is always variance
+weighted regardless of the value of the \fIweights\fR parameter. This
+makes sense since the detector noise parameters must be specified and
+the spectrum profile computed, so all of the computational effort must
+be done anyway, and the variance weighting is as good or superior to a
+simple unweighted extraction.
+
+The detection and removal of deviant pixels is straightforward. Based
+on the noise model described earlier, pixels deviating by more than a
+specified number of sigma (square root of the variance) above or below
+the model are removed from the weighted sum. A new spectrum estimate
+is made and the rejection is repeated. The rejections are made one at
+a time starting with the most deviant and up to half the pixels in the
+aperture may be rejected. The total number of rejected pixels in the
+spectrum is recorded in the logfile and a profile plot of data and
+model profile is recorded in the plotfile.
+
+As a final step when computing a weighted/cleaned spectrum the total
+fluxes from the weighted spectrum and the simple unweighted spectrum
+(excluding any deviant and saturated pixels) are computed and a
+"bias" factor of the ratio of the two fluxes is multiplied into
+the weighted spectrum and the sigma estimate. This makes the total
+fluxes the same. The bias factor is recorded in the logfile
+if one is kept. Also a check is made for unusual bias factors.
+If the two fluxes disagree by more than a factor of two a warning
+is given on the standard output and the logfile with the individual
+total fluxes as well as the bias factor. If the bias factor is
+negative a warning is also given and no bias factor is applied.
+.ih
+SEE ALSO
+apbackground approfiles apall apsum
+.endhelp
diff --git a/noao/twodspec/apextract/doc/dictionary b/noao/twodspec/apextract/doc/dictionary
new file mode 100644
index 00000000..1046499c
--- /dev/null
+++ b/noao/twodspec/apextract/doc/dictionary
@@ -0,0 +1,282 @@
+ADU
+APALL
+APAXIS
+APEDIT
+APEXTRACT
+APFIND
+APFIT
+APFLATTEN
+APFORMAT
+APID
+APID2
+APIO
+APMASK
+APNORMALIZE
+APNUM2
+APNUMn
+APPARAMS
+APRECENTER
+APRESIZE
+APSCATTER
+APSTRIP
+APSUM
+APTRACE
+CCD
+CL
+DISPAXIS
+ECHELLE
+EOF
+EPARAM
+FIT1D
+FLAT1D
+Fri
+Horne
+Horne's
+ICFIT
+IMARITH
+IMREPLACE
+IMSURFIT
+INDEF
+IRAF
+Jul
+Jul90
+Nfind
+P.O
+PASP
+PSET
+RMS
+SETDISP
+SN
+STDIN
+STDOUT
+Slitlet
+VB
+VMIN
+Valdes
+ansclob
+ansclobber
+ansclobber1
+ansdbwr
+ansdbwrite
+ansdbwrite1
+ansedit
+ansextr
+ansextract
+ansfind
+ansfit
+ansfits
+ansfitscatter
+ansfitsmooth
+ansfitspec
+ansfitspec1
+ansfitt
+ansfittrace
+ansfittrace1
+ansflat
+ansmask
+ansnorm
+ansrece
+ansrecenter
+ansresi
+ansresize
+ansrevi
+ansreview
+ansreview1
+ansscat
+anssmoo
+anssmooth
+anstrac
+anstrace
+ap
+apall
+apall1
+apbackground
+apdefault
+apdefault.apidtable
+apdefault.b
+apdefault.lower
+apdefault.upper
+apdemo1d
+apdemo2d
+apdemo2d.ms
+apdemos
+apdemosdb
+apedit
+apedit.radius
+apedit.threshold
+apedit.width
+apertur
+apextract
+apextractsys
+apfind
+apfind.maxsep
+apfind.minsep
+apfind.nfind
+apfind.order
+apfit
+apfit1
+apflat1
+apflatten
+apidtab
+apidtable
+apio
+aplast
+apmask
+apnorm1
+apnormalize
+apparams
+approfile
+approfiles
+aprecenter
+aprecenter.apertures
+aprecenter.npeaks
+aprecenter.shift
+apresize
+apresize.avglimits
+apresize.bkg
+apresize.llimit
+apresize.peak
+apresize.r
+apresize.ulimit
+apresize.ylevel
+apscat1
+apscat2
+apscatter
+apscript
+apstrip
+apsum
+apsum.background
+apsum.clean
+apsum.extras
+apsum.gain
+apsum.lsigma
+apsum.nsubaps
+apsum.readnoise
+apsum.saturation
+apsum.skybox
+apsum.usigma
+apsum.weights
+aptrace
+aptrace.function
+aptrace.grow
+aptrace.high
+aptrace.low
+aptrace.naverage
+aptrace.niterate
+aptrace.nsum
+aptrace.order
+aptrace.sample
+aptrace.step
+apvariance
+artdata
+avg
+avglimi
+avglimits
+backgro
+bkg
+ccd
+cennorm
+center1d
+chebyshev
+cl
+clopset
+computerese
+curfit
+dbwrite
+dispaxi
+dispaxis
+dropoff
+ech
+ech001
+echelle
+echelles
+elp
+eparam
+fiber1
+fitscatter
+fitsmooth
+fitspec
+fittrace
+fittype
+flat001,flat002
+funct
+gaussian
+gkimosaic
+gtools
+icfit
+im
+im1
+image.pl
+image1
+imarith
+imh
+imred
+imred.generic.flat1d
+imsurfit
+keystroke
+legendre
+llimit
+logfile
+longslit
+lparam
+ls1
+lsigma
+maxsep
+maxtilt
+minsep
+mk1dspec
+mk2dspec
+mknoise
+msred
+multislit1
+multspec.ms
+naverage
+ndhelp
+nessie
+newimage
+nfind
+niter
+niterat
+niterate
+nl
+noao.twodspec.apextract
+npeaks
+nsubaps
+nsum
+onedspec
+onedspec.continuum
+pl
+plotfile
+poisson
+polyord
+polysep
+pset
+psets
+qtz001,qtz002
+rdnoise
+readnoi
+readnoise
+rec
+ref
+res
+root.0001
+rootname
+rootnames
+sampl
+saturat
+setdisp
+skybox
+slitlet
+slitlets
+spline1
+spline3
+thresho
+twodspec
+ulimit
+usigma
+whitespace
+widt
+xlow
+xmax
+xmin
+ylevel
diff --git a/noao/twodspec/apextract/doc/old/Tutorial.hlp b/noao/twodspec/apextract/doc/old/Tutorial.hlp
new file mode 100644
index 00000000..fd0ff8e8
--- /dev/null
+++ b/noao/twodspec/apextract/doc/old/Tutorial.hlp
@@ -0,0 +1,278 @@
+.help Tutorial Sep86 "Apextract Tutorial"
+.ih
+TOPICS
+The APEXTRACT tutorial consists of a number of topics. The topics are brief
+and describe the simplest operations. More sophisticated discussions are
+available for the tasks in the printed documentation and through the on-line
+\fBhelp\fR facility; i.e. "help taskname". To obtain information
+on a particular topic type "tutor topic" where the topic is one of the
+following:
+
+.nf
+ TOPICS
+
+ topics - List of topics
+ overview - An overview of the \fBapextract\fR tasks
+ organization - How the package is organized
+ apertures - Definition of apertures
+ defining - How to define apertures
+ references - Using reference images to define apertures
+ queries - Description of interactive queries
+ cosmic - Problems with cosmic ray removal
+ all - Print all of this tutorial
+.fi
+.ih
+OVERVIEW
+The \fBapextract\fR tasks extract spectra from two dimensional images.
+One image axis is the dispersion axis and the other image axis is the
+aperture axis. The user defines apertures whose position along the
+aperture axis is a function of position along the dispersion axis and
+whose width is fixed. There are two types of aperture extractions.
+\fIStrip\fR extraction produces two dimensional images in which the
+center of the aperture is exactly centered along one of the lines or
+columns of the image and the edges of the image just include the
+edges of the aperture. \fISum\fR extraction sums the pixels across
+the aperture at each point along the dispersion to produce a one
+dimensional spectrum. The extraction algorithms include
+fitting and subtracting a background, modeling the profiles across the
+dispersion, detecting and removing deviant pixels which do not fit the
+model profiles, and weighting the pixels in the sum extraction according
+to the signal-to-noise.
+
+To extract spectra one must define the dispersion axis by placing the
+parameter DISPAXIS in the image headers using the task \fBsetdisp\fR.
+Then apertures are defined either automatically, interactively, or by
+reference to an image in which apertures have been previously defined.
+Initially the apertures are aligned parallel to the dispersion axis
+but if the spectra are not aligned with the dispersion axis and have
+profiles which can be traced then the position of the aperture along
+the aperture axis can be made a function of position along the dispersion
+axis. Finally, the extraction operation is performed for each aperture.
+.ih
+ORGANIZATION
+The tasks in the \fBapextract\fR package are highly integrated. This
+means that tasks call each other. For example, the aperture
+editing task may be called from the finding, tracing, or extraction
+tasks. Also from within the aperture editor the finding, tracing, and
+extraction tasks may be run on selected apertures. This organization
+provides the flexibility to process images either step-by-step,
+image-by-image, or very interactively from the aperture editor. For
+example, one may defined apertures for all the images, trace all the
+images, and then extract all the images or, alternatively, define,
+trace, and extract each image individually.
+
+This organization also implies that parameters from many tasks are used
+during the execution of a single task. For example, the editing
+parameters are used in any of the tasks which may enter the interactive
+editing task. Two tasks, \fBapio\fR and \fBapdefault\fR, only set
+parameters but these parameters are package parameters which affect all
+the other tasks. There are two effects of this parameter
+organization. First, only parameters from the task being executed may
+be specified on the command line or with menu mode. However, the
+parameters are logically organized and the parameter list for any
+particular task is not excessively long or complex. For example, the
+number of parameters potentially used by the task \fBapsum\fR is 57
+parameters instead of just the parameters logically related to the
+extraction itself.
+
+Another feature of the package organization is the ability to
+control the flow and interactivity of the tasks. The parameter
+\fIinteractive\fR selects whether the user will be queried about various
+operations and if the aperture editor, trace fitting, and extraction
+review will be performed. The parameters \fBdbwrite,
+find, recenter, edit, trace, fittrace, sum, review\fR, and
+\fBstrip\fR select which operations may be performed by a particular
+task. When a task is run interactively the user is queried about
+whether to perform each operation on each image. A query may be answered
+individually or as a group. In the latter case the query will not be
+repeated for other images but will always take the specified action.
+This allows the user to begin interactively and then reduce
+the interactivity as the images are processed and parameters are refined.
+For additional discussion of these parameters see the topic QUERIES.
+
+Finally, the package has attempted to provide good logging facilities.
+There are log files for both time stamped text output and plots.
+The text log is still minimal but the plot logging is complete
+and allows later browsing and hardcopy review of batch processing.
+See \fBapio\fR for further discussion.
+
+This package organization is somewhat experimental. Let us know what
+you think.
+.ih
+APERTURES
+An aperture consists of the following elements:
+
+.ls id
+An integer aperture identification number. The identification number
+must be unique. The aperture number is used as the default extension
+of the extracted spectra.
+.le
+.ls beam
+An integer beam number. The beam number need not be unique; i.e.
+several apertures may have the same beam number. The beam number will
+be recorded in the image header of the extracted spectrum. Note that
+the \fBonedspec\fR package restricts the beam numbers to the range 0 to
+49.
+.le
+.ls cslit, cdisp
+The center of the aperture along the slit and dispersion axes in the two
+dimensional image.
+.le
+.ls lslit, ldisp
+The lower limits of the aperture, relative to the aperture center,
+along the slit and dispersion axes. The lower limits need not be less
+than the center.
+.le
+.ls uslit, udisp
+The upper limits of the aperture, relative to the aperture center,
+along the slit and dispersion axes. The upper limits need not be greater
+than the center.
+.le
+.ls curve
+An shift to be added to the center position for the slit axis which is
+a function of position along the dispersion axis. The function is one
+of the standard IRAF \fBicfit\fR types; a legendre polynomial, a chebyshev
+polynomial, a linear spline, or a cubic spline.
+.le
+.ls background
+Background fitting parameters used by the \fBicfit\fR package for background
+subtraction. Background parameters need not be used if background
+subtraction is not needed. The background sample regions are specified
+relative to aperture center.
+.le
+
+The aperture center is the only absolute coordinate relative to the
+image or image section. The size and shape of the aperture are
+specified relative to the aperture center. The center and aperture
+limits in image coordinates along the slit axis are functions of the
+dispersion coordinate, lambda, given by
+
+.nf
+ center(lambda) = cslit + curve(lambda)
+ lower(lambda) = center(lambda) + lslit
+ upper(lambda) = center(lambda) + uslit
+.fi
+
+Note that both the lower and upper constants are added to the center
+defined by the aperture center and the curve offset. The aperture limits
+along the dispersion axis are constant,
+
+.nf
+ center(s) = cdisp
+ lower(s) = center(s) + ldisp
+ upper(s) = center(s) + udisp
+.fi
+
+Usually the aperture size along the dispersion is equal to the entire image.
+.ih
+DEFINING APERTURES
+If a reference image is specified the \fBapextract\fR tasks first search
+the database for it's apertures. Note that this supercedes any apertures
+previously defined for the input image. If no reference apertures are
+found then the apertures for the input image are sought.
+If no apertures are defined at this point then apertures
+may be defined automatically, interactively, or, by default, in the center
+of the image. The automatic method, \fBapfind\fR, locates spectra as peaks
+across the dispersion and then defines default apertures given by the
+parameters from \fBapdefault\fR. The algorithm is controlled
+by specifying the number of apertures and a minimum separation between
+spectra. Only the strongest peaks are selected.
+
+The interactive method, \fBapedit\fR, allows the user to mark the positions
+of apertures and to adjust the aperture parameters such as the limits.
+The aperture editor may be used edit apertures defined by any of the
+other methods.
+
+If no apertures are defined when tracing or extraction is begun, that is
+following the optional editing, then a default aperture is defined
+centered along the aperture axis of the image. This ultimate default
+may be useful for spectra defined by image sections; i.e. the image
+section is a type of aperture. Image sections are sometimes used with
+multislit spectra.
+.ih
+REFERENCE IMAGES
+The \fBapextract\fR tasks define apertures for an input image by
+first searching the database for apertures recorded under the name
+of the reference image. Use of a reference image implies
+superceding the input image apertures. Reference images are specified
+by an image list which is paired with
+the input image list. If the number of reference images
+is less than the number of input images then the last reference image
+is used for all following images. Generally, the reference image list
+consists of the null string if reference images are not to be used,
+a single image which is applied to all input images, or a list
+which exactly matches the input list. The special reference image
+name "last" may be used to refer to the last apertures written to
+the database; usually the previous input image.
+
+The task parameter \fIrecenter\fR specifies whether the
+reference apertures are to be recentered on the spectra in the input
+image. If recentering is desired the \fBcenter1d\fR centering algorithm
+is used with centering parameters taken from the task \fBapedit\fR.
+The spectra in the image must all have well defined profiles for the
+centering. It does not make sense to center an aperture defined for
+a region of sky or background or for an arc spectrum.
+
+Recentering is used when the only change between two spectra is
+a shift along the aperture axis. This can reduce the number of
+images which must be traced if tracing is required by using a
+traced reference image and just recentering on the next spectra.
+Recentering of a traced reference image is also useful when
+the spectra are too weak to be traced reliably. Recentering would be
+most commonly used with echelle or multiaperture spectra.
+
+Recentering is not used when extracting sky or arc calibration spectra
+from long slit or multislit images. This is because it is desirable
+to extract from the same part of the detector as the object spectra and
+because recentering does not make sense when there is no profile across
+the aperture. Centering or recentering is also not used when dealing
+with apertures covering parts of extended objects in long slit spectra.
+.ih
+QUERIES
+When the interactive parameter is specified as yes in a task then the user
+is queried at each step of the task. The queries refer to either a
+particular image or a particular aperture in an image. The acceptable
+responses to the queries are the strings "yes", "no", "YES", and "NO".
+The lower case answers refer only to the specific query. The upper
+case answers apply to all repetitions of query for other images and
+apertures. The upper case reponses then suppress the query and take
+the specified action every time. This allows tasks to be highly interactive
+by querying at each step and for each image or to skip or perform
+each step for all images without queries.
+
+The two steps of fitting a function to traced positions and reviewing
+one dimensional extracted spectra, selected with the parameters
+\fIaptrace.fittrace\fR and \fIapsum.review\fR have two levels of queries.
+First a query is made for the image being traced or extracted. If
+the answer is "yes" or "YES" then a query is made for each aperture.
+A response of "YES" or "NO" applies only to the remaining apertures
+and not to apertures of a later image.
+.ih
+COSMIC RAYS
+The cleaning and modeling features available during aperture extraction
+are fairly good. They are described in the documentation for the
+tasks. It can only go so far towards discriminating cosmic rays
+because of problems described below. Further work on the algorithm may
+improve the performance but it is best, when feasible, to first
+eliminate at least the strongest cosmic rays from the data before
+extracting. One recommended method is to use \fBlineclean\fR with a
+high rejection threshold and a high order.
+
+There are two difficult problems encountered in using the
+\fBapextract\fR tasks for cosmic ray detection. First, the spectral
+profiles are first interpolated to a common center before comparison
+with the average profile model. The interpolation often splits single
+strong spikes into two high points of half the intensity, as is
+intuitively obvious. Furthermore, for very strong spikes there is
+ringing in the interpolator which makes the interpolated profile depart
+significantly from the original profile. The fact that the
+interpolated profile now has two or more deviant points makes it much
+harder to decide which points are in the profile. This leads to the
+second problem. The average profile model is scaled to fit the
+spectrum profile. When there are several high points it is very
+difficult to discriminate between a higher scale factor and bad
+points. The algorithm has been enhanced to initially exclude the point which
+most pulls the scale factor to higher values. If there are two high
+points due to the interpolator splitting a strong spike then this helps
+but does not eliminate errors in the extracted spectra.
+.endhelp
diff --git a/noao/twodspec/apextract/doc/old/apextract.ms b/noao/twodspec/apextract/doc/old/apextract.ms
new file mode 100644
index 00000000..3e71890b
--- /dev/null
+++ b/noao/twodspec/apextract/doc/old/apextract.ms
@@ -0,0 +1,725 @@
+.EQ
+delim $$
+define sl '{s lambda}'
+.EN
+.RP
+.TL
+The IRAF APEXTRACT Package
+.AU
+Francisco Valdes
+.AI
+IRAF Group - Central Computer Services
+.K2
+P.O. Box 26732, Tucson, Arizona 85726
+.AB
+The IRAF \fBapextract\fR package provides tools for the extraction of
+one and two dimensional spectra from two dimensional images
+such as echelle, long slit, multi-fiber, and multi-slit spectra.
+Apertures of fixed width along the spatial define the regions of
+the two dimensional images to be extracted at each point along the
+dispersion axis. Apertures may follow changes in the positions of
+the spectra as a function of position along the dispersion axis.
+The spatial and dispersion axes may be oriented along either image axis.
+Extraction to one dimensional spectra consists of a weighted sum of the pixels
+within the apertures at each point along the dispersion axis. The
+weighting options provide the simple sum of the pixel values and a
+weighting by the expected uncertainty of each pixel. Two dimensional
+extractions interpolate the spectra in the spatial axis to produce
+image strips with the position of the spectra exactly aligned with one
+of the image dimensions. The extractions also include optional
+background subtraction, modeling, and bad pixel detection and replacement.
+The tasks are flexible in their ability to define and edit apertures,
+operate on lists of images, use apertures defined for reference
+images, and operate both very interactively or noninteractively.
+The extraction tasks are efficient and require only one pass through
+the data. This paper describes the tasks, the algorithms, the data
+structures, as well as some examples and possible future developments.
+.AE
+.NH
+Introduction
+.PP
+The IRAF \fBapextract\fR package provides tools for the extraction of
+one and two dimensional aperture spectra from two dimensional format
+images such as those produced by echelle, long slit, multi-fiber, and
+multi-slit spectrographs. This type of data is becoming increasingly
+popular because of the efficiency of data collection and recent
+technological improvements such as fibers and digital detectors.
+The trend is also to greater and greater numbers of spectra per
+image. Extraction is one of the fundamental operations performed
+on these types of two dimensional spectral images, so a great deal of effort
+has gone into the design and development of this package.
+.PP
+The tasks are flexible and have many options. To make the best use of
+them it is important to understand how they work. This paper provides
+a general description of the tasks, the algorithms, the data structures,
+as well as some examples of usage. Specific descriptions of parameters
+and usage may be found in the IRAF help pages for the tasks included
+as appendices to this paper. The image reduction "cookbooks" also
+provide complete examples of usage for specific instruments or types
+of instruments.
+.PP
+The tasks in the \fBapextract\fR pacakge are summarized below.
+
+.ce
+The \fBApextract\fR Package
+.TS
+center;
+n.
+apdefault \&- Set the default aperture parameters
+apedit \&- Edit apertures interactively
+apfind \&- Automatically find spectra and define apertures
+apio \&- Set the I/O parameters for the APEXTRACT tasks
+apnormalize \&- Normalize 2D apertures by 1D functions
+apstrip \&- Extract two dimensional aperture strips
+apsum \&- Extract one dimensional aperture sums
+aptrace \&- Trace positions of spectra
+.TE
+
+The tasks are highly integrated so that one task may call another tasks
+or use its parameters. Thus, these tasks reflect the logical organization
+of the package rather than a set of disparate tools. One reason for
+this organization is group the parameters by function into easy to manage
+\fIparameter sets (psets)\fR. The tasks \fBapdefault\fR and \fBapio\fR
+are just psets for specifying the default aperture parameters and the
+I/O parameters of the package; in other words, they do nothing but
+provide a grouping of parameters. Executing these tasks is a shorthand
+for the command "eparam apdefault" or "eparam apio". The other tasks
+provide both a logical grouping of parameters and function. For
+example the task \fBaptrace\fR traces the positions of the spectra
+in the images and has the parameters related to tracing. The task
+\fBapsum\fR, however, may trace the spectra as part of the overall
+extraction process and it uses the functionality and parameters of
+the \fBaptrace\fR task without requiring all the tracing parameters
+be included as part of its parameter set. As we examine each task
+in detail it will become more apparent how this integration of function
+and parameters works.
+.PP
+The \fBapextract\fR package identifies the image axes with the spatial
+and dispersion axes. Thus, during extraction pixels of constant
+wavelength are those along a line or column. In this paper the terms
+\fIslit\fR or \fIspatial\fR axis and \fIdispersion\fR or \fIwavelength\fR
+axis are used to refer to the image axes corresponding to the spatial
+and dispersion axes. Often a small degree of misalignment between the
+image axes and the true dispersion and spatial axes is not important.
+The main effect of misalignment is a broadening of the spectral
+features due to the difference in wavelength on opposite sides of the
+extraction aperture. If the misalignment is significant, however, the
+image may be rotated with the task \fBrotate\fR in the \fBimages\fR
+package or remapped with the \fBlongslit\fR package tasks for
+coordinate rectification.
+.PP
+It does not matter which image axis is the dispersion axis since the
+tasks work equally well in either orientation. However, the dispersion
+axis must be defined, with the \fBtwodspec\fR task \fBsetdisp\fR,
+before these tasks may be used. This task is a simple script which
+adds the parameter DISPAXIS to the image headers. The \fBapextract\fR
+tasks, like the \fBlongslit\fR tasks, look in the header to determine
+the dispersion axis.
+.NH
+Apertures
+.PP
+Apertures are the basic data structures used in the package; hence the
+package name. An aperture defines a region of the two dimensional image
+to be extracted. The aperture definitions are stored in a database.
+An aperture consists of the following components.
+
+.IP ID
+.br
+An integer identification number. The identification number must be
+unique. It is used as the default extension during extraction of
+the spectra. Typically the IDs are consecutive positive integers
+ordered by increasing or decreasing slit position.
+.IP BEAM
+.br
+An integer beam number. The beam number need not be
+unique; i.e. several apertures may have the same beam number.
+The beam number will be recorded in the image header of the
+the extracted spectrum. By default the beam number is the same as
+the ID.
+.IP APAXIS
+.IP CENTER[2]
+.br
+The center of the aperture along the slit and dispersion axes in the two
+dimensional image.
+.IP LOWER[2]
+.br
+The lower limits of the aperture, relative to the aperture center,
+along the slit and dispersion axes. The lower limits need not be less
+than the center.
+.IP UPPER[2]
+.br
+The upper limits of the aperture, relative to the aperture center,
+along the slit and dispersion axes. The upper limits need not be greater
+than the center.
+.IP CURVE
+.br
+An offset to be added to the center position for the \fIslit\fR axis which is
+a function of the wavelength. The function is one of the standard IRAF
+types; a legendre polynomial, a chebyshev polynomial, a linear spline,
+or a cubic spline.
+.IP background
+.br
+Parameters for background subtraction based on the interactive
+curve fitting (\fBicfit\fR) tools.
+
+.PP
+The aperture center is the only absolute coordinate (relative to the
+image or image section). The other aperture parameters and the
+background fitting regions are defined relative to the center. Thus,
+an aperture may be repositioned easily by changing the center
+coordinates. Also a constant aperture size, shape (curve), and
+background regions may be maintained for many apertures. The center
+and aperture limits, in image coordinates, along the slit axis are
+given by:
+
+.EQ I
+ ~roman center ( lambda )~mark = roman cslit + roman curve ( lambda )
+.EN
+.EQ I
+roman lower ( lambda )~lineup = roman center ( lambda ) + roman lslit
+.EN
+.EQ I
+roman upper ( lambda )~lineup = roman center ( lambda ) + roman uslit
+.EN
+
+where $lambda$ is the wavelength coordinate. Note that both the lower and
+upper constants are added to the center defined by the aperture center and
+the offset curve. The aperture limits along the dispersion axis are
+constant since there is no offset curve:
+
+.EQ I
+roman center (s)~lineup = roman cdisp
+.EN
+.EQ I
+roman lower (s)~lineup = roman center (s) + roman ldisp
+.EN
+.EQ I
+roman upper (s)~lineup = roman center (s) + roman udisp
+.EN
+
+.PP
+Apertures for a particular image may be defined in several ways.
+These methods are arranged in a hierarchy.
+
+.IP (1)
+The database is first searched for previously defined apertures.
+.IP (2)
+If no apertures are found and a reference image is specified then the
+database is searched for apertures defined for the reference image.
+.IP (3)
+The user may then edit the apertures interactively with graphics
+commands if the \fIapedit\fR parameter is set. This includes creating
+new apertures and deleting or modifying existing apertures. This
+interactive editing procedure may be entered from any of the \fBapextract\fR
+tasks.
+.IP (4)
+For the tasks \fBtrace\fR, \fBsumextract\fR, and \fBstripextract\fR
+if no apertures are defined at this point a default aperture
+is created consisting of the entire image with center at the center of
+the image. Note that if an image section is used then the aperture
+spans the image section only.
+.IP (5)
+Any apertures created, modified, or adopted from a reference image are recorded
+in the database for the image.
+
+.PP
+There are several important points to appreciate in the above logic.
+First, any of the tasks may be used without prior use of the others.
+For example one may use extract with the \fIapedit\fR switch set and
+define the apertures to be extracted (except for tracing).
+Alternatively the apertures may be defined with \fBapedit\fR
+interactively and then traced and extracted noninteractively. Second,
+image sections may be used to define apertures (step 4). For example
+a list of image sections (such as are used in multislit spectra) may be
+extracted directly and noninteractively. Third, multiple images may
+use a reference image to define the same apertures. There are several
+more options which are illustrated in the examples section.
+.PP
+Another subtlety is the way in which reference images may be
+specified. The tasks in the package all accept list of images
+(including image sections). Reference images may also be given as a
+list of images. The lists, however, need not be of the same length.
+The reference images in the reference image list are paired in order
+with the input images. If the reference list ends before the image
+list then the last reference image is used for the remaining images.
+The most common situations are when there is no reference image, when
+only one reference image is given for a set of input images, and when a
+matching list of reference images is given. In the second case the
+reference image refers to all the input images while in the last case
+each input image has a reference image.
+.PP
+There is a trick which may be played with the reference images. If a list
+of input images is given and the reference image is the same as the first
+input image then only the first image need be done interactively.
+This is because after the apertures for the first image have been defined
+they are recorded in the database. Then when the database is searched
+for apertures for the second image, the apertures of the reference image
+will be available.
+.NH
+.PP
+\fBApedit\fR is a generally interactive task which graphs a line of
+an image along the slit axis and allows the user to define and edit
+apertures with the graphics cursor. The defined apertures are recorded
+in a database. The task \fBtrace\fR traces the positions of the
+spectrum profiles from one wavelength to other wavelengths in the image
+and fits a smooth curve to the positions. This allows apertures
+to follow shifts in the spectrum along the slit axis. The tasks
+\fBsumextract\fR and \fBstripextract\fR perform the actual aperture
+extraction to one and two dimensional spectra. They have options for
+performing background subtraction, detecting and replacing bad pixels,
+modeling the spectrum profile, and weighting the pixels in the aperture
+when summing across the dispersion.
+.NH
+Tracing
+.PP
+The spectra to be extracted are not always aligned exactly with the
+image columns or lines (the extraction axes).
+For consistent extraction it is important that the same
+part of the spectrum profile be extracted at each wavelength point.
+Thus, the extraction apertures allow for shifts along the spatial axis
+at each dispersion point. The shifts are defined by a curve which is a
+function of the wavelength. The curve is determined by tracing the
+positions of the spectrum profile at a number of wavelengths and
+fitting a function to these positions.
+.PP
+The task \fBtrace\fR performs the tracing and curve fitting and records
+the curve in the database. The starting point along the
+dispersion axis (a line or column) for the tracing is specified by the
+user. The position of the profile is then determined using the
+\fBcenter1d\fR algorithm described elsewhere (see the help page for
+\fBcenter1d\fR or the paper \fIThe Long Slit Reduction Package\fR).
+The user specifies a step along the dispersion axis. At each step the
+positions of the profiles are redetermined using the preceding
+position as the initial guess. In order to enhance and trace weak
+spectra the user may specify a number of neighboring profiles to be
+summed before determining the profile positions.
+.PP
+Once the
+positions have been traced from the starting point to the ends of the
+aperture, or until the positions become indeterminate, a curve of a
+specified type and order is fit to the positions as a function of
+wavelength. The function fitting is performed with the \fBicfit\fR
+tools (see the IRAF help page). The curve fitting may be performed
+interactively or noninteractively. Note that when the curve is fit
+interactively the actually positions measured are graphed. However, the
+curve is stored in the aperture definition as an offset relative to the
+aperture center.
+.PP
+The tracing requires that the spectrum profile have a shape from which
+\fBcenter1d\fR can determine a position. This pretty much means
+gaussian type profiles. To extract a part of a long slit spectrum
+which does not have such a profile the user must trace a profile from
+another part of the image or a different image and then shift the
+center of the aperture without changing the shape. For example the
+center of a extended galaxy spectrum can be traced and the aperture
+shifted to other parts of the galaxy.
+.NH
+Extraction
+.PP
+There are two types of extraction; strip extraction and sum
+extraction. Strip extraction produces two dimensional images with
+pixels corresponding to the center of an aperture aligned along the
+lines or columns. Sum extraction consists of the weighted sum of the
+pixels within an aperture along the image axis nearest the spatial axis
+at each point along the dispersion direction. It is important to
+understand that the extraction is along image lines or columns while
+the actual dispersion/spatial coordinates may not be aligned exactly
+with the image axes. If this misalignment is important then for simple
+rotations the task \fBrotate\fR in the \fBimages\fR package may be used
+while for more complex coordinate rectifications the tasks in the
+\fBlongslit\fR package may be used.
+.NH 2
+Sum Extraction
+.PP
+Denote the image axis nearest the spatial axis by the index $s$ and
+the other image axis corresponding to the dispersion axis by $lambda$.
+The extraction is defined by the equation
+
+.EQ I (1)
+f sub lambda~=~sum from s (W sub sl (I sub sl - B sub sl ) / P sub sl ) /
+sum from s W sub sl
+.EN
+
+where the sums are over all pixels along the spatial axis within some
+aperture. The $W$ are weights, the $I$ are pixel intensities,
+the $B$ are background intensities, and the $P$ are a normalized
+profile model.
+.PP
+There are many possible choices for the extraction weights. The extraction
+task currently provides two:
+
+.EQ I (2a)
+W sub sl~mark =~P sub sl
+.EN
+.EQ I (2b)
+W sub sl~lineup =~P sub sl sup 2 / V sub sl
+.EN
+
+where $V sub sl$ is the variance of the pixel intensities given by the
+model
+
+.EQ I
+ V sub sl~=~v sub 0 + v sub 1~max (0,~I sub sl )~~~~if v sub 0~>~0
+.EN
+.EQ I
+ V sub sl~=~v sub 1~max (1,~I sub sl )~~~~~~~~~if v sub 0~=~0
+.EN
+
+Substituting these weights in equation (1) yields the extraction equations
+
+.EQ I (3a)
+f sub lambda~mark =~sum from s (I sub sl - B sub sl )
+.EN
+.EQ I (3b)
+f sub lambda~lineup =~sum from s (P sub sl (I sub sl - B sub sl ) / V sub sl ) /
+sum from s (P sub sl sup 2 / V sub sl )
+.EN
+
+.PP
+The first type of weighting (2a), called \fIprofile\fR weighting, weights
+by the profile. Since the weights cancel this gives the simple extraction (3a)
+consisting of the direct summation of the pixels within the aperture.
+It has the virtue of being simple and computationally fast (since the
+profile model does not have to be determined).
+.PP
+The second type of weighting (2b), called \fIvariance\fR weighting,
+uses a model for the variance of the pixel intensities.
+The model is based on Poisson statistics for a linear quantum detector.
+The first term is commanly call the \fIreadout\fR noise and the second term
+is the Poisson noise. The actual value of $v sub 1$ is the reciprical of
+the number of photons per digital intensity unit (ADU). A simple variant of
+this type of weighting is to let $v sub 1$ equal zero. Since the actual
+scale of the variance cancels we can then set $v sub 0$ to unity to obtain
+
+.EQ I (4)
+f sub lambda~=~sum from s (P sub sl (I sub sl - B sub sl )) /
+sum from s P sub sl sup 2 .
+.EN
+
+The interpretation of this extraction is that the variance of the intensities
+is constant. It gives greater weight to the stronger parts of the spectrum
+profile than does the profile weighting (3a) since the weights are
+$P sub sl sup 2$. Equation (4) has the virtue that one need not know the
+readout noise or the ADU to photon number conversion.
+.NH 3
+Optimal Extraction
+.PP
+Variance weighted extraction is sometimes called optimal extraction because
+it is optimal in a statistical sense. Specifically,
+the relative contribution of a pixel to the sum is related to the uncertainty
+of its intensity. The uncertainty is measured by the expected variance of
+a pixel with that intensity. The degree of optimality depends on how well
+the relative variances of the pixels are known.
+.PP
+A discussion of the concepts behind optimal extraction is given in the paper
+\fIAn Optimal Extraction Algorithm for CCD Spectroscopy\fR by Keith Horne
+(\fBPASP\fR, June 1986). The weighting described in Horne's paper is the
+same as the variance weighting described in this paper. The differences
+in the algorithms are primarily in how the model profiles $P sub sl$ are
+determined.
+.NH 3
+Profile Determination
+.PP
+The profiles of the spectra along the spatial axis are determined when
+either the detection and replacement of bad pixels or variance
+weighting are specified. The requirements on the profiles are that
+they have the same shape as the image profiles at a each dispersion
+point and that they be as noise free and uncontaminated as possible.
+The algorithm used to create these profiles is to average a specified
+number of consecutive background subtracted image profiles immediately
+preceding the wavelength to which a profile refers. When there are an
+insufficient number of image profiles preceding the wavelength being
+extracted then the following image profiles are also used to make up
+the desired number. The image profiles are interpolated to a common
+center before averaging using the curve given in the aperture
+definition. The averaging reduces the noise in the image data while
+the centering eliminates shifts in the spectrum as a function of
+wavelength which would broaden the profile relative to the profile of a
+single image line or column. It is assumed that the spectrum profile
+changes slowly with wavelength so that by using profiles near a given
+wavelength the average profile shape will correctly reflect the profile
+of the spectrum at that wavelength.
+.PP
+The average profiles are determined in parallel with the extraction,
+which proceeds sequentially through the image. Initially the first set
+of spectrum profiles is read from the image and interpolated to a common
+center. The profiles are averaged excluding the first profile to be
+extracted; the image profiles in the average never include the image
+profile to be extracted. Subsequently the average profile is updated
+by adding the last extracted image profile and subtracting the image
+profile which no longer belongs in the average. This allows each image
+profile to be accessed and interpolated only once and makes the
+averaging computationally efficient. This scheme also allows excluding
+bad pixels from the average profile. The average profile is used to
+locate and replace bad pixels in the image profile being extracted as
+discussed in the following sections. Then when this profile is added
+into the average for the next image profile the detected bad pixels are
+no longer in the profile.
+.PP
+In summary this algorithm for determining the spectrum profile
+has the following advantages:
+
+.IP (1)
+No model dependent smoothing is done.
+.IP (2)
+There is no assumption required about the shape of the profile.
+The only requirement is that the profile shape change slowly.
+.IP (3)
+Only one pass through the image is required and each image profile
+is accessed only once.
+.IP (4)
+The buffered moving average is very efficient computationally.
+.IP (5)
+Bad pixels are detected and removed from the profile average as the
+extraction proceeds.
+
+.NH 3
+Detection and Elimination of Bad Pixels
+.PP
+One of the important features of the aperture extraction package is the
+detection and elimination of bad pixels. The average profile described
+in the previous section is used to find pixels which deviate from this
+profile. The algorithm is straightforward. A model spectrum of the
+image profile is obtained by scaling the normalized profile to the
+image profile. The scale factor is determined using chi squared fitting:
+
+.EQ I (6)
+M sub sl~=~P sub sl~left { sum from s ((I sub sl - B sub sl ) P sub sl /
+V sub sl)~/~ sum from s (P sub sl sup 2 / V sub sl ) right } .
+.EN
+
+The RMS of this fit is determined and pixels deviating by more than a
+user specified factor times this RMS are rejected. The fit is then
+repeated excluding the rejected points. These steps are repeated until
+the user specified number of points have been rejected or no further deviant
+points are detected. The rejected points in the image profile are then
+replaced by their model values.
+.PP
+This algorithm is based only on the assumption that the spatial profile
+of the spectrum (no matter what it is) changes slowly with wavelength.
+It is very sensitive at detecting departures from the expected profile.
+Its main defect is that in the first pass at the fit all of the image profile
+is used. If there is a very badly deviant point and the rest of the profile
+is weak then the scale factor may favor the bad pixel more than the
+rest of the profile resulting in rejecting good profile points and not
+the bad pixel.
+.NH 3
+Relation of Optimal Extraction to Model Extraction
+.PP
+Equation (1) defines the extraction process in terms of a weighted sum
+of the pixel intensities. However, the actual extraction operations
+performed by the task \fBsumextract\fR are
+
+.EQ I (7a)
+f sub lambda~mark =~sum from s (I sub sl - B sub sl )
+.EN
+.EQ I (7b)
+f sub lambda~lineup =~sum from s M sub sl
+.EN
+
+where $M sub sl$ is the model spectrum fit to the background subtracted
+image spectrum $(I sub sl - B sub sl )$
+defined in the previous section (equation 6). It is not obvious at first that
+(7b) is equivalent to (3b). However, if one sums (6) and uses the fact
+that the sum of the normalized profile is unity one is left with equation (3b).
+.PP
+Equations (6) and (7b) provide an alternate way to think about the
+extracted one dimensional spectra. Sum extraction of the model spectrum
+is used instead of the weighted sum for variance weighted extraction
+because the model spectrum is a product of the profile determination
+and the bad pixel cleaning process. It is then more convenient
+and efficient to use the simple equations (7).
+.NH 2
+Strip Extraction
+.PP
+The task \fBstripextract\fR uses one dimensional image interpolation
+to shift the pixels along the spatial axes so that in the resultant
+output image the center of the aperture is exactly aligned with the
+image lines or columns. The cleaning of bad pixels is an option
+in this extraction using the methods described above. In addition
+the model spectrum described above may be extracted as a two
+dimensional image. In fact, the only difference between strip extraction
+and sum extraction is whether the final step of summing the pixels
+in the aperture along the spatial axis is performed.
+.PP
+The primary use of \fBstripextract\fR is as a diagnostic tool. It
+allows the user to see the background subtracted, cleaned and/or model
+spectrum as an image before it is summed to a one dimensional spectrum.
+In addition the two dimensional format allows use of other IRAF tools such as
+smoothing operators. When appropriate
+it is a much simpler method of removing detector distortions and alignment
+errors than the full two dimensional mapping and image transformation
+available with the \fBlongslit\fR package.
+.NH
+Examples
+.de CS
+.nf
+.ft L
+..
+.de CE
+.fi
+.ft R
+..
+.PP
+This section is included because the flexibility and many options of
+the tasks allows a wide range of applications. The examples illustrate
+the use of the task parameters for manipulating input images, output
+images, and reference images, and setting apertures interactively and
+noninteractively. They do not illustrate the different possibilities
+in extraction or the interactive aperture definition and editing
+features. These examples are meant to be relevant to actual data
+reduction and analysis problems. For the purpose of these examples we
+will assume the dispersion axis is along the second image axis; i.e.
+DISPAXIS = 2.
+.PP
+The simplest problem is the extraction of an object spectrum which
+is centered on column 200. To extract the spectrum with an aperture
+width of 20 pixels an image section can be used.
+
+.CS
+cl> sumextract image[190:209,*] obj1d
+cl> stripextract image[190:209,*] obj2d
+.CE
+
+To set the aperture center and limits interactively the edit option can be
+used with or without the image section. This also allows fractional pixel
+centering and limits.
+.PP
+If the object slit position changes the spectrum profile can be traced first
+and then extracted.
+
+.CS
+cl> trace image[190:209,*]
+cl> sumextract image[190:209,*] obj1d
+cl> stripextract image[190:209,*] obj2d
+.CE
+
+By default the apertures are defined and/or edited interactively in
+\fBtrace\fR and editing is not the default in \fBsumextract\fR or
+\fBstripextract\fR.
+.PP
+A more typical example involves many images. In this case a list of images
+is used though, of course, each image could be done separately as
+in the previous examples. There are three common forms of lists, a
+pattern matching template, a comma separated list, and an "@" file.
+In addition the template editing metacharacter, "%", may be used
+to create new output image names based on input image names.
+If the object positions are different in each image then we can select
+apertures with image sections or using the editing option. Some examples
+are
+
+.CS
+cl> sumextract image1[10:29,*],image2[32:51] obj1,obj2
+cl> sumextract image* e//image* edit+
+cl> sumextract image* image%%ex%* edit+
+cl> sumextract @images @images edit+
+.CE
+
+The "@" files can be created from the other two types of lists using the
+\fBsections\fR task in the \fBimages\fR package. An important feature
+of the image templates is the use of the concatenation operator. Note,
+however, this a feature of image templates and not file templates.
+Also the output root name may be the same as the input
+name because an extension is added provided there are no image
+sections in the input images.
+.PP
+If the object positions are the same then the apertures can be defined once
+and the remaining objects can be extracted using a reference image.
+
+.CS
+cl> apedit image1
+cl> sumextract image* image* ref=image1
+.CE
+
+Rather than using \fBapedit\fR one can use \fBsumextract\fR alone with
+the edit switch set. The command is
+
+.CS
+cl> sumextract image* image* ref=image1 edit+
+.CE
+
+The task queries whether to edit the apertures for each image.
+For the first image respond with "yes" and set the apertures interactively.
+For the second task respond with "NO". Since the aperture for "image1"
+was recorded when the first image was extracted it then acts as the reference
+for the remaining images. The emphatic response "NO" turns off the edit switch
+for all the other images. One difference between this example and the
+previous one is that the task cannot be run as a background batch task.
+.PP
+The extension to using traced apertures in the preceding examples is
+very similar.
+
+.CS
+cl> apedit image1
+cl> trace image* ref=image1 edit-
+cl> sumextract image* image*
+cl> stripextract image* image*
+.CE
+
+.PP
+Another common type of data has multiple spectra on each image. Some examples
+are echelle and multislit spectra. Echelle extractions usually are done
+interactively with tracing. Thus, the commands are
+
+.CS
+cl> trace ech*
+cl> sumextract ech* ech*
+.CE
+
+For multislit spectra the slitlets are usually referenced by creating
+an "@" file containing the image sections. The usage for extraction
+is then
+
+.CS
+cl> sumextract @slits @slitsout
+.CE
+
+.PP
+The aperture definitions can be transfered from a reference image to
+other images using \fBapedit\fR. There is no particular reason to
+do this except that reference images would not be needed in
+\fBtrace\fR, \fBsumextract\fR or \fBstripextract\fR. The transfer
+is accomplished with the following command
+
+.CS
+cl> apedit image1
+cl> apedit image* ref=image1 edit-
+.CE
+
+The above can also be combined into one step by editing the first image
+and then responding with "NO" to the second image query.
+.NH
+Future Developments
+.PP
+The IRAF extraction package \fBapextract\fR is going to continue to
+evolve because 1) the extraction of one and two dimensional spectra
+from two dimensional images is an important part of reducing echelle,
+longslit, multislit, and multiaperture spectra, 2) the final strategy
+for handling multislit and multiaperture spectra produced by aperture
+masks or fiber optic mapping has not yet been determined, and 3) the
+extraction package and the algorithms have not received sufficient user
+testing and evaluation. Changes may include some of the following.
+
+.IP (1)
+Determine the actual variance from the data rather than using the Poisson
+CCD model.
+.IP (2)
+Another task, possibly called \fBapfind\fR, is needed to automatically find
+profile positions in multiaperture, multislit, and echelle spectra.
+.IP (3)
+The bad pixel detection and removal algorithm does not handle well the case
+of a very strong cosmic ray event on top of a very weak spectrum profile.
+A heuristic method to make the first fitting pass of the average
+profile to the image data less prone to errors due to strong cosmic rays
+is needed.
+.IP (4)
+The aperture definition structure is general enough to allow the aperture
+limits along the dispersion dimension to be variable. Eventually aperture
+definition and editing will be available using an image display. Then
+both graphics and image display editing switches will be available.
+An image display interface will make extraction of objective prism
+spectra more convenient than it is now.
+.IP (5)
+Other types of extraction weighting may be added.
+.IP (6)
+Allow the extraction to be locally perpendicular to the traced curve.
diff --git a/noao/twodspec/apextract/doc/old/apextract1.ms b/noao/twodspec/apextract/doc/old/apextract1.ms
new file mode 100644
index 00000000..b586daad
--- /dev/null
+++ b/noao/twodspec/apextract/doc/old/apextract1.ms
@@ -0,0 +1,811 @@
+.EQ
+delim $$
+define sl '{s lambda}'
+.EN
+.RP
+.TL
+The IRAF APEXTRACT Package
+.AU
+Francisco Valdes
+.AI
+IRAF Group - Central Computer Services
+.K2
+P.O. Box 26732, Tucson, Arizona 85726
+.AB
+The IRAF \fBapextract\fR package provides tools for the extraction of
+one and two dimensional spectra from two dimensional images
+such as echelle, long slit, multifiber, and multislit spectra.
+Apertures of fixed spatial width define the regions of
+the two dimensional images to be extracted at each point along the
+dispersion axis. Apertures may follow changes in the positions of
+the spectra as a function of position along the dispersion axis.
+The spatial and dispersion axes may be oriented along either image axis.
+Extraction to one dimensional spectra consists of a weighted sum of the pixels
+within the apertures at each point along the dispersion axis. The
+weighting options provide the simple sum of the pixel values and a
+weighting by the expected uncertainty of each pixel. Two dimensional
+extractions interpolate the spectra in the spatial axis to produce
+image strips with the position of the spectra exactly aligned with one
+of the image dimensions. The extractions also include optional
+background subtraction, modeling, and bad pixel detection and replacement.
+The tasks are flexible in their ability to define and edit apertures,
+operate on lists of images, use apertures defined for reference
+images, and operate both very interactively or noninteractively.
+The extraction tasks are efficient and require only one pass through
+the data. This paper describes the package organization, the tasks,
+the algorithms, and the data structures.
+.AE
+.NH
+Introduction
+.PP
+The IRAF \fBapextract\fR package provides tools for the extraction of
+one and two dimensional aperture spectra from two dimensional format
+images such as those produced by echelle, long slit, multifiber, and
+multislit spectrographs. This type of data is becoming increasingly
+common because of the efficiency of data collection and technological
+improvements in spectrographs and detectors. The trend is to greater
+and greater numbers of spectra per image. Extraction is one of the
+fundamental operations performed on these types of two dimensional
+spectral images, so a great deal of effort has gone into the design and
+development of this package and to making it easy to use.
+.PP
+The tasks are flexible and have many options. To make the best use of
+them it is important to understand how they work. This paper provides
+a general description of the package organization, the tasks, the algorithms,
+and the data structures. Specific descriptions of parameters
+and usage may be found in the IRAF help pages for the tasks which
+are included as appendices to this paper. The image reduction "cookbooks"
+also provide examples of usage for specific instruments or types
+of instruments.
+.PP
+Extraction of spectra consists of three logical steps. First, locating
+the spectra in the two dimensional image. This includes defining the
+dispersion direction, the positions of the spectra at some point
+along the dispersion direction, the spatial extent or aperture to be
+used for extraction, and possible information about where the background
+for each spectrum is to be determined. This information is maintained
+in the package as structures called \fIapertures\fR. The second step is
+to measure the positions of the spectra at other points along the dispersion.
+This process is called tracing. Tracing is optional if the spectra
+are exactly aligned with the dispersion direction. The final step is
+to extract the spectra into one or two dimensional images.
+.PP
+The \fBapextract\fR package identifies the image axes with the spatial
+and dispersion axes. Thus, during extraction, pixels of constant
+wavelength are assumed to be along a line or column. In this paper the
+terms \fIslit\fR or \fIspatial\fR axis and \fIdispersion\fR or
+\fIwavelength\fR axis are used to refer to the image axes corresponding
+to the spatial and dispersion axes. To simplify the presentation a
+cut across the dispersion axis will be called a line even though it
+could also be a column.
+.PP
+Often a small degree of
+misalignment between the image axes and the true dispersion and spatial
+axes is not important. The main effect of misalignment is a broadening
+of the spectral features due to the difference in wavelength on
+opposite sides of the extraction aperture. If the misalignment is
+significant, however, the image may be rotated with the task
+\fBrotate\fR in the \fBimages\fR package or remapped with the
+\fBlongslit\fR package tasks for coordinate rectification.
+.PP
+It does not matter which image axis is the dispersion axis since the
+tasks work equally well in either orientation. However, the dispersion
+axis must be defined, with the \fBtwodspec\fR task \fBsetdisp\fR,
+before these tasks may be used. This task is a simple script which
+adds the parameter DISPAXIS to the image headers. The \fBapextract\fR
+tasks, like the \fBlongslit\fR tasks, look in the header to determine
+the dispersion axis.
+.NH
+The APEXTRACT Package
+.PP
+In this section the organization of the \fBapextract\fR package and the
+functions and parameters of the tasks are briefly described. More detailed
+descriptions are given in the help pages for the tasks. The tasks in the
+package are:
+
+.ce
+.ft B
+The APEXTRACT Tasks
+
+.ft L
+.nf
+ apdefault - Set the default aperture parameters
+ apedit - Edit apertures interactively
+ apfind - Automatically find spectra and define apertures
+ apio - Set the I/O parameters for the APEXTRACT tasks
+ apnormalize - Normalize 2D apertures by 1D functions
+ apstrip - Extract two dimensional aperture strips
+ apsum - Extract one dimensional aperture sums
+ aptrace - Trace positions of spectra
+.fi
+.ft R
+
+.PP
+The tasks are highly integrated so that each task includes some or all of
+the functions and parameters of the other tasks. Thus, these tasks
+reflect the logical organization of the extraction process rather than
+a set of disparate tools. One reason for this organization is to group
+the parameters by function into easy to manage \fIparameter sets
+(psets)\fR. The tasks \fBapdefault\fR and \fBapio\fR are just psets
+for specifying the default aperture parameters and the I/O parameters
+of the package; in other words, they do nothing but provide a grouping
+of parameters. Executing these tasks is a shorthand for the command
+"eparam apdefault" or "eparam apio".
+.PP
+The input/output parameters in \fBapio\fR specify the aperture database,
+an optional log file for brief, time stamped log information, an optional
+metacode plot file for saving plots of the apertures, the traces, and the
+quick look extracted spectra, and the graphics input and output devices
+(almost always the user's terminal). One point about the plot file is
+that the plots are recorded even if the user chooses not to view these
+graphs as the task is run interactively or noninteractively. This allows
+reviewing the traces and spectra with a tool like \fBgkimosaic\fR.
+.PP
+The default aperture parameters specify the aperture limits (basically
+the width of the aperture and position relative to the center of the
+spectrum) and the background fitting parameters. The background
+parameters are the standard parameters used by the \fBicfit\fR package
+with which the user is assumed to be familiar. For more on this see
+the help information for \fBicfit\fR.
+.PP
+The other tasks are both psets and executable tasks. There are a
+number features which are common to all these tasks. First, they
+follow the same steps in defining apertures for the input images.
+These steps are:
+.IP (1)
+If a reference image is specified then the database is searched for
+apertures previously defined for this image.
+.IP (2)
+If apertures are found for the reference image they may be recentered
+on the spectra in the input image at a specified line. This does not
+change the shape of the apertures but only adds a shift in the center
+coordinate of the apertures along the spatial axis.
+.IP (3)
+If a reference image is not specified or if no reference apertures are found
+then the database is searched for previous apertures for the input image.
+.IP (4)
+If there are no apertures defined either from a reference image or previous
+apertures for the input image then an automatic algorithm may be used to find
+a specified number of spectra (based on peak values) and assign them default
+apertures.
+.IP (5)
+Finally, a sophisticated graphical aperture editor may be used to examine,
+define, and modify apertures.
+.IP (6)
+When tracing, extracting, or normalizing flat field spectra,
+if no apertures have been defined by the steps above then a single default
+aperture, centered in the image, is defined.
+
+Any apertures created, modified, or adopted from a reference image
+may be recorded in the database for the input image.
+.PP
+The operations listed above are selected by parameters common to each of the
+tasks. For example the parameter \fIedit\fR selects whether to enter
+the aperture editor and is present in each of the executable tasks.
+On the other hand the parameters specific to the aperture editor,
+while accessed by any of the tasks, reside only in the parameter set of
+the task \fBapedit\fR. In this way parameters are distributed
+by logical function rather than including them in each task.
+.PP
+In addition to the aperture editing and finding functions available in
+every task, some of the tasks include functions for tracing, extracting,
+or normalizing the spectra. The tasks \fBapsum\fR and \fBapstrip\fR,
+which extract one and two dimensional spectra, are at the top of the
+hierarchy and include all the logical functions provided by the package.
+Thus, in most cases the user need only use the task \fBapsum\fR to define
+apertures, trace the spectra, and extract them.
+.PP
+Another feature common to the tasks is their interactive and noninteractive
+modes. When the parameter \fIinteractive\fR is set to \fIno\fR then the
+aperture editing, interactive trace fitting, and review of the extracted
+one dimensional spectra functions of the package are bypassed. Note that
+this means you do not have to explicitly set the parameter \fIedit\fR,
+or those for other purely interactive functions,
+to \fIno\fR when extracting spectra noninteractively. In the noninteractive
+mode there are also no queries.
+.PP
+The interactive mode includes the interactive graphical functions of
+aperture editing, trace fitting, and extraction review. In addition
+the user is queried at each step. For example the user will be queried
+whether to edit the apertures for a particular image if the task
+parameter for editing is set. The queries have four responses: \fIyes,
+no, YES,\fR and \fINO\fR. The lower case responses apply only to the
+particular query. The upper case responses apply to any further
+queries of the same type and suppress the query from appearing again.
+This is particularly useful when dealing with many images or many
+apertures. For example, when fitting the traced points interactively
+the user may examine the first few and then say \fINO\fR to skip the
+remaining apertures using the last defined fitting parameters. Note
+that if a plot file is specified the graphs showing the traced points
+and the fits are recorded even if they are not viewed interactively.
+.NH
+Algorithms
+.PP
+The \fBapextract\fR package consists of a number of logical functions or,
+in computerese, algorithms. These algorithms manipulate the aperture
+structure data and create output data in the form of images. In
+this section the various algorithms are described. In addition to the
+algorithms specific to the package, there are some general algorithms
+and tools used which appear in other IRAF tasks. Specifically there are the
+interactive curve fitting tools called \fBicfit\fR and the one
+dimensional centering algorithm called \fBcenter1d\fR. These are
+mentioned below and described in detail elsewhere in the help documentation.
+.NH 2
+Finding Spectra
+.PP
+When dealing with images containing large numbers of spectra it may be
+desirable to locate the spectra and define apertures automatically. The
+\fBapfind\fR algorithm provides this ability from any of the executable
+tasks and from the aperture editor using the 'f' key. It takes a cut
+across the dispersion axis by summing one or more image lines.
+All the local maxima are identified and ranked by intensity. Starting
+with the highest maxima any other peaks within a specified minimum
+separation are eliminated. The weakest remaining peaks exceeding the
+specified number are eliminated next. The positions of the
+spectra based on peak positions are refined by centering using the
+\fBcenter1d\fR algorithm. Finally identical apertures are assigned
+for each spectrum found.
+.PP
+When the algorithm is invoked by a task, with the parameter \fIfind\fR,
+there must be no previous or reference apertures in the database.
+The apertures assigned to the spectra have the parameters
+specified in the \fBapdefault\fR pset. When the algorithm is invoked
+from the aperture editor with the 'f' key then new apertures are
+added to any existing apertures up to the total number of apertures,
+existing plus new, given by the \fInfind\fR parameter. If there
+is a current aperture then copies of it are used to define the
+apertures for the new spectra. Thus, one method for defining many
+apertures is to use the editor to define one aperture, set its
+limits and background parameters, and then find the remaining apertures
+automatically.
+.NH 2
+Centering and Recentering
+.PP
+When new apertures are defined (except for a special key to mark apertures
+without centering) or when apertures are recentered, either with the
+centering key in the editor or with the task parameter \fIrecenter\fR,
+the center is determined using the \fBcenter1d\fR algorithm.
+This is described in the help documentation under the name \fBcenter1d\fR.
+Briefly, the data line is convolved with an asymmetric function of specified
+width. The convolution integral is evaluated using image interpolation.
+The sign of the convolution acts as a gradient to move from the starting
+position to the final position where the convolution is zero. This algorithm
+is good to about 5% of a pixel. It has two important parameters; the
+width of the convolution and the error distance between the starting
+and final positions. The width of the convolution determines the scale
+of features to which the centering is sensitive. The error distance is
+the greatest change allowed in the initial positions. If this error
+distance is exceeded then the centering fails and either a new aperture
+is not defined or the position of an existing aperture is not changed.
+.NH 2
+The Aperture Editor
+.PP
+The aperture editor is a sophisticated tool for defining and modifying
+apertures. It may also be used to selectively trace and extract
+spectra. Thus, the aperture editor may be used alone to perform all
+the functions for extracting spectra. The aperture editor uses a
+graphical presentation. A line or sum of lines is displayed. The
+apertures are marked above the line and identified with the aperture
+number. Information about the current aperture is shown on the status
+line. The cursor is used to mark new apertures, shift the center or
+aperture limits, and perform a variety of functions. Because there may
+be many apertures which the user wants to modify in the same way there
+is a mode switch to apply commands to all the apertures. The switch is
+toggled with the 'a' key and the mode is indicated on the status line.
+.PP
+There are also a number of colon commands. These allow resetting parameters
+explicitly rather than by cursor and interacting with the aperture
+database and the image data. The background fitting parameters such as
+the background regions and function order are set by switching to the
+interactive curve fitting package \fBicfit\fR. The line being edited is
+used to set the parameters. No background is actually extracted at this
+stage. The ALL mode applies to the background parameters as well.
+.PP
+The aperture editor has many commands. For a description of the
+commands see the help information for the task \fBapedit\fR. In
+summary the aperture editor is used to interactively define apertures,
+both centered on spectra and at arbitrary positions, adjust the limits
+and background parameters, and possibly select apertures to be traced
+and extracted. These functions may be applied independently on each
+aperture for maximum flexibility or applied to all apertures for ease
+of use with many apertures.
+.NH 2
+Tracing
+.PP
+The spectra to be extracted are not always aligned exactly with the
+image columns or lines. For consistent
+extraction it is important that the same part of the spectrum profile
+be extracted at each wavelength point. Thus, the extraction apertures
+allow for shifts along the spatial axis at each wavelength. The
+shifts are defined by a curve which is a function of the wavelength.
+The curve is determined by tracing the positions of the spectrum
+profile at a number of wavelengths and fitting a function to these
+positions.
+.PP
+The \fIaptrace\fR algorithm performs the tracing and curve fitting.
+The starting point along the dispersion axis (a line or column) for
+the tracing is specified by the user. The positions of the spectrum
+profiles are determined using the \fBcenter1d\fR algorithm
+(see the previous section on centering and the help page for \fBcenter1d\fR).
+The user specifies a step along the dispersion axis. At each step the
+positions of the profiles are redetermined using the preceding
+positions as the initial guesses. If the positions are lost at one step
+an attempt is made to recover the spectrum in the next step. If this
+also fails then tracing of that spectrum in that direction is finished.
+In order to enhance and trace weak spectra the user may specify a number
+of neighboring profiles to be summed before determining the profile positions.
+In addition to the other centering parameters, there is also a
+\fIthreshold\fR parameter to define a minimum contrast between the spectrum
+and the background.
+.PP
+Once the positions have been traced from the starting point to the ends of the
+aperture, or until the positions become indeterminate, a curve of a
+specified type and order is fit to the positions as a function of
+wavelength. The function fitting is performed with the \fBicfit\fR
+tools (see the help documentation for \fBicfit\fR). The curve fitting
+may be performed interactively or noninteractively. Note that when the
+curve is fit interactively the actual positions measured are graphed.
+However, the curve is stored in the aperture definition as an offset
+relative to the aperture center.
+.PP
+The tracing requires that the spectrum profile be continuous and have
+some kind of maxima. This means that arc calibration spectra or
+arbitrary regions of an extended object in a long slit spectrum cannot
+be traced. Flat topped spectra such as quartz lamp images taken through
+slits can be measured provided the width of the centering function is
+somewhat wider than the profile (to avoid centering on little peaks
+within the slit). For images which cannot be traced, reference apertures
+from images that can be traced are used. This is how apertures for
+arc spectra are defined and extracted. For sky apertures or the
+wings of extended objects the reference apertures can be shifted
+by the aperture editor without altering the shape of the aperture.
+.NH 2
+Sum Extraction
+.PP
+Sum extraction consists of the weighted sum of the pixels along the spatial axis
+within the aperture limits at each point along the dispersion axis.
+A background at each point along the dispersion may be determined by fitting a
+function to data in the vicinity of the spectrum and subtracting the
+function values estimated at each point within the aperture. The estimated
+background may be output as a one dimensional spectrum. Other options
+include the detection and replacement of deviant points such as due to
+cosmic rays.
+.PP
+Denote the image axis nearest the spatial axis by the index $s$ and
+the other image axis corresponding to the dispersion axis by $lambda$.
+The weighted extraction is defined by the equation
+
+.EQ I (1)
+f sub lambda~=~sum from s (W sub sl (I sub sl - B sub sl ) / P sub sl ) /
+sum from s W sub sl
+.EN
+
+where the sums are over all pixels along the spatial axis within some
+aperture. The $W$ are weights, the $I$ are pixel intensities,
+the $B$ are background intensities, and the $P$ are a normalized
+profile model.
+.PP
+There are many possible choices for the extraction weights. The extraction
+task \fBapsum\fR currently provides two:
+
+.EQ I (2a)
+W sub sl~mark =~P sub sl
+.EN
+.EQ I (2b)
+W sub sl~lineup =~P sub sl sup 2 / V sub sl
+.EN
+
+where $V sub sl$ is the variance of the pixel intensities given by the
+model
+
+.EQ I
+ V sub sl~=~v sub 0 + v sub 1~max (0,~I sub sl )~~~~if v sub 0~>~0
+.EN
+.EQ I
+ V sub sl~=~v sub 1~max (1,~I sub sl )~~~~~~~~~if v sub 0~=~0
+.EN
+
+Substituting these weights in equation (1) yields the extraction equations
+
+.EQ I (3a)
+f sub lambda~mark =~sum from s (I sub sl - B sub sl )
+.EN
+.EQ I (3b)
+f sub lambda~lineup =~sum from s (P sub sl (I sub sl - B sub sl ) / V sub sl ) /
+sum from s (P sub sl sup 2 / V sub sl )
+.EN
+
+.PP
+The first type of weighting (2a), called \fIprofile\fR weighting, weights
+by the profile. Since the weights cancel this gives the simple extraction (3a)
+consisting of the direct summation of the pixels within the aperture.
+It has the virtue of being simple and computationally fast (since the
+profile model does not have to be determined).
+.PP
+The second type of weighting (2b), called \fIvariance\fR weighting,
+uses a model for the variance of the pixel intensities.
+The model is based on Poisson statistics for a linear quantum detector.
+The first term is commonly call the \fIreadout\fR noise and the second term
+is the Poisson noise. The actual value of $v sub 1$ is the reciprocal of
+the number of photons per digital intensity unit (ADU). A simple variant of
+this type of weighting is to let $v sub 1$ equal zero. Since the actual
+scale of the variance cancels we can then set $v sub 0$ to unity to obtain
+
+.EQ I (4)
+f sub lambda~=~sum from s (P sub sl (I sub sl - B sub sl )) /
+sum from s P sub sl sup 2 .
+.EN
+
+The interpretation of this extraction is that the variance of the intensities
+is constant. It gives greater weight to the stronger parts of the spectrum
+profile than does the profile weighting (3a) since the weights are
+$P sub sl sup 2$. Equation (4) has the virtue that one need not know the
+readout noise or the ADU to photon number conversion.
+.NH 3
+Optimal Extraction
+.PP
+Variance weighted extraction is sometimes called optimal extraction because
+it is optimal in a statistical sense. Specifically,
+the relative contribution of a pixel to the sum is related to the uncertainty
+of its intensity. The uncertainty is measured by the expected variance of
+a pixel with that intensity. The degree of optimality depends on how well
+the relative variances of the pixels are known.
+.PP
+A discussion of the concepts behind optimal extraction is given in the paper
+\fIAn Optimal Extraction Algorithm for CCD Spectroscopy\fR by Keith Horne
+(\fBPASP\fR, June 1986). The weighting described in Horne's paper is the
+same as the variance weighting described in this paper. The differences
+in the algorithms are primarily in how the model profiles $P sub sl$ are
+determined.
+.NH 3
+Profile Determination
+.PP
+The profiles of the spectra along the spatial axis are determined when
+either the detection and replacement of bad pixels or variance
+weighting are specified. The requirements on the profiles are that
+they have the same shape as the image profiles at a each dispersion
+point and that they be as noise free and uncontaminated as possible.
+The algorithm used to create these profiles is to average a specified
+number of consecutive background subtracted image profiles immediately
+preceding the wavelength to which a profile refers. When there are an
+insufficient number of image profiles preceding the wavelength being
+extracted then the following image profiles are also used to make up
+the desired number. The image profiles are interpolated to a common
+center before averaging using the curve given in the aperture
+definition. The averaging reduces the noise in the image data while
+the centering eliminates shifts in the spectrum as a function of
+wavelength which would broaden the profile relative to the profile of a
+single image line or column. It is assumed that the spectrum profile
+changes slowly with wavelength so that by using profiles near a given
+wavelength the average profile shape will correctly reflect the profile
+of the spectrum at that wavelength.
+.PP
+The average profiles are determined in parallel with the extraction,
+which proceeds sequentially through the image. Initially the first set
+of spectrum profiles is read from the image and interpolated to a common
+center. The profiles are averaged excluding the first profile to be
+extracted; the image profiles in the average never include the image
+profile to be extracted. Subsequently the average profile is updated
+by adding the last extracted image profile and subtracting the image
+profile which no longer belongs in the average. This allows each image
+profile to be accessed and interpolated only once and makes the
+averaging computationally efficient. This scheme also allows excluding
+bad pixels from the average profile. The average profile is used to
+locate and replace bad pixels in the image profile being extracted as
+discussed in the following sections. Then when this profile is added
+into the average for the next image profile the detected bad pixels are
+no longer in the profile.
+.PP
+In summary this algorithm for determining the spectrum profile
+has the following advantages:
+
+.IP (1)
+No model dependent smoothing is done.
+.IP (2)
+There is no assumption required about the shape of the profile.
+The only requirement is that the profile shape change slowly.
+.IP (3)
+Only one pass through the image is required and each image profile
+is accessed only once.
+.IP (4)
+The buffered moving average is very efficient computationally.
+.IP (5)
+Bad pixels are detected and removed from the profile average as the
+extraction proceeds.
+
+.NH 3
+Detection and Elimination of Bad Pixels
+.PP
+One of the important features of the aperture extraction package is the
+detection and elimination of bad pixels. The average profile described
+in the previous section is used to find pixels which deviate from this
+profile. The algorithm is straightforward. A model spectrum of the
+image profile is obtained by scaling the normalized profile to the
+image profile. The scale factor is determined using chi-squared fitting:
+
+.EQ I (6)
+M sub sl~=~P sub sl~left { sum from s ((I sub sl - B sub sl ) P sub sl /
+V sub sl )~/~ sum from s (P sub sl sup 2 / V sub sl ) right } .
+.EN
+
+The RMS of this fit is determined and pixels deviating by more than a
+user specified factor times this RMS are rejected. The fit is then
+repeated excluding the rejected points. These steps are repeated until
+the user specified number of points have been rejected or no further deviant
+points are detected. The rejected points in the image profile are then
+replaced by their model values.
+.PP
+This algorithm is based only on the assumption that the spatial profile
+of the spectrum (no matter what it is) changes slowly with wavelength.
+It is very sensitive at detecting departures from the expected
+profile. It has two problems currently. Because the input line is
+first interpolated to the same center as the profile, single bad pixels
+are generally broadened to two bad pixels, making it harder to find the
+bad data. Also, in the first pass at the fit all of the image profile
+is used so if there is a very badly deviant point and the rest of the
+profile is weak then the scale factor may favor the bad pixel more than
+the rest of the profile. This may result in rejecting good profile
+points and not the bad pixel.
+.NH 3
+Relation of Optimal Extraction to Model Extraction
+.PP
+Equation (1) defines the extraction process in terms of a weighted sum
+of the pixel intensities. However, the actual extraction operations
+performed by the task \fBapsum\fR are
+
+.EQ I (7a)
+f sub lambda~mark =~sum from s (I sub sl - B sub sl )
+.EN
+.EQ I (7b)
+f sub lambda~lineup =~sum from s M sub sl
+.EN
+
+where $M sub sl$ is the model spectrum fit to the background subtracted
+image spectrum $(I sub sl - B sub sl )$
+defined in the previous section (equation 6). It is not obvious at first that
+(7b) is equivalent to (3b). However, if one sums (6) and uses the fact
+that the sum of the normalized profile is unity one is left with equation (3b).
+.PP
+Equations (6) and (7b) provide an alternate way to think about the
+extracted one dimensional spectra. Sum extraction of the model spectrum
+is used instead of the weighted sum for variance weighted extraction
+because the model spectrum is a product of the profile determination
+and the bad pixel cleaning process. It is then more convenient
+and efficient to use the simple equations (7).
+.NH 2
+Strip Extraction
+.PP
+The task \fBapstrip\fR uses one dimensional image interpolation
+to shift the pixels along the spatial axis so that in the resultant
+output image the center of the aperture is exactly aligned with the
+image lines or columns. The cleaning of bad pixels is an option
+in this extraction using the methods described above. In addition
+the model spectrum, described above, may be extracted as a two
+dimensional image. In fact, the only difference between strip extraction
+and sum extraction is whether the final step of summing the pixels
+in the aperture along the spatial axis is performed.
+.PP
+The primary use of \fBapstrip\fR is as a diagnostic tool. It
+allows the user to see the background subtracted, cleaned, and/or model
+spectrum as an image before it is summed to a one dimensional spectrum.
+In addition the two dimensional format allows use of other IRAF tools such as
+smoothing operators. When appropriate
+it is a much simpler method of removing detector distortions and alignment
+errors than the full two dimensional mapping and image transformation
+available with the \fBlongslit\fR package.
+.NH 2
+Aperture Normalization
+.PP
+The special algorithm/task \fBapnormalize\fR normalizes the two dimensional
+image data within an aperture by a smooth function of the dispersion
+coordinate. Unlike the extraction tasks the output of this algorithm is
+a two dimensional image of the same format as the input image. This function
+is used primarily for creating flat field images in which the large
+scale shape of the quartz spectra and the variations in level between the
+spectra are removed and the regions between the spectra, where there is no
+signal, are set to unity. It may also be used to normalize two dimensional
+spectra to a unit continuum at some point in the spectrum, such as the center.
+.PP
+The algorithm is to extract a one dimensional spectrum for each aperture,
+fit a smooth function to the spectrum, and then divide this spectrum
+back into the two dimensional image. Points outside the apertures are
+set to 1. This is the same algorithm used in the \fBlongslit\fR package
+by the task \fBresponse\fR except that it applies to arbitrary apertures
+rather than to image sections.
+.PP
+Apertures are defined in the same way as for extraction. The normalization
+spectrum may be obtained from a different aperture than the aperture to be
+normalized. Generally the normalization apertures are either the same or
+narrower than the apertures to be normalized. The continuum fitting also
+uses the \fBicfit\fR package. Sample regions and iterative sigma clipping
+are used to remove spectral lines from the continuum fits.
+.PP
+There are two commonly used approaches to fitting the extracted spectra
+in flat field images. First, a constant function is fit. This has the
+effect of simply normalizing the apertures to near unity without affecting
+the shape of spectra in any way. This removes response effects at all scales,
+from spectra flatten with this flat field. However, it does not
+preserve total counts, it introduces the shape of the quartz spectrum,
+and it removes the blaze function. The second approach is to fit the
+large scale shape of the quartz spectra. This removes smaller scale
+response effects such a fringing and individual pixel responses while
+preserving the total counts by leaving the blaze function alone. There are
+cases where each of these approaches is applicable.
+.NH
+Apertures
+.PP
+Apertures are the basic data structures used in the package; hence the
+package name. An aperture defines a region of the two dimensional image
+to be extracted. The aperture definitions are stored in a database.
+An aperture consists of the following components:
+
+.IP ID
+.br
+An integer identification number. The identification number must be
+unique. It is used as the default extension during extraction of
+the spectra. Typically the IDs are consecutive positive integers
+ordered by increasing or decreasing slit position.
+.IP BEAM
+.br
+An integer beam number. The beam number need not be
+unique; i.e. several apertures may have the same beam number.
+The beam number will be recorded in the image header of the
+the extracted spectrum. By default the beam number is the same as
+the ID.
+.IP CENTER[2]
+.br
+The center of the aperture along the slit and dispersion axes in the two
+dimensional image.
+.IP LOWER[2]
+.br
+The lower limits of the aperture, relative to the aperture center,
+along the slit and dispersion axes. The lower limits need not be less
+than the center.
+.IP UPPER[2]
+.br
+The upper limits of the aperture, relative to the aperture center,
+along the slit and dispersion axes. The upper limits need not be greater
+than the center.
+.IP APAXIS
+.br
+The aperture or spatial axis.
+.IP CURVE
+.br
+An offset to be added to the center position for the aperture axis as
+a function of the wavelength. The function is one of the standard IRAF
+types; a legendre polynomial, a chebyshev polynomial, a linear spline,
+or a cubic spline.
+.IP BACKGROUND
+.br
+Parameters for background subtraction along the aperture axis based on
+the interactive curve fitting (\fBicfit\fR) tools.
+
+.PP
+The aperture center is the only absolute coordinate (relative to the
+image or image section). The other aperture parameters and the
+background fitting regions are defined relative to the center. Thus,
+an aperture may be repositioned easily by changing the center
+coordinates. Also constant aperture size, shape (curve), and
+background regions may be maintained for many apertures.
+.PP
+The edges of the aperture along the spatial axis at each point along the
+dispersion axis are given by evaluating the offset curve at that dispersion
+coordinate and adding the aperture center and the lower or upper limits
+for the aperture axis. The edges of the aperture along the dispersion axis
+do not have an offset curve and are currently fixed to define the entire
+length of the image. In the future this may not be the case such as
+in applications with objective prism spectra.
+.PP
+Apertures for a particular image may be defined in several ways. They
+may be defined and modified graphically with an aperture editor. Default
+apertures may be defined automatically with parameters from the
+\fBapdefault\fR pset using an aperture finding algorithm. Another
+method is to specify that the apertures for one image use the aperture
+definitions from another "reference" image. In the rare cases where
+apertures are not defined at the stage of tracing or extracting then
+a single default aperture centered in the image is created.
+.NH 2
+The Database
+.PP
+The aperture information is stored in a database. The structure and type of
+database is expected to change in the future and as far as the package and
+user need be concerned it is just a black box with some name specified in
+the database name parameter. However, accepting that the database structure may
+change it may be of use to the user to understand the nature of the current
+text file / directory format database. The database is a directory containing
+text files. It is automatically created if necessary. The aperture data
+for all the apertures from a single image are stored in a text file
+with the name given by the image name (with special characters replaced
+with '_') prefixed with "ap". Updates of the aperture data are performed
+by overwriting the database file.
+.PP
+The content of a file consists of a comment (beginning with a #) giving
+the date created/updated, a record identification (there is one record
+per aperture) with the image name, aperture number and aperture
+coordinate in the aperture and dispersion axes. The following lines
+give information about the aperture. The position and shape of an
+aperture is given by a center coordinate along the aperture axis (given
+by the axis keyword) and the dispersion axis. There are lower and
+upper limits for the aperture relative to this center, again along both
+axis. Currently the limits along the dispersion axis are the image
+boundaries. The background keyword introduces the background
+subtraction parameters. Finally there is an offset or trace function
+which is added to the center at each point along the dispersion axis.
+function. The offset is generally zero at the dispersion point
+corresponding to the aperture center.
+.PP
+This offset or trace function is described by a \fBcurfit\fR array under
+the keyword curve. The first value is the number of elements in this
+array. The first element is a magic number specifying the function
+type. The next number is the order or number of spline pieces. The
+next two elements give the range over which the curve is defined. In
+the \fBapextract\fR case it is the edges of the image along the dispersion.
+The remaining elements are the function coefficients. The form of the
+the function is specific to the IRAF \fBcurfit\fR math routines. Note that
+the coefficients apply to an independent variable which is -1 at the
+beginning of the defined range (element 3) and 1 at the end of the range
+(element 4). For further details consult the IRAF group.
+.PP
+An example database file for one aperture from an image "ech001" is given
+below.
+
+.ft L
+.nf
+ # Fri 14:33:35 08-May-87
+ begin aperture ech001 1 22.75604 100.
+ image ech001
+ aperture 1
+ beam 1
+ center 22.75604 100.
+ low -2.680193 -99.
+ high 3.910698 100.
+ background
+ xmin -262.
+ xmax 262.
+ function chebyshev
+ order 1
+ sample -10:-6,6:10
+ naverage -3
+ niterate 0
+ low_reject 3.
+ high_reject 3.
+ grow 0.
+ axis 1
+ curve 6
+ 2.
+ 2.
+ 1.
+ 200.
+ -0.009295368
+ -0.3061974
+.fi
+.ft R
+.NH
+Future Developments
+.PP
+The IRAF extraction package \fBapextract\fR is going to continue to
+evolve because the extraction of one and two dimensional spectra
+from two dimensional images is an important part of reducing echelle,
+longslit, multislit, and multiaperture spectra. Changes may include
+some of the following:
+
+.IP (1)
+Determine the actual variance from the data rather than using the Poisson
+CCD model. Also output the variance vector if desired.
+.IP (2)
+The bad pixel detection and removal algorithm does not handle well the case
+of a very strong cosmic ray event on top of a very weak spectrum profile.
+A heuristic method to make the first fitting pass of the average
+profile to the image data less prone to errors due to strong cosmic rays
+is needed. Also the detection should be done by interpolating the profile
+to the original image data rather than the other way around, in order to
+avoid broadening cosmic rays by interpolation.
+.IP (3)
+The aperture definition structure is general enough to allow the aperture
+limits along the dispersion dimension to be variable. Eventually aperture
+definition and editing will be available using an image display. Then
+both graphics and image display editing switches will be available.
+An image display interface will make extraction of objective prism
+spectra more convenient than it is now.
+.IP (4)
+Other types of extraction weighting may be added.
diff --git a/noao/twodspec/apextract/doc/old/apextract2.ms b/noao/twodspec/apextract/doc/old/apextract2.ms
new file mode 100644
index 00000000..35b42390
--- /dev/null
+++ b/noao/twodspec/apextract/doc/old/apextract2.ms
@@ -0,0 +1,14 @@
+.RP
+.TL
+Cleaning and Optimal Extraction with the IRAF APEXTACT Package
+.AU
+Francisco Valdes
+.AI
+IRAF Group - Central Computer Services
+.K2
+P.O. Box 26732, Tucson, Arizona 85726
+.AB
+.AE
+.NH
+Introduction
+.PP
diff --git a/noao/twodspec/apextract/doc/revisions.v3.ms b/noao/twodspec/apextract/doc/revisions.v3.ms
new file mode 100644
index 00000000..f78362a5
--- /dev/null
+++ b/noao/twodspec/apextract/doc/revisions.v3.ms
@@ -0,0 +1,522 @@
+.nr PS 9
+.nr VS 11
+.RP
+.ND
+.TL
+APEXTRACT Package Revisions Summary: IRAF Version 2.10
+.AU
+Francisco Valdes
+.AI
+IRAF Group - Central Computer Services
+.K2
+P.O. Box 26732, Tucson, Arizona 85726
+September 1990
+.AB
+This paper summarizes the changes in Version 3 of the IRAF \fBapextract\fR
+package which is part of IRAF Version 2.10. The major new features and
+changes are:
+
+.IP \(bu
+New techniques for cleaning and variance weighting extracted spectra
+.IP \(bu
+A new task, \fBapall\fR, which integrates all the parameters used for
+one dimensional extraction of spectra
+.IP \(bu
+A new extended output format for recording both weighted and unweighted
+extractions, subtracted background, and variance information.
+.IP \(bu
+Special featurers for automatically numbering and identifying large
+numbers of apertures.
+.IP \(bu
+New tasks and algorithms, \fBaprecenter\fR and \fBapresize\fR,
+for automatically recentering and resizing aperture definitions
+.IP \(bu
+A new task, \fBapflatten\fR, for creating flat fields from
+fiber and slitlet spectra
+.IP \(bu
+A new task, \fBapfit\fR, providing various types of fitting for
+two dimensional multiobject spectra.
+.IP \(bu
+A new task, \fBapmask\fR, for creating mask images from aperture definitions.
+.AE
+.NH
+Introduction
+.PP
+A new version of the IRAF \fBapextract\fR package has been completed.
+It is Version 3 and is part of IRAF Version 2.10. The package will
+be made available as an external package prior to the release of V2.10.
+This paper describes the changes and new features of the package. It
+does not describe them in detail. Full details of the algorithms,
+functions, and parameters are found in the task descriptions.
+Reference is made to the previous version so familiarity with that
+version is useful though not necessary. There were three goals for the
+new package: new and improved cleaning and variance weighting (optimal
+extraction) algorithms, the addition of recommended or desirable new
+tasks and algorithms (particularly to support large numbers of spectra
+from fiber and aperture mask instruments), and special support for the
+new image reduction scripts. Features relating to the last point are
+not discussed here.
+.PP
+Table 1 summarizes the major new features and changes in the package.
+
+.ce
+Table 1: Summary of Major New Features and Changes
+
+.IP \(bu
+New techniques for cleaning and variance weighting extracted spectra
+.IP \(bu
+A new task, \fBapall\fR, which integrates all the parameters used for
+one dimensional extraction of spectra
+.IP \(bu
+A new extended output format for recording both weighted and unweighted
+extractions, subtracted background, and variance information.
+.IP \(bu
+Special featurers for automatically numbering and identifying large
+numbers of apertures.
+.IP \(bu
+New tasks and algorithms, \fBaprecenter\fR and \fBapresize\fR, for
+automatically recentering and resizing aperture definitions
+.IP \(bu
+A new task, \fBapflatten\fR, for creating flat fields from fiber and slitlet
+spectra
+.IP \(bu
+A new task, \fBapfit\fR, providing various types of fitting for two dimensional
+multiobject spectra.
+.IP \(bu
+A new task, \fBapmask\fR, for creating mask images from aperture definitions.
+.NH
+Cleaned and Variance Weighted Extractions: apsum and apall
+.PP
+There are two types of aperture extraction (estimating the background
+subtracted flux across a fixed width aperture at each image line or
+column) just as in the previous version. One is a simple sum of pixel
+values across an aperture. In the previous version this was called
+"profile" weighting while in this version it is simply called
+unweighted or "none". The second type weights each pixel in the sum by
+its estimated variance based on a spectrum model and detector noise
+parameters. As before this type of extraction is selected by
+specifying "variance" for the weighting parameter.
+.PP
+Variance weighting is often called "optimal" extraction since it
+produces the best unbiased signal-to-noise estimate of the flux in the
+two dimensional profile. It also has the advantage that wider
+apertures may be used without penalty of added noise. The theory and
+application of this type of weighting has been described in several
+papers. The ones which were closely examined and used as a model for
+the algorithms in this software are \fIAn Optimal Extraction Algorithm
+for CCD Spectroscopy\fR, \fBPASP 98\fR, 609, 1986, by Keith Horne and
+\fIThe Extraction of Highly Distorted Spectra\fR, \fBPASP 100\fR, 1032,
+1989, by Tom Marsh.
+.PP
+The noise model for the image data used in the variance weighting,
+cleaning, and profile fitting consists of a constant gaussian noise and
+a photon count dependent poisson noise. The signal is related to the
+number of photons detected in a pixel by a gain parameter given
+as the number of photons per data number. The gaussian noise is given
+by a readout noise parameter which is a defined as a sigma in
+photons. The poisson noise is approximated as gaussian with sigma
+given by the number of photons. The method of specifying this noise
+model differs from the previous version in that the more common CCD
+detector parameters of readout noise and gain are used rather than the
+linear variance parameters "v0" and "v1".
+.PP
+Some additional effects which should be considered in principle, and
+which are possibly important in practice, are that the variance
+estimate should be based on the actual number of photons detected before
+correction for pixel sensitivity; i.e. before flat field correction.
+Furthermore the uncertainty in the flat field should also be included
+in the weighting. However, the profile must be determined free of
+sensitivity effects including rapid larger scale variations such as
+fringing. Thus, ideally one should input the unflat-fielded
+observation and the flat field data and carry out the extractions with
+the above points in mind. However, due to the complexity often
+involved in basic CCD reductions and special steps required for
+producing spectroscopic flat fields this level of sophistication is not
+provided by the current package.
+.PP
+The package does provide, however, for propagation of an approximate
+uncertainty in the background estimate when using background subtraction.
+If background subtraction is done, a background variance is computed
+using the poisson noise model based on the estimated background counts.
+Because the background estimate is based on a finite number of
+pixels, the poisson variance estimate is divided by the number (minus
+one) of pixels used in determining the background. The number of
+pixels used includes any box car smoothing. Thus, the larger the
+number of background pixels the smaller the background noise
+contribution to the variance weighting. This method is only
+approximate since no correction is made for the number of degrees of
+freedom and correlations when using the fitting method of background
+estimation.
+.PP
+If removal of cosmic rays and other deviant pixels is desired (called
+cleaning) they are iteratively rejected based on the estimated variance
+and excluded from the weighted sum. Unlike the previous version, a
+cleaned extraction is always variance weighted. This makes sense since
+the detector noise parameters must be specified and the spectrum
+profile computed, so all of the computational effort must be done
+anyway, and the variance weighting is as good or superior to a simple
+unweighted extraction.
+.PP
+The detection and removal of deviant pixels is straightforward. Based
+on the noise model, pixels deviating by more than a
+specified number of sigma (square root of the variance) above or below
+the model are removed from the weighted sum. A new spectrum estimate
+is made and the rejection is repeated. The rejections are made one at
+a time starting with the most deviant and up to half the pixels in the
+aperture may be rejected.
+.NH
+Spectrum Profile Determination: apsum, apall, apflatten, apfit
+.PP
+The foundation of variance weighted or optimal extraction, cosmic ray
+detection and removal, two dimensional flat field normalization, and
+spectrum fitting and modeling is the accurate determination of the
+spectrum profile across the dispersion as a function of wavelength.
+The previous version of the \fBapextract\fR package accomplished this by
+averaging a specified number of profiles in the vicinity of each
+wavelength after correcting for shifts in the center of the profile.
+This technique was sensitive to perturbations from cosmic rays
+and the exact choice of averaging parameters. The current version of
+the package uses a different algorithm, actually a combination of
+two algorithms, which is much more stable.
+.PP
+The basic idea is to normalize each profile along the dispersion to
+unit flux and then fit a low order function to sets of unsaturated
+points at nearly the same point in the profile parallel to the
+dispersion. The important point here is that points at the same
+distance from the profile center should have the nearly the same values
+once the continuum shape and spectral features have been divided out.
+Any variations are due to slow changes in the shape of the profile with
+wavelength, differences in the exact point on the profile, pixel
+binning or sampling, and noise. Except for the noise, the variations
+should be slow and a low order function smoothing over many points will
+minimize the noise and be relatively insensitive to bad pixels such as
+cosmic rays. Effects from bad pixels may be further eliminated by
+chi-squared iteration and clipping. Since there will be many points
+per degree of freedom in the fitting function the clipping may even be
+quite aggressive without significantly affecting the profile
+estimates. Effects from saturated pixels are minimized by excluding
+from the profile determination any profiles containing one or more
+saturated pixels.
+.PP
+The normalization is, in fact, the one dimensional spectrum. Initially
+this is the simple sum across the aperture which is then updated
+by the variance weighted sum with deviant pixels possibly removed.
+This updated one dimensional spectrum is what is meant by the
+profile normalization factor in the discussion below. The two dimensional
+spectrum model or estimate is the product of the normalization factor
+and the profile. This model is used for estimating
+the pixel intensities and, thence, the variances.
+.PP
+There are two important requirements that must be met by the profile fitting
+algorithm. First it is essential that the image data not be
+interpolated. Any interpolation introduces correlated errors and
+broadens cosmic rays to an extent that they may be confused with the
+spectrum profile, particularly when the profile is narrow. This was
+one of the problems limiting the shift and average method used
+previously. The second requirement is that data fit by the smoothing
+function vary slowly with wavelength. This is what precludes, for
+instance, fitting profile functions across the dispersion since narrow,
+marginally sampled profiles require a high order function using only a
+very few points. One exception to this, which is sometimes useful but
+of less generality, is methods which assume a model for the profile
+shape such as a gaussian. In the methods used here there is no
+assumption made about the underlying profile other than it vary
+smoothly with wavelength.
+.PP
+These requirements lead to two fitting algorithms based on how well the
+dispersion axis is aligned with the image columns or lines. When the
+spectra are well aligned with the image axes one dimensional functions
+are fit to the image columns or lines. Small excursions of a few
+pixels over the length of the spectrum can be adequately fit in this
+way. When the spectra become strongly tilted then single lines or
+columns may cross the actual profile relatively quickly causing the
+requirement of a slow variation to be violated. One thought is to use
+interpolation to fit points always at the same distance from the
+profile. This is ruled out by the problems introduced by image
+interpolation. However, there is a clever method which, in effect,
+fits low order polynomials parallel to the direction defined by tracing
+the spectrum but which does not interpolate the image data. Instead it
+weights and couples polynomial coefficients. This method was developed
+by Tom Marsh and is described in detail in the paper, \fIThe Extraction
+of Highly Distorted Spectra\fR, \fBPASP 101\fR, 1032, Nov. 1989. Here
+we refer to this method as the Marsh algorithm and do not attempt to
+explain it further.
+.PP
+Both fitting algorithms weight the pixels by their variance as computed
+from the background and background variance if background subtraction
+is specified, the spectrum estimate from the profile and the spectrum
+normalization, and the detector noise parameters. The noise model is
+that described earlier.
+.PP
+The profile fitting can be iterated to remove deviant pixels. This is
+done by rejecting pixels greater than a specified number of sigmas
+above or below the expected value based on the profile, the
+normalization factor, the background, the detector noise parameters,
+and the overall chi square of the residuals. Rejected points are
+removed from the profile normalization and from the fits.
+.NH
+New Extraction Task: apall
+.PP
+All of the functions of the \fBapextract\fR package are actually part
+of one master program. The organization of the package into tasks by
+function with parameters to allow selection of some of the other
+functions, for example the aperture editor may be entered from
+virtually every task, was done to highlight the logic and organize the
+parameters into small sets. However, there was often confusion about
+which parameters were being used and the need to set parameters in one
+task, say \fBaptrace\fR, in order to use the trace option in another
+task, say \fBapsum\fR. In practice, for the most common function of
+extraction of two dimensional spectra to one dimension most users end up
+using \fBapsum\fR for all the functions.
+.PP
+In the new version, the old organization is retained (with the addition
+of new functions and some changes in parameters) but a new task,
+\fBapall\fR, is also available. This task contains all of the
+parameters needed for extraction with a parameter organization which is
+nicely formated for use with \fBeparam\fR. The parameters in
+\fBapall\fR are independent of the those in the other tasks. It is
+expected that many, if not most users will opt to use this task for
+spectrum extraction in preference to the individual functions.
+.PP
+The organization by function is still used in the documentation. This
+is still the best way to organize the descriptions of the various
+algorithms and parameters. As an example, the profile tracing algorithm
+is described in most detail under the topic \fBaptrace\fR.
+.NH
+Extraction Output Formats: apsum and apall
+.PP
+The extracted spectra are recorded in one, two, or three dimensional
+images depending on the \fIformat\fR and \fIextras\fR parameters. If
+the \fIextras\fR parameter is selected the formats are three
+dimensional with each plane in the third dimension containing
+associated information for the spectra in the first plane. This
+information includes the unweighted spectrum and a sigma spectrum
+(estimated from the variances and weights of the pixels extracted) when
+using variance weighting, and the background spectrum when background
+subtraction is used. When \fIextras\fR is not selected only the
+extracted spectra are output.
+.PP
+The formats are basically the same as in the previous version;
+onedspec, multispec, and echelle. In addition, the function of the
+task \fBapstrip\fR in the previous version has been transferred to the
+extraction tasks by simply specifying "strip" for the format.
+.PP
+There are some additions to the header parameters in multispec and
+echelle format. Two additional fields have been added to the
+aperture number parameter giving the aperture limits (at the reference
+dispersion point). Besides being informative it may be used for
+interpolating dispersion solutions spatially. A second, optional keyword per
+spectrum has been added to contain a title. This is useful for
+multiobject spectra.
+.NH
+Easier and Extended Aperture Identifications: apfind and apedit
+.PP
+When dealing with a large number of apertures, such as occur with
+multifiber and multiaperture data, the burden of making and maintaining
+useful aperture identifications becomes large. Several very useful
+improvements were made in this area. These improvements generally
+apply equally to aperture identifications made by the automated
+\fBapfind\fR algorithm and those made interactively using
+\fBapedit\fR. In the simplest usage of defining apertures
+interactively or with the aperture finding algorithm, aperture numbers
+are assigned sequentially beginning with 1. In the new version the
+parameter "order" allows the direction of increasing aperture numbers
+with respect to the direction of increasing pixel coordinate (either
+column or line) to be set. An "increasing" order parameter value
+numbers the apertures from left to right (the direction naturally
+plotted) in the same sense as the pixel coordinates. A "decreasing"
+order reverses this sense.
+.PP
+Some instruments, particularly multifiber instruments, produce nearly
+equally spaced spectra for which one wants to maintain a consistent
+numbering sequence. However, at times some spectra may be missing
+due to broken or unassigned fibers and one would like to skip an
+aperture identification number to maintain the same fiber assignments.
+To do this automatically, a new parameter called \fImaxsep\fR has been
+added. This parameter defines the maximum separation between two
+apertures beyond which a jump in the aperture sequence is made. In
+other words the sequence increment is given by rounding down the
+separation divided by this parameter. How accurately this value has
+to be specified depends on how large the gaps may be and the natural
+variability in the aperture positions. In conjunction with the
+minimum separation parameter this algorithm works quite well in
+accounting for missing spectra.
+.PP
+One flaw in this scheme is when the first spectrum is missing causing
+the identifications will be off. In this case the modified interactive
+aperture editing command 'o' asks for the aperture identification
+number of the aperture pointed at by the cursor and then automatically
+renumbers the other apertures relative to that aperture. The other
+possible flaw is identification of noise as a spetrum but this is
+controlled by the \fIthreshold\fR parameter and, provided the actual
+number of spectra is known, say by counting off a graph, then the
+\fInfind\fR parameter generally limits this type of problem.
+.PP
+A new attribute of an aperture is a title. If present this title
+is propagated through the extraction into the image headers. The title
+may be set interactively but normally the titles are supplied in
+another new feature, an "aperture identification" file specified by
+the parameter \fIapidtable\fR. This file provides
+the most flexibility in making aperture identification assignments.
+The file consists of lines with three fields, a unique aperture number,
+a beam or aperture type number which may be repeated, and the
+aperture title. The aperture identification lines from the file are
+assigned sequentially in the same order as would be done if using
+the default indexing including skipping of missing spectra based on
+the maximum separation.
+.PP
+By default the beam number is the same as the aperture number. When
+using an aperture identification file the beam number can be used
+to assign spectrum types which other software may use. For example,
+some of the specialized fiber reduction packages use the beam number
+to identify sky fibers and embedded arc fibers.
+.NH
+New Aperture Recentering Task: aprecenter
+.PP
+An automated recentering algorithm has been added. It may be called
+through the new \fBaprecenter\fR command, from any of the tasks containing
+the \fIrecenter\fR parameter, or from the aperture editor. The purpose of
+this new feature is to allow automatically adjusting the aperture
+centers to follow small changes in the positions of spectra expected to be at
+essentially the same position, such as with fiber fed spectrographs.
+This does not change the shape of the trace but simply adds a shift
+across the dispersion axis.
+.PP
+Typically, one uses a strong image to define reference apertures and
+then for subsequent objects uses the reference positions with a
+recentering to correct for flexure effects. However, it may be
+inappropriate to base a new center on weak spectra or to have multiple
+spectra recentered independently. The recentering options provide for
+selecting specific apertures to be recentered, selecting only a
+fraction of the strongest (highest peak data level) spectra and
+averaging the shifts determined (possible from only a subset of the
+spectra) and applying the average shift to all the apertures.
+Note that one may still specify the dispersion line and number of
+dispersion lines to sum in order to improve the signal for centering.
+.NH
+New Aperture Resizing Task: apresize
+.PP
+An automated resizing algorithm has been added. It may be called
+through the new \fBapresize\fR command, from any of the tasks
+containing the \fIresize\fR parameter, or from the aperture editor with
+the new key 'z' (the y cursor level command is still available with the
+'y' key). The purpose of this new feature is to allow automatically
+adjusting the aperture widths to follow changes in seeing and to
+provide a greater variety of global aperture sizing methods.
+.PP
+In all the methods the aperture limits are set at the pixel positions
+relative to the center which intersect the linearly interpolated data
+at some data value. The methods differ in how the data level is
+determined. The methods are:
+
+.IP \(bu
+Set size at a specified absolute data level
+.IP \(bu
+Set size at a specified data level above a background
+.IP \(bu
+Set size at a specified fraction of the peak pixel value
+.IP \(bu
+Set size at a specified fraction of the peak pixel value above a background
+.LP
+The automatic background is quite simple; a line connecting the first
+local minima from the aperture center.
+.PP
+The limits determined by one of the above methods may be further
+adjusted. The limits may be increased or decreased by a specified
+fraction. This allows setting wider limits based on more accurately
+determined limits from the stronger part of the profile; for example
+doubling the limits obtained from the half intensity point. A maximum
+extent may be imposed. Finally, if there is more than one aperture and one
+wants to maintain the same aperture size, the apertures sizes
+determined individually may be averaged and substituted for all the
+apertures.
+.NH
+New Aperture Mask Output: apmask
+.PP
+A new task, \fBapmask\fR, has been added to produce a mask file/image
+of 1's and 0's defined by the aperture definitions. This is based on
+the new IRAF mask facilities. The output is a compact binary file
+which may be used directly as an image in most applications. In
+particular the mask file can be used with tasks such as \fBimarith\fR,
+\fBimreplace\fR, and \fBdisplay\fR. Because the mask facility is new,
+there is little that can be done with masks other than using it as an
+image. However, eventually many tasks will be able to use mask
+images. The aperture mask will be particularly well suited to work
+with \fBimsurfit\fR for fitting a surface to the data outside the apertures.
+This would be an alternative for scattered light modeling to the
+\fBapscatter\fR tasks.
+.NH
+Aperture Flat Fields and Normalization: apflatten and apnormalize
+.PP
+Slitlet, echelle, and fiber spectra have the characteristic that the
+signal falls off to near zero values outside regions of the image
+containing spectra. Also fiber profiles are usually undersampled
+causing problems with gradients across the pixels. Directly dividing
+by a flat field produces high noise (if not division by zero) where the
+signal is low, introduces the spectrum of the flat field light, and
+changes the profile shape.
+.PP
+One method for modifying the flat field to avoid these problems is
+provided by the task \fBimred.generic.flat1d\fR. However, this task
+does not use any knowledge of where the spectra are. There are two
+tasks in the \fBapextract\fR package which can be used to modify flat
+field images. \fBapnormalize\fR is not new. It divides the spectra
+within specified apertures by a one dimensional spectrum, either a
+constant for simple throughput normalization or some smoothed version
+of the spectrum in the aperture to remove the spectral shape. Pixels
+outside specified apertures are set to unity to avoid division
+effects. This task has the effect of preserving the profile shape in
+the flat field which may be desired for attempts to remove slit
+profiles.
+.PP
+Retaining the profile shape of the flat field can give very bad edge
+effects, however, if there is image flexure. A new task similar to
+\fBflat1d\fR but which uses aperture information is \fBapflatten\fR.
+It uses the spectrum profile model described earlier. For nearly image
+axes aligned spectra this amounts very nearly to the line or column
+fitting of \fBflat1d\fR. As with \fBapnormalize\fR there is an option
+to fit the one dimensional spectrum to remove the large scale shape of
+the spectrum while preserving small scale sensitivity variations. The
+smoothed spectrum is multiplied by the normalized profile and divided
+into the data in each aperture. Pixels outside the aperture are set to
+1. Pixels with model values below a threshold are also set to 1. This
+produces output images which have the small scale sensitivity
+variations, a normalized mean, and the spectrum profile removed.
+.NH
+Two Dimensional Spectrum Fitting: apfit
+.PP
+The profile and spectrum fitting used for cleaning and variance
+weighted extraction may be used and output in the new task
+\fBapfit\fR. The task \fBapfit\fR is similar in structure to
+\fBfit1d\fR. One may output the fit, difference, or ratio. The fit
+may be used to examine the spectrum model used for the cleaning and
+variance weighted extraction. The difference and ratio may used to
+display small variations and any deviant pixels. While specific uses
+are not given this task will probably be used in interesting ways not
+anticipated by the author.
+.NH
+I/O and Dispersion Axis Parameters: apextract and apio
+.PP
+The general parameters, primarily concerning input and output devices
+and files, were previously in the parameter set \fBapio\fR. This "pset"
+task has been removed and those parameters are now found as part of
+the package parameters, i.e. \fBapextract\fR. There is one new parameter
+in the \fBapextract\fR package parameters, dispaxis. In the previous
+version of the package one needed to run the task \fBsetdisp\fR to insert
+information in the image header identifying the dispersion direction
+of the spectra in the image. Often people would forget this step
+and receive an error message to that effect. The new parameter
+allows skipping this step. If the DISPAXIS image header parameter
+is missing the package parameter value is inserted into the image
+header as part of the processing. Note that if the parameter is
+present in the image header either because \fBsetdisp\fR was used or the
+image creation process inserted it (a future ideal case) then that
+value is used in preference to the package parameter.
+.NH
+Strip Extraction: apstrip
+.PP
+The task \fBapstrip\fR from the previous version has been removed.
+However, it is possible to obtain two dimensional strips aligned with
+the image axes by specifying a format of "strip" when using \fBapsum\fR
+or \fBapall\fR. While the author doesn't anticipate a good scientific
+use for this feature others may find it useful.
diff --git a/noao/twodspec/apextract/mkpkg b/noao/twodspec/apextract/mkpkg
new file mode 100644
index 00000000..bcc342c4
--- /dev/null
+++ b/noao/twodspec/apextract/mkpkg
@@ -0,0 +1,76 @@
+# APEXTRACT
+
+$call relink
+$exit
+
+update:
+ $call relink
+ $call install
+ ;
+
+relink:
+ $update libpkg.a
+ $call apextract
+ ;
+
+install:
+ $move xx_apextract.e noaobin$x_apextract.e
+ ;
+
+apextract:
+ $omake x_apextract.x
+ $link x_apextract.o libpkg.a -lxtools\
+ -lcurfit -liminterp -lllsq -o xx_apextract.e
+ ;
+
+libpkg.a:
+ apalloc.x apertures.h
+ apanswer.x
+ apcenter.x <pkg/center1d.h>
+ apcolon.x apertures.h <error.h> <gset.h> <imhdr.h>
+ apcopy.x apertures.h
+ apcveval.x <math/curfit.h>
+ apcvset.x apertures.h <math/curfit.h>
+ apdb.x apertures.h <math/curfit.h> <pkg/dttext.h>
+ apdefault.x apertures.h <imhdr.h>
+ apdelete.x
+ apedit.x apertures.h <gset.h> <imhdr.h> <mach.h> <pkg/gtools.h>
+ apextract.x apertures.h <error.h> <imhdr.h> <mach.h>\
+ <math/iminterp.h> <pkg/gtools.h>
+ apfind.x apertures.h <imhdr.h> <mach.h>
+ apfindnew.x apertures.h <mach.h>
+ apfit.x apertures.h <imhdr.h> <imset.h> <pkg/gtools.h>
+ apgetdata.x <imhdr.h>
+ apgetim.x
+ apgmark.x apertures.h <pkg/rg.h>
+ apgraph.x apertures.h <pkg/gtools.h>
+ apgscur.x apertures.h
+ apicset.x apertures.h <imhdr.h>
+ apids.x apertures.h <error.h> <mach.h>
+ apimmap.x <imhdr.h>
+ apinfo.x apertures.h
+ apio.x <time.h>
+ apmask.x apertures.h <imhdr.h> <pmset.h>
+ apmw.x <error.h> <imhdr.h> <imio.h> <mwset.h>
+ apnearest.x apertures.h <mach.h>
+ apnoise.x apertures.h <gset.h> <pkg/gtools.h>
+ apparams.x
+ appars.x <math/iminterp.h>
+ apprint.x apertures.h
+ approfile.x apertures.h <gset.h> <mach.h> <math/curfit.h>
+ aprecenter.x apertures.h
+ apresize.x apertures.h
+ apscatter.x apertures.h <error.h> <imhdr.h> <imset.h> <pkg/gtools.h>
+ apselect.x apertures.h
+ apshow.x apertures.h
+ apskyeval.x apertures.h <math/iminterp.h> <mach.h>
+ apsort.x apertures.h
+ aptrace.x apertures.h <imhdr.h> <math/curfit.h> <pkg/center1d.h>\
+ <pkg/gtools.h>
+ apupdate.x apertures.h <gset.h>
+ apvalues.x apertures.h
+ apvariance.x apertures.h <gset.h>
+ apylevel.x
+ peaks.x
+ t_apall.x apertures.h <error.h> <imhdr.h> <pkg/gtools.h>
+ ;
diff --git a/noao/twodspec/apextract/peaks.x b/noao/twodspec/apextract/peaks.x
new file mode 100644
index 00000000..fe525f88
--- /dev/null
+++ b/noao/twodspec/apextract/peaks.x
@@ -0,0 +1,313 @@
+# PEAKS -- The following procedures are general numerical functions
+# dealing with finding peaks in a data array.
+#
+# FIND_PEAKS Find additional peaks in the data array.
+# FIND_LOCAL_MAXIMA Find the local maxima in the data array.
+# IS_LOCAL_MAX Test a point to determine if it is a local maximum.
+# FIND_CONTRAST Find the peaks satisfying the contrast constraint.
+# FIND_ISOLATED Flag peaks which are within separation of a peak
+# with a higher peak value.
+# FIND_NMAX Select up to the nmax highest ranked peaks.
+# COMPARE Compare procedure for sort used in FIND_PEAKS.
+
+# FIND_PEAKS -- Find the peaks in the data array.
+#
+# The peaks are found using the following algorithm:
+#
+# 1. Find the local maxima which are not near the edge of existing peaks.
+# 2. Reject those below the absolute threshold.
+# 3. Reject those below the contrast threshold.
+# 4. Determine the ranks of the remaining peaks.
+# 5. Flag weaker peaks within separation of a stronger peak.
+# 6. Add strongest peaks to the peaks array.
+#
+# Indefinite data points are ignored.
+
+procedure find_peaks (data, npts, contrast, edge, nmax, separation, threshold,
+ peaks, npeaks)
+
+real data[npts] # Input data array
+int npts # Number of data points
+
+real contrast # Maximum contrast between strongest and weakest
+int edge # Minimum distance from the edge
+int nmax # Maximum number of peaks to be returned
+real separation # Minimum separation between peaks
+real threshold # Minimum threshold level for peaks
+
+real peaks[nmax] # Positons of input peaks / output peaks
+int npeaks # Number of input peaks / number of output peaks
+
+int i, nx
+pointer sp, x, y, rank
+
+int compare()
+extern compare()
+
+common /sort/ y
+
+begin
+ if (npeaks >= nmax)
+ return
+
+ call smark (sp)
+ call salloc (x, npts, TY_INT)
+ call salloc (y, npts, TY_REAL)
+
+ # Find the positions of the local maxima.
+ call find_local_maxima (data, npts, peaks, npeaks, edge, separation,
+ threshold, Memi[x], Memr[y], nx)
+
+ # Eliminate points not satisfying the contrast constraint.
+ call find_contrast (data, Memi[x], Memr[y], nx, contrast)
+
+ # Rank the peaks by peak value.
+ call salloc (rank, nx, TY_INT)
+ for (i = 1; i <= nx; i = i + 1)
+ Memi[rank + i - 1] = i
+ call qsort (Memi[rank], nx, compare)
+
+ # Reject weaker peaks within a specified separation of a stronger peak.
+ call find_isolated (Memi[x], Memi[rank], nx, separation)
+
+ # Add the strongest peaks.
+ call find_nmax (Memi[x], Memi[rank], nx, nmax, peaks, npeaks)
+
+ call sfree (sp)
+end
+
+
+# FIND_LOCAL_MAXIMA -- Find the local maxima in the data array.
+
+procedure find_local_maxima (data, npts, peaks, npeaks, edge, separation,
+ threshold, x, y, nx)
+
+real data[npts] # Input data array
+int npts # Number of input points
+real peaks[ARB] # Positions of peaks
+int npeaks # Number of peaks
+int edge # Edge buffer distance
+real separation # Minimum separation from peaks
+real threshold # Data threshold
+int x[npts] # Output positions
+real y[npts] # Output data values
+int nx # Number of maxima
+
+int i, j
+
+bool is_local_max()
+
+begin
+ # Find the local maxima above the threshold and not near the edge.
+ nx = 0
+ for (i = edge + 1; i <= npts - edge; i = i + 1) {
+ if ((data[i] >= threshold) && (is_local_max (i, data, npts))) {
+ nx = nx + 1
+ x[nx] = i
+ }
+ }
+
+ # Flag maxima within separation of previous peaks.
+ for (j = 1; j <= npeaks; j = j + 1) {
+ for (i = 1; i <= nx; i = i + 1) {
+ if (IS_INDEFI (x[i]))
+ next
+ if (x[i] < peaks[j] - separation)
+ next
+ if (x[i] > peaks[j] + separation)
+ break
+ x[i] = INDEFI
+ }
+ }
+
+ # Eliminate flagged maxima and set y values.
+ j = 0
+ for (i = 1; i <= nx; i = i + 1) {
+ if (!IS_INDEFI (x[i])) {
+ j = j + 1
+ x[j] = x[i]
+ y[j] = data[x[j]]
+ }
+ }
+
+ nx = j
+end
+
+
+# IS_LOCAL_MAX -- Test a point to determine if it is a local maximum.
+#
+# Indefinite points are ignored.
+
+bool procedure is_local_max (index, data, npts)
+
+# Procedure parameters:
+int index # Index to test for local maximum
+real data[npts] # Data values
+int npts # Number of points in the data vector
+
+int i, j, nright, nleft
+
+begin
+ # INDEFR points cannot be local maxima.
+ if (IS_INDEFR (data[index]))
+ return (false)
+
+ # Find the left and right indices where data values change and the
+ # number of points with the same value. Ignore INDEFR points.
+ nleft = 0
+ for (i = index - 1; i >= 1; i = i - 1) {
+ if (!IS_INDEFR (data[i])) {
+ if (data[i] != data[index])
+ break
+ nleft = nleft + 1
+ }
+ }
+ nright = 0
+ for (j = index + 1; i <= npts; j = j + 1) {
+ if (!IS_INDEFR (data[j])) {
+ if (data[j] != data[index])
+ break
+ nright = nright + 1
+ }
+ }
+
+ # Test for failure to be a local maxima
+ if ((i == 0) && (j == npts)) {
+ return (FALSE) # Data is constant
+ } else if (i == 0) {
+ if (data[j] > data[index])
+ return (FALSE) # Data increases to right
+ } else if (j == npts) {
+ if (data[i] > data[index]) # Data increase to left
+ return (FALSE)
+ } else if ((data[i] > data[index]) || (data[j] > data[index])) {
+ return (FALSE) # Not a local maximum
+ } else if (!((nleft - nright == 0) || (nleft - nright == 1))) {
+ return (FALSE) # Not center of plateau
+ }
+
+ # Point is a local maxima
+ return (TRUE)
+end
+
+
+
+# FIND_CONTRAST -- Find the peaks with positions satisfying contrast constraint.
+
+procedure find_contrast (data, x, y, nx, contrast)
+
+real data[ARB] # Input data values
+int x[ARB] # Input/Output peak positions
+real y[ARB] # Output peak data values
+int nx # Number of peaks input
+real contrast # Contrast constraint
+
+int i, j
+real minval, maxval, threshold
+
+begin
+ if ((nx == 0.) || (contrast <= 0.))
+ return
+
+ call alimr (y, nx, minval, maxval)
+ threshold = contrast * maxval
+
+ j = 0
+ do i = 1, nx {
+ if (y[i] < threshold) {
+ j = j + 1
+ x[j] = x[i]
+ y[j] = y[i]
+ }
+ }
+
+ nx = j
+end
+
+# FIND_ISOLATED -- Flag peaks which are within separation of a peak
+# with a higher peak value.
+#
+# The peak positions, x, and their ranks, rank, are input.
+# The rank array contains the indices of the peak positions in order from
+# the highest peak value to the lowest peak value. Starting with
+# highest rank (rank[1]) all peaks of lower rank within separation
+# are marked by setting their positions to INDEFI.
+
+procedure find_isolated (x, rank, nx, separation)
+
+int x[ARB] # Positions of points
+int rank[ARB] # Rank of peaks
+int nx # Number of peaks
+real separation # Minimum allowed separation
+
+int i, j
+
+begin
+ if ((nx == 0) || (separation <= 0.))
+ return
+
+ # Eliminate close neighbors. The eliminated
+ # peaks are marked by setting their positions to INDEFI.
+
+ for (i = 1; i < nx; i = i + 1) {
+ if (IS_INDEFI (x[rank[i]]))
+ next
+ for (j = i + 1; j <= nx; j = j + 1) {
+ if (IS_INDEFI (x[rank[j]]))
+ next
+ if (abs (x[rank[i]] - x[rank[j]]) < separation)
+ x[rank[j]] = INDEFI
+ }
+ }
+end
+
+
+# FIND_NMAX -- Select up to the nmax highest ranked peaks.
+
+procedure find_nmax (x, rank, nx, nmax, peaks, npeaks)
+
+int x[ARB] # Peak positions
+int rank[ARB] # Ranks of peaks
+int nx # Number of input / output peaks
+int nmax # Max number of peaks to be selected
+real peaks[nmax] # Output peak position array
+int npeaks # Output number of peaks
+
+int i
+
+begin
+ for (i = 1; (i <= nx) && (npeaks < nmax); i = i + 1) {
+ if (IS_INDEFI (x[rank[i]]))
+ next
+ npeaks = npeaks + 1
+ peaks[npeaks] = x[rank[i]]
+ }
+end
+
+
+# COMPARE -- Compare procedure for sort used in FIND_PEAKS.
+# Larger values are indexed first. INDEFR values are indexed last.
+
+int procedure compare (index1, index2)
+
+# Procedure parameters:
+int index1 # Comparison index
+int index2 # Comparison index
+
+pointer y
+
+common /sort/ y
+
+begin
+ # INDEFR points are considered to be smallest possible values.
+ if (IS_INDEFR (Memr[y - 1 + index1]))
+ return (1)
+ else if (IS_INDEFR (Memr[y - 1 + index2]))
+ return (-1)
+ else if (Memr[y - 1 + index1] < Memr[y - 1 + index2])
+ return (1)
+ else if (Memr[y - 1 + index1] > Memr[y - 1 + index2])
+ return (-1)
+ else
+ return (0)
+end
diff --git a/noao/twodspec/apextract/t_apall.x b/noao/twodspec/apextract/t_apall.x
new file mode 100644
index 00000000..415066ba
--- /dev/null
+++ b/noao/twodspec/apextract/t_apall.x
@@ -0,0 +1,576 @@
+include <imhdr.h>
+include <error.h>
+include <pkg/gtools.h>
+include "apertures.h"
+
+define APFIND 1
+define APRECENTER 2
+define APRESIZE 3
+define APEDIT 4
+define APTRACE 5
+define APSUM 6
+define APNORM 7
+define APSCAT 8
+define APALL 9
+define APFIT 10
+define APFLAT 11
+define APMASK 12
+define APSCRIPT 13
+define APSLITPROC 14
+define APNOISE 15
+
+
+# APEXTRACT TASK ENTRY POINTS
+#
+# The entry point for each task selects the operations to be performed
+# and initializes the pset to be used for the algorithm parameters.
+
+procedure t_apfind ()
+begin
+ call apall (APFIND)
+end
+
+procedure t_aprecenter ()
+begin
+ call apall (APRECENTER)
+end
+
+procedure t_apresize ()
+begin
+ call apall (APRESIZE)
+end
+
+procedure t_apedit ()
+begin
+ call apall (APEDIT)
+end
+
+procedure t_aptrace ()
+begin
+ call apall (APTRACE)
+end
+
+procedure t_apsum ()
+begin
+ call apall (APSUM)
+end
+
+procedure t_apnorm ()
+begin
+ call apall (APNORM)
+end
+
+procedure t_apscatter ()
+begin
+ call apall (APSCAT)
+end
+
+procedure t_apall ()
+begin
+ call apall (APALL)
+end
+
+procedure t_apflat ()
+begin
+ call apall (APFLAT)
+end
+
+procedure t_apfit ()
+begin
+ call apall (APFIT)
+end
+
+procedure t_apmask ()
+begin
+ call apall (APMASK)
+end
+
+procedure t_apscript ()
+begin
+ call apall (APSCRIPT)
+end
+
+procedure t_apslitproc ()
+begin
+ call apall (APSLITPROC)
+end
+
+procedure t_apnoise ()
+begin
+ call apall (APNOISE)
+end
+
+
+# APALL -- Master aperture definition and extraction procedure.
+
+procedure apall (ltask)
+
+int ltask # Logical task
+
+bool find # Find apertures?
+bool recenter # Recenter apertures?
+bool resize # Resize apertures?
+bool edit # Edit apertures?
+bool trace # Trace apertures?
+bool extract # Extract apertures?
+bool fit # Extract fit?
+bool norm # Normalize spectra?
+bool flat # Flatten spectra?
+bool scat # Subtract scattered light?
+bool mask # Aperture mask?
+bool noise # Noise calculation?
+
+int input # List of input spectra
+int refs # List of reference spectra
+int out # List of output spectra
+pointer format # Output format or fit type
+int scatout # List of scattered light images
+int profs # List of profile spectra
+int line # Dispersion line
+int nsum # Lines to sum
+
+pointer aps # Pointer to array of aperture pointers
+int naps # Number of apertures
+
+char nullstr[1]
+int i
+pointer sp, image, output, reference, profiles, str, str1
+
+bool clgetb(), apgetb(), streq(), ap_answer(), apgans(), apgansb()
+int imtopenp(), clgeti(), ap_getim(), ap_dbaccess(), strncmp()
+
+errchk ap_dbacess, ap_dbread, ap_find, ap_recenter, ap_resize, ap_edit
+errchk ap_trace, ap_plot, ap_extract, ap_scatter, ap_mask, ap_dbwrite
+
+data nullstr /0,0/
+
+begin
+ # Allocate memory for the apertures, filenames, and strings.
+ call smark (sp)
+ call salloc (image, SZ_FNAME, TY_CHAR)
+ call salloc (output, SZ_FNAME, TY_CHAR)
+ call salloc (reference, SZ_FNAME, TY_CHAR)
+ call salloc (format, SZ_LINE, TY_CHAR)
+ call salloc (profiles, SZ_FNAME, TY_CHAR)
+ call salloc (str, SZ_LINE, TY_CHAR)
+ call salloc (str1, SZ_LINE, TY_CHAR)
+
+ switch (ltask) {
+ case APALL:
+ call apopset ("apall1")
+ case APFIT:
+ call apopset ("apfit1")
+ case APFLAT:
+ call apopset ("apflat1")
+ case APNORM:
+ call apopset ("apnorm1")
+ case APSCRIPT:
+ call apopset ("apscript")
+ case APSLITPROC:
+ call apopset ("apslitproc")
+ case APNOISE:
+ call apopset ("apnoise1")
+ default:
+ call apopset ("apparams")
+ }
+
+ input = imtopenp ("input")
+ refs = imtopenp ("references")
+ line = clgeti ("line")
+ nsum = clgeti ("nsum")
+ out = NULL
+ profs = NULL
+ scatout = NULL
+
+ switch (ltask) {
+ case APSUM, APALL, APFIT, APNORM, APFLAT, APSCAT,
+ APMASK, APSCRIPT, APSLITPROC:
+ out = imtopenp ("output")
+ }
+
+ switch (ltask) {
+ case APSUM, APALL:
+ profs = imtopenp ("profiles")
+ call apgstr ("format", Memc[format], SZ_LINE)
+ case APFIT:
+ call clgstr ("fittype", Memc[format], SZ_LINE)
+ case APNORM:
+ call strcpy ("normalize", Memc[format], SZ_LINE)
+ case APFLAT:
+ call strcpy ("flatten", Memc[format], SZ_LINE)
+ case APSCAT:
+ scatout = imtopenp ("scatter")
+ case APSCRIPT, APSLITPROC:
+ scatout = imtopenp ("scatter")
+ profs = imtopenp ("profiles")
+ call apgstr ("format", Memc[format], SZ_LINE)
+ case APNOISE:
+ call strcpy ("noise", Memc[format], SZ_LINE)
+ }
+
+ trace = false
+ extract = false
+ fit = false
+ norm = false
+ flat = false
+ scat = false
+ mask = false
+ noise = false
+
+ if (apgetb ("initialize")) {
+ find = clgetb ("find")
+ recenter = clgetb ("recenter")
+ resize = clgetb ("resize")
+ edit = clgetb ("edit")
+
+ switch (ltask) {
+ case APTRACE, APSUM, APALL, APFIT, APNORM,
+ APFLAT, APSCAT, APMASK, APSCRIPT, APSLITPROC, APNOISE:
+ trace = clgetb ("trace")
+ }
+
+ switch (ltask) {
+ case APSUM, APALL:
+ extract = clgetb ("extract")
+ case APFIT:
+ fit = clgetb ("fit")
+ case APNORM:
+ norm = clgetb ("normalize")
+ case APFLAT:
+ flat = clgetb ("flatten")
+ case APSCAT:
+ scat = clgetb ("subtract")
+ case APMASK:
+ mask = clgetb ("mask")
+ case APSCRIPT, APSLITPROC:
+ extract = clgetb ("extract")
+ scat = clgetb ("subtract")
+ if (extract && scat)
+ call error (1,
+ "APSCRIPT: Can't combine scattered light and extraction")
+ case APNOISE:
+ noise = true
+ }
+
+ call ap_init (find, recenter, resize, edit, trace, extract, fit,
+ norm, flat, scat, mask, noise)
+ } else {
+ find = apgans ("ansfind")
+ recenter = apgans ("ansrecenter")
+ resize = apgans ("ansresize")
+ edit = apgans ("ansedit")
+
+ switch (ltask) {
+ case APTRACE, APSUM, APALL, APFIT, APNORM,
+ APFLAT, APSCAT, APMASK, APSCRIPT, APSLITPROC, APNOISE:
+ trace = apgans ("anstrace")
+ }
+
+ switch (ltask) {
+ case APSUM, APALL:
+ extract = apgans ("ansextract")
+ case APFIT:
+ fit = apgans ("ansfit")
+ case APNORM:
+ norm = apgans ("ansnorm")
+ case APFLAT:
+ flat = apgans ("ansflat")
+ case APSCAT:
+ scat = apgans ("ansscat")
+ case APMASK:
+ mask = apgans ("ansmask")
+ case APSCRIPT, APSLITPROC:
+ extract = apgans ("ansextract")
+ scat = apgans ("ansscat")
+ if (extract && scat)
+ call error (1,
+ "APSCRIPT: Can't combine scattered light and extraction")
+ }
+ }
+
+ # Initialize the apertures.
+ naps = 0
+ Memc[reference] = EOS
+ Memc[profiles] = EOS
+ call malloc (aps, 100, TY_POINTER)
+
+ # Process the apertures from each input image.
+ while (ap_getim (input, Memc[image], SZ_FNAME) != EOF) {
+ if (ap_getim (refs, Memc[str], SZ_LINE) != EOF)
+ call strcpy (Memc[str], Memc[reference], SZ_FNAME)
+ if (extract || fit || flat || norm || scat || mask)
+ if (ap_getim (out, Memc[output], SZ_FNAME) == EOF)
+ Memc[output] = EOS
+
+ # Get apertures.
+ call appstr ("ansdbwrite1", "no")
+ if (streq (Memc[reference], nullstr) ||
+ streq (Memc[reference], Memc[image])) {
+ if (clgetb ("verbose"))
+ call printf ("Searching aperture database ...\n")
+ iferr (call ap_dbread (Memc[image], aps, naps))
+ ;
+ } else if (streq (Memc[reference], "OLD")) {
+ iferr (call ap_dbread (Memc[image], aps, naps))
+ next
+ } else {
+ if (strncmp (Memc[reference], "NEW", 3) == 0) {
+ if (ap_dbaccess (Memc[image]) == YES)
+ next
+ call strcpy (Memc[reference+3], Memc[reference], SZ_FNAME)
+ }
+ if (clgetb ("verbose"))
+ call printf ("Searching aperture database ...\n")
+ iferr (call ap_dbread (Memc[reference], aps, naps)) {
+ call eprintf (
+ "WARNING: Reference image (%s) apertures not found\n")
+ call pargstr (Memc[reference])
+ next
+ }
+ if (naps > 0)
+ call appstr ("ansdbwrite1", "yes")
+ }
+ call clgstr ("apertures", Memc[str], SZ_LINE)
+ call ap_select (Memc[str], Memi[aps], naps)
+
+ iferr {
+ # Find apertures.
+ if (find && naps == 0)
+ call ap_find (Memc[image], line, nsum, aps, naps)
+
+ # Recenter apertures.
+ else if (recenter)
+ call ap_recenter (Memc[image], line, nsum, Memi[aps], naps,
+ NO)
+
+ # Resize apertures.
+ if (resize)
+ call ap_resize (Memc[image], line, nsum, Memi[aps], naps,
+ NO)
+
+ # Edit apertures.
+ if (edit)
+ call ap_edit (Memc[image], line, nsum, aps, naps)
+
+ # Trace apertures.
+ if (trace)
+ call ap_trace (Memc[image], line, Memi[aps], naps, NO)
+
+ # Write database and make aperture plot.
+ if (apgansb ("ansdbwrite1")) {
+ call clgstr ("database", Memc[str1], SZ_LINE)
+ call sprintf (Memc[str], SZ_LINE,
+ "Write apertures for %s to %s")
+ call pargstr (Memc[image])
+ call pargstr (Memc[str1])
+ if (ap_answer ("ansdbwrite", Memc[str]))
+ call ap_dbwrite (Memc[image], aps, naps)
+ }
+ iferr (call ap_dbwrite ("last", aps, naps))
+ ;
+ iferr (call ap_plot (Memc[image], line, nsum, Memi[aps], naps))
+ call erract (EA_WARN)
+
+ # Extract 1D spectra but do not extract negative beams
+ if (extract) {
+ do i = 1, naps {
+ if (AP_BEAM(Memi[aps+i-1]) < 0)
+ AP_SELECT(Memi[aps+i-1]) = NO
+ }
+
+ if (ap_getim (profs, Memc[str1], SZ_LINE) != EOF)
+ call strcpy (Memc[str1], Memc[profiles], SZ_FNAME)
+ call sprintf (Memc[str], SZ_LINE,
+ "Extract aperture spectra for %s?")
+ call pargstr (Memc[image])
+ if (ap_answer ("ansextract", Memc[str])) {
+ call sprintf (Memc[str], SZ_LINE,
+ "Review extracted spectra from %s?")
+ call pargstr (Memc[image])
+ if (ap_answer ("ansreview", Memc[str])) {
+ call apgstr ("ansreview", Memc[str], SZ_LINE)
+ call appstr ("ansreview1", Memc[str])
+ } else
+ call appstr ("ansreview1", "NO")
+ call ap_extract (Memc[image], Memc[output],
+ Memc[format], Memc[profiles], Memi[aps], naps)
+ }
+ }
+
+ # Fit apertures.
+ if (fit) {
+ call sprintf (Memc[str], SZ_LINE,
+ "Fit apertures in %s?")
+ call pargstr (Memc[image])
+ if (ap_answer ("ansfit", Memc[str])) {
+ call ap_extract (Memc[image], Memc[output],
+ Memc[format], nullstr, Memi[aps], naps)
+ }
+ }
+
+ # Normalize apertures.
+ if (norm) {
+ call sprintf (Memc[str], SZ_LINE,
+ "Normalize apertures in %s?")
+ call pargstr (Memc[image])
+ if (ap_answer ("ansnorm", Memc[str])) {
+ call sprintf (Memc[str], SZ_LINE,
+ "Fit spectra from %s interactively?")
+ call pargstr (Memc[image])
+ if (ap_answer ("ansfitspec", Memc[str])) {
+ call apgstr ("ansfitspec", Memc[str], SZ_LINE)
+ call appstr ("ansfitspec1", Memc[str])
+ } else
+ call appstr ("ansfitspec1", "NO")
+ call ap_extract (Memc[image], Memc[output],
+ Memc[format], nullstr, Memi[aps], naps)
+ }
+ }
+
+ # Flatten apertures.
+ if (flat) {
+ call sprintf (Memc[str], SZ_LINE,
+ "Flatten apertures in %s?")
+ call pargstr (Memc[image])
+ if (ap_answer ("ansflat", Memc[str])) {
+ call sprintf (Memc[str], SZ_LINE,
+ "Fit spectra from %s interactively?")
+ call pargstr (Memc[image])
+ if (ap_answer ("ansfitspec", Memc[str])) {
+ call apgstr ("ansfitspec", Memc[str], SZ_LINE)
+ call appstr ("ansfitspec1", Memc[str])
+ } else
+ call appstr ("ansfitspec1", "NO")
+ call ap_extract (Memc[image], Memc[output],
+ Memc[format], nullstr, Memi[aps], naps)
+ }
+ }
+
+ # Substract scattered light.
+ if (scat) {
+ if (ap_getim (scatout, Memc[str1], SZ_LINE) == EOF)
+ Memc[str1] = EOS
+ if (Memc[output] == EOS ||
+ streq (Memc[image], Memc[output])) {
+ call mktemp ("tmp", Memc[str], SZ_LINE)
+ call ap_scatter (Memc[image], Memc[str],
+ Memc[str1], Memi[aps], naps, line)
+ call imdelete (Memc[image])
+ call imrename (Memc[str], Memc[image])
+ } else
+ call ap_scatter (Memc[image], Memc[output],
+ Memc[str1], Memi[aps], naps, line)
+ }
+
+ # Make a aperture mask.
+ if (mask)
+ call ap_mask (Memc[image], Memc[output], Memi[aps], naps)
+
+ # Fit noise.
+ if (noise)
+ call ap_extract (Memc[image], nullstr,
+ Memc[format], nullstr, Memi[aps], naps)
+
+ } then
+ call erract (EA_WARN)
+
+ # Free memory.
+ for (i = 1; i <= naps; i = i + 1)
+ call ap_free (Memi[aps+i-1])
+ naps = 0
+ }
+
+ # Free memory and finish up.
+ call imtclose (input)
+ call imtclose (refs)
+ if (out != NULL)
+ call imtclose (out)
+ if (profs != NULL)
+ call imtclose (profs)
+ if (norm || flat)
+ call ap_fitfree ()
+ if (scat) {
+ if (scatout != NULL)
+ call imtclose (scatout)
+ call scat_free ()
+ }
+ call ap_gclose ()
+ call ap_trfree ()
+ call apcpset ()
+ call sfree (sp)
+end
+
+
+procedure ap_init (find, recenter, resize, edit, trace, extract, fit,
+ norm, flat, scat, mask, noise)
+
+bool find, recenter, resize, edit, trace
+bool extract, fit, norm, flat, scat, mask, noise
+
+pointer sp, str
+bool clgetb()
+
+begin
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ if (find)
+ call appans ("ansfind", find, find)
+ if (recenter)
+ call appans ("ansrecenter", recenter, recenter)
+ if (resize)
+ call appans ("ansresize", resize, resize)
+ if (edit)
+ call appans ("ansedit", edit, false)
+ if (trace) {
+ call appans ("anstrace", trace, trace)
+ call appans ("ansfittrace", clgetb ("fittrace"), false)
+ }
+ if (extract) {
+ call appans ("ansextract", extract, extract)
+ call appans ("ansreview", clgetb ("review"), false)
+ }
+ if (fit) {
+ call appans ("ansfit", fit, fit)
+ call appstr ("ansreview1", "NO")
+ }
+ if (norm) {
+ call appans ("ansnorm", norm, norm)
+ call appans ("ansfitspec", clgetb ("fitspec"), false)
+ call appstr ("ansreview1", "NO")
+ }
+ if (flat) {
+ call appans ("ansflat", flat, flat)
+ call appans ("ansfitspec", clgetb ("fitspec"), false)
+ call appstr ("ansreview1", "NO")
+ }
+ if (scat) {
+ call appans ("ansscat", scat, scat)
+ call appans ("anssmooth", clgetb ("smooth"), clgetb ("smooth"))
+ call appans ("ansfitscatter", clgetb ("fitscatter"), false)
+ call appans ("ansfitsmooth", clgetb ("fitsmooth"), false)
+ }
+ if (mask)
+ call appans ("ansmask", mask, mask)
+ if (noise)
+ call appstr ("ansreview1", "NO")
+
+ if (extract || fit || norm || flat) {
+ if (clgetb ("interactive"))
+ call appstr ("ansclobber", "no")
+ else
+ call appstr ("ansclobber", "NO")
+ }
+
+ call apgstr ("dbwrite", Memc[str], SZ_LINE)
+ if (clgetb ("interactive"))
+ call appstr ("ansdbwrite", Memc[str])
+ else {
+ if (Memc[str] == 'y' || Memc[str] == 'Y')
+ call appstr ("ansdbwrite", "YES")
+ else
+ call appstr ("ansdbwrite", "NO")
+ }
+
+ call sfree (sp)
+end
diff --git a/noao/twodspec/apextract/x_apextract.x b/noao/twodspec/apextract/x_apextract.x
new file mode 100644
index 00000000..47a5fc1a
--- /dev/null
+++ b/noao/twodspec/apextract/x_apextract.x
@@ -0,0 +1,15 @@
+task apall = t_apall,
+ apedit = t_apedit,
+ apfind = t_apfind,
+ apfit = t_apfit,
+ apflatten = t_apflat,
+ apmask = t_apmask,
+ apnormalize = t_apnorm,
+ aprecenter = t_aprecenter,
+ apresize = t_apresize,
+ apscatter = t_apscatter,
+ apscript = t_apscript,
+ apslitproc = t_apslitproc,
+ apnoise = t_apnoise,
+ apsum = t_apsum,
+ aptrace = t_aptrace