aboutsummaryrefslogtreecommitdiff
path: root/noao/imred/quadred/src/ccdproc
diff options
context:
space:
mode:
Diffstat (limited to 'noao/imred/quadred/src/ccdproc')
-rw-r--r--noao/imred/quadred/src/ccdproc/calimage.x367
-rw-r--r--noao/imred/quadred/src/ccdproc/ccdcache.com10
-rw-r--r--noao/imred/quadred/src/ccdproc/ccdcache.h10
-rw-r--r--noao/imred/quadred/src/ccdproc/ccdcache.x381
-rw-r--r--noao/imred/quadred/src/ccdproc/ccdcheck.x67
-rw-r--r--noao/imred/quadred/src/ccdproc/ccdcmp.x23
-rw-r--r--noao/imred/quadred/src/ccdproc/ccddelete.x55
-rw-r--r--noao/imred/quadred/src/ccdproc/ccdflag.x27
-rw-r--r--noao/imred/quadred/src/ccdproc/ccdlog.x46
-rw-r--r--noao/imred/quadred/src/ccdproc/ccdmean.x50
-rw-r--r--noao/imred/quadred/src/ccdproc/ccdnscan.x38
-rw-r--r--noao/imred/quadred/src/ccdproc/ccdproc.par43
-rw-r--r--noao/imred/quadred/src/ccdproc/ccdproc.x106
-rw-r--r--noao/imred/quadred/src/ccdproc/ccdred.h155
-rw-r--r--noao/imred/quadred/src/ccdproc/ccdsection.x100
-rw-r--r--noao/imred/quadred/src/ccdproc/ccdsubsets.x92
-rw-r--r--noao/imred/quadred/src/ccdproc/ccdtypes.h14
-rw-r--r--noao/imred/quadred/src/ccdproc/ccdtypes.x72
-rw-r--r--noao/imred/quadred/src/ccdproc/cor.gx362
-rw-r--r--noao/imred/quadred/src/ccdproc/corinput.gx220
-rw-r--r--noao/imred/quadred/src/ccdproc/doc/ccdproc.hlp778
-rw-r--r--noao/imred/quadred/src/ccdproc/doproc.x29
-rw-r--r--noao/imred/quadred/src/ccdproc/generic/ccdred.h155
-rw-r--r--noao/imred/quadred/src/ccdproc/generic/cor.x695
-rw-r--r--noao/imred/quadred/src/ccdproc/generic/corinput.x436
-rw-r--r--noao/imred/quadred/src/ccdproc/generic/mkpkg12
-rw-r--r--noao/imred/quadred/src/ccdproc/generic/proc.x678
-rw-r--r--noao/imred/quadred/src/ccdproc/hdrmap.com4
-rw-r--r--noao/imred/quadred/src/ccdproc/hdrmap.x544
-rw-r--r--noao/imred/quadred/src/ccdproc/mkpkg78
-rw-r--r--noao/imred/quadred/src/ccdproc/proc.gx379
-rw-r--r--noao/imred/quadred/src/ccdproc/readcor.x138
-rw-r--r--noao/imred/quadred/src/ccdproc/scancor.x340
-rw-r--r--noao/imred/quadred/src/ccdproc/setdark.x155
-rw-r--r--noao/imred/quadred/src/ccdproc/setfixpix.x181
-rw-r--r--noao/imred/quadred/src/ccdproc/setflat.x146
-rw-r--r--noao/imred/quadred/src/ccdproc/setfringe.x123
-rw-r--r--noao/imred/quadred/src/ccdproc/setheader.x76
-rw-r--r--noao/imred/quadred/src/ccdproc/setillum.x132
-rw-r--r--noao/imred/quadred/src/ccdproc/setinput.x48
-rw-r--r--noao/imred/quadred/src/ccdproc/setinteract.x31
-rw-r--r--noao/imred/quadred/src/ccdproc/setoutput.x51
-rw-r--r--noao/imred/quadred/src/ccdproc/setoverscan.x344
-rw-r--r--noao/imred/quadred/src/ccdproc/setproc.x80
-rw-r--r--noao/imred/quadred/src/ccdproc/setsections.x327
-rw-r--r--noao/imred/quadred/src/ccdproc/settrim.x115
-rw-r--r--noao/imred/quadred/src/ccdproc/setzero.x141
-rw-r--r--noao/imred/quadred/src/ccdproc/t_ccdproc.x155
-rw-r--r--noao/imred/quadred/src/ccdproc/timelog.x29
-rw-r--r--noao/imred/quadred/src/ccdproc/x_quadred.x1
50 files changed, 8639 insertions, 0 deletions
diff --git a/noao/imred/quadred/src/ccdproc/calimage.x b/noao/imred/quadred/src/ccdproc/calimage.x
new file mode 100644
index 00000000..8a6007c1
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/calimage.x
@@ -0,0 +1,367 @@
+include <error.h>
+include <imset.h>
+include "ccdtypes.h"
+
+define SZ_SUBSET 16 # Maximum size of subset string
+define IMAGE Memc[$1+($2-1)*SZ_FNAME] # Image string
+define SUBSET Memc[$1+($2-1)*SZ_SUBSET] # Subset string
+
+# CAL_IMAGE -- Return a calibration image for a specified input image.
+# CAL_OPEN -- Open the calibration image list.
+# CAL_CLOSE -- Close the calibration image list.
+# CAL_LIST -- Add images to the calibration image list.
+#
+# The open procedure is called first to get the calibration image
+# lists and add them to an internal list. Calibration images from the
+# input list are also added so that calibration images may be specified
+# either from the calibration image list parameters or in the input image list.
+# Existence errors and duplicate calibration images are ignored.
+# Validity checks are made when the calibration images are requested.
+#
+# During processing the calibration image names are requested for each input
+# image. The calibration image list is searched for a calibration image of
+# the right type and subset. If more than one is found the first one is
+# returned and a warning given for the others. The warning is only issued
+# once. If no calibration image is found then an error is returned.
+#
+# The calibration image list must be closed at the end of processing the
+# input images.
+
+
+# CAL_IMAGE -- Return a calibration image of a particular type.
+# Search the calibration list for the first calibration image of the desired
+# type and subset. Print a warning if there is more than one possible
+# calibration image and return an error if there is no calibration image.
+
+procedure cal_image (im, ccdtype, nscan, image, maxchars)
+
+pointer im # Image to be processed
+int ccdtype # Callibration CCD image type desired
+int nscan # Number of scan rows desired
+char image[maxchars] # Calibration image (returned)
+int maxchars # Maximum number chars in image name
+
+int i, m, n
+pointer sp, subset, str
+bool strne(), ccd_cmp()
+
+pointer ccdtypes # Pointer to array of calibration ccdtypes
+pointer subsets # Pointer to array of calibration subsets
+pointer nscans # Pointer to array of calibration nscan values
+pointer images # Pointer to array of calibration image names
+int nimages # Number of images
+common /calib/ ccdtypes, subsets, nscans, images, nimages
+
+begin
+ call smark (sp)
+ call salloc (subset, SZ_SUBSET, TY_CHAR)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ m = 0
+ n = 0
+ switch (ccdtype) {
+ case ZERO, DARK:
+ do i = 1, nimages {
+ if (Memi[ccdtypes+i-1] != ccdtype)
+ next
+ n = n + 1
+ if (n == 1) {
+ m = i
+ } else {
+ if (Memi[nscans+i-1] == Memi[nscans+m-1]) {
+# call eprintf (
+# "Warning: Extra calibration image %s ignored\n")
+# call pargstr (IMAGE(images,i))
+
+ # Reset the image type to eliminate further warnings.
+ Memi[ccdtypes+i-1] = UNKNOWN
+ } else if (Memi[nscans+m-1] != nscan &&
+ (Memi[nscans+i-1] == nscan ||
+ Memi[nscans+i-1] == 1)) {
+ m = i
+ }
+ }
+ }
+ case FLAT, ILLUM, FRINGE:
+ call ccdsubset (im, Memc[subset], SZ_SUBSET)
+
+ do i = 1, nimages {
+ if (Memi[ccdtypes+i-1] != ccdtype)
+ next
+ if (strne (SUBSET(subsets,i), Memc[subset]))
+ next
+ n = n + 1
+ if (n == 1) {
+ m = i
+ } else {
+ if (Memi[nscans+i-1] == Memi[nscans+m-1]) {
+# call eprintf (
+# "Warning: Extra calibration image %s ignored\n")
+# call pargstr (IMAGE(images,i))
+
+ # Reset the image type to eliminate further warnings.
+ Memi[ccdtypes+i-1] = UNKNOWN
+ } else if (Memi[nscans+m-1] != nscan &&
+ (Memi[nscans+i-1] == nscan ||
+ Memi[nscans+i-1] == 1)) {
+ m = i
+ }
+ }
+ }
+ }
+
+ # If no calibration image is found then it is an error.
+ if (m == 0) {
+ switch (ccdtype) {
+ case ZERO:
+ call error (0, "No zero level calibration image found")
+ case DARK:
+ call error (0, "No dark count calibration image found")
+ case FLAT:
+ call sprintf (Memc[str], SZ_LINE,
+ "No flat field calibration image of subset %s found")
+ call pargstr (Memc[subset])
+ call error (0, Memc[str])
+ case ILLUM:
+ call sprintf (Memc[str], SZ_LINE,
+ "No illumination calibration image of subset %s found")
+ call pargstr (Memc[subset])
+ call error (0, Memc[str])
+ case FRINGE:
+ call sprintf (Memc[str], SZ_LINE,
+ "No fringe calibration image of subset %s found")
+ call pargstr (Memc[subset])
+ call error (0, Memc[str])
+ }
+ }
+
+ call strcpy (IMAGE(images,m), image, maxchars)
+ if (nscan != Memi[nscans+m-1]) {
+ if (nscan != 1 && Memi[nscans+m-1] == 1)
+ call cal_scan (nscan, image, maxchars)
+ else {
+ call sprintf (Memc[str], SZ_LINE,
+ "Cannot find or create calibration with nscan of %d")
+ call pargi (nscan)
+ call error (0, Memc[str])
+ }
+ }
+
+ # Check that the input image is not the same as the calibration image.
+ call imstats (im, IM_IMAGENAME, Memc[str], SZ_LINE)
+ if (ccd_cmp (Memc[str], IMAGE(images,m))) {
+ call sprintf (Memc[str], SZ_LINE,
+ "Calibration image %s is the same as the input image")
+ call pargstr (image)
+ call error (0, Memc[str])
+ }
+
+ call sfree (sp)
+end
+
+
+# CAL_OPEN -- Create a list of calibration images from the input image list
+# and the calibration image lists.
+
+procedure cal_open (list)
+
+int list # List of input images
+int list1 # List of calibration images
+
+pointer sp, str
+int ccdtype, strdic(), imtopenp()
+bool clgetb()
+
+pointer ccdtypes # Pointer to array of calibration ccdtypes
+pointer subsets # Pointer to array of calibration subset numbers
+pointer nscans # Pointer to array of calibration nscan values
+pointer images # Pointer to array of calibration image names
+int nimages # Number of images
+common /calib/ ccdtypes, subsets, nscans, images, nimages
+
+errchk cal_list
+
+begin
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ call clgstr ("ccdtype", Memc[str], SZ_LINE)
+ call xt_stripwhite (Memc[str])
+ if (Memc[str] == EOS)
+ ccdtype = NONE
+ else
+ ccdtype = strdic (Memc[str], Memc[str], SZ_LINE, CCDTYPES)
+
+ # Add calibration images to list.
+ nimages = 0
+ if (ccdtype != ZERO && clgetb ("zerocor")) {
+ list1 = imtopenp ("zero")
+ call cal_list (list1, ZERO)
+ call imtclose (list1)
+ }
+ if (ccdtype != ZERO && ccdtype != DARK && clgetb ("darkcor")) {
+ list1 = imtopenp ("dark")
+ call cal_list (list1, DARK)
+ call imtclose (list1)
+ }
+ if (ccdtype != ZERO && ccdtype != DARK && ccdtype != FLAT &&
+ clgetb ("flatcor")) {
+ list1 = imtopenp ("flat")
+ call cal_list (list1, FLAT)
+ call imtclose (list1)
+ }
+ if (ccdtype != ZERO && ccdtype != DARK && ccdtype != FLAT &&
+ ccdtype != ILLUM && clgetb ("illumcor")) {
+ list1 = imtopenp ("illum")
+ call cal_list (list1, ILLUM)
+ call imtclose (list1)
+ }
+ if (ccdtype != ZERO && ccdtype != DARK && ccdtype != FLAT &&
+ ccdtype != FRINGE && clgetb ("fringecor")) {
+ list1 = imtopenp ("fringe")
+ call cal_list (list1, FRINGE)
+ call imtclose (list1)
+ }
+ if (list != NULL) {
+ call cal_list (list, UNKNOWN)
+ call imtrew (list)
+ }
+
+ call sfree (sp)
+end
+
+
+# CAL_CLOSE -- Free memory from the internal calibration image list.
+
+procedure cal_close ()
+
+pointer ccdtypes # Pointer to array of calibration ccdtypes
+pointer subsets # Pointer to array of calibration subset
+pointer nscans # Pointer to array of calibration nscan values
+pointer images # Pointer to array of calibration image names
+int nimages # Number of images
+common /calib/ ccdtypes, subsets, nscans, images, nimages
+
+begin
+ if (nimages > 0) {
+ call mfree (ccdtypes, TY_INT)
+ call mfree (subsets, TY_CHAR)
+ call mfree (nscans, TY_INT)
+ call mfree (images, TY_CHAR)
+ }
+end
+
+
+# CAL_LIST -- Add calibration images to an internal list.
+# Map each image and get the CCD image type and subset.
+# If the ccdtype is given as a procedure argument this overrides the
+# image header type. For the calibration images add the type, subset,
+# and image name to dynamic arrays. Ignore duplicate names.
+
+procedure cal_list (list, listtype)
+
+pointer list # Image list
+int listtype # CCD type of image in list.
+ # Overrides header type if not UNKNOWN.
+
+int i, ccdtype, ccdtypei(), ccdnscan(), imtgetim()
+pointer sp, image, im, immap()
+bool streq()
+
+pointer ccdtypes # Pointer to array of calibration ccdtypes
+pointer subsets # Pointer to array of calibration subsets
+pointer nscans # Pointer to array of calibration nscan values
+pointer images # Pointer to array of calibration image names
+int nimages # Number of images
+common /calib/ ccdtypes, subsets, nscans, images, nimages
+
+begin
+ call smark (sp)
+ call salloc (image, SZ_FNAME, TY_CHAR)
+
+ while (imtgetim (list, Memc[image], SZ_FNAME) != EOF) {
+ # Open the image. If an explicit type is given it is an
+ # error if the image can't be opened.
+ iferr (im = immap (Memc[image], READ_ONLY, 0)) {
+ if (listtype == UNKNOWN)
+ next
+ else
+ call erract (EA_ERROR)
+ }
+
+ # Override image header CCD type if a list type is given.
+ if (listtype == UNKNOWN)
+ ccdtype = ccdtypei (im)
+ else
+ ccdtype = listtype
+
+ switch (ccdtype) {
+ case ZERO, DARK, FLAT, ILLUM, FRINGE:
+ # Check for duplication.
+ for (i=1; i<=nimages; i=i+1)
+ if (streq (Memc[image], IMAGE(images,i)))
+ break
+ if (i <= nimages)
+ break
+
+ # Allocate memory for a new image.
+ if (i == 1) {
+ call malloc (ccdtypes, i, TY_INT)
+ call malloc (subsets, i * SZ_SUBSET, TY_CHAR)
+ call malloc (nscans, i, TY_INT)
+ call malloc (images, i * SZ_FNAME, TY_CHAR)
+ } else {
+ call realloc (ccdtypes, i, TY_INT)
+ call realloc (subsets, i * SZ_FNAME, TY_CHAR)
+ call realloc (nscans, i, TY_INT)
+ call realloc (images, i * SZ_FNAME, TY_CHAR)
+ }
+
+ # Enter the ccdtype, subset, and image name.
+ Memi[ccdtypes+i-1] = ccdtype
+ Memi[nscans+i-1] = ccdnscan (im, ccdtype)
+ call ccdsubset (im, SUBSET(subsets,i), SZ_SUBSET-1)
+ call strcpy (Memc[image], IMAGE(images,i), SZ_FNAME-1)
+ nimages = i
+ }
+ call imunmap (im)
+ }
+ call sfree (sp)
+end
+
+
+# CAL_SCAN -- Generate name for scan corrected calibration image.
+
+procedure cal_scan (nscan, image, maxchar)
+
+int nscan #I Number of scan lines
+char image[maxchar] #U Input root name, output scan name
+int maxchar #I Maximum number of chars in image name
+
+bool clgetb()
+pointer sp, root, ext
+
+begin
+ # Check if this operation is desired.
+ if (!clgetb ("scancor") || nscan == 1)
+ return
+
+ call smark (sp)
+ call salloc (root, SZ_FNAME, TY_CHAR)
+ call salloc (ext, SZ_FNAME, TY_CHAR)
+
+ call xt_imroot (image, Memc[root], SZ_FNAME)
+ call xt_imext (image, Memc[ext], SZ_FNAME)
+ if (IS_INDEFI (nscan)) {
+ call sprintf (image, maxchar, "%s.1d%s")
+ call pargstr (Memc[root])
+ call pargstr (Memc[ext])
+ } else {
+ call sprintf (image, maxchar, "%s.%d%s")
+ call pargstr (Memc[root])
+ call pargi (nscan)
+ call pargstr (Memc[ext])
+ }
+
+ call sfree (sp)
+end
diff --git a/noao/imred/quadred/src/ccdproc/ccdcache.com b/noao/imred/quadred/src/ccdproc/ccdcache.com
new file mode 100644
index 00000000..91ffae12
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/ccdcache.com
@@ -0,0 +1,10 @@
+# Common data defining the cached images and data.
+
+int ccd_ncache # Number of images cached
+int ccd_maxcache # Maximum size of cache
+int ccd_szcache # Current size of cache
+int ccd_oldsize # Original memory size
+int ccd_pcache # Pointer to image cache structures
+
+common /ccdcache_com/ ccd_ncache, ccd_maxcache, ccd_szcache, ccd_oldsize,
+ ccd_pcache
diff --git a/noao/imred/quadred/src/ccdproc/ccdcache.h b/noao/imred/quadred/src/ccdproc/ccdcache.h
new file mode 100644
index 00000000..f7de3a2c
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/ccdcache.h
@@ -0,0 +1,10 @@
+# Definition for image cache structure.
+
+define CCD_LENCACHE 6
+
+define CCD_IM Memi[$1] # IMIO pointer
+define CCD_NACCESS Memi[$1+1] # Number of accesses requested
+define CCD_SZDATA Memi[$1+2] # Size of data in cache in chars
+define CCD_DATA Memi[$1+3] # Pointer to data cache
+define CCD_BUFR Memi[$1+4] # Pointer to real image line
+define CCD_BUFS Memi[$1+5] # Pointer to short image line
diff --git a/noao/imred/quadred/src/ccdproc/ccdcache.x b/noao/imred/quadred/src/ccdproc/ccdcache.x
new file mode 100644
index 00000000..78f84ace
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/ccdcache.x
@@ -0,0 +1,381 @@
+include <imhdr.h>
+include <imset.h>
+include <mach.h>
+include "ccdcache.h"
+
+.help ccdcache Jun87
+.nf ---------------------------------------------------------------------
+The purpose of the CCD image caching package is to minimize image mapping
+time, to prevent multiple mapping of the same image, and to keep entire
+calibration images in memory for extended periods to minimize disk
+I/O. It is selected by specifying a maximum caching size based on the
+available memory. When there is not enough memory for caching (or by
+setting the size to 0) then standard IMIO is used. When there is
+enough memory then as many images as will fit into the specified cache
+size are kept in memory. Images are also kept mapped until explicitly
+flushed or the entire package is closed.
+
+This is a special purpose interface intended only for the CCDRED package.
+It has the following restrictions.
+
+ 1. Images must be processed to be cached.
+ 2. Images must be 2 dimensional to be cached
+ 3. Images must be real or short to be cached.
+ 4. Images must be read_only to be cached.
+ 5. Cached images remain in memory until they are displaced,
+ flushed, or the package is closed.
+
+The package consists of the following procedures.
+
+ ccd_open ()
+ im = ccd_cache (image)
+ ptr = ccd_glr (im, col1, col2, line)
+ ptr = ccd_gls (im, col1, col2, line)
+ ccd_unmap (im)
+ ccd_flush (im)
+ ccd_close ()
+
+
+CCD_OPEN: Initialize the image cache. Called at the beginning.
+CCD_CLOSE: Flush the image cache and restore memory. Called at the end.
+
+CCD_CACHE: Open an image and save the IMIO pointer. If the image has been
+opened previously it need not be opened again. If image data caching
+is specified the image data may be read it into memory. In order for
+image data caching to occur the the image has to have been processed,
+be two dimensional, be real or short, and the total cache memory not
+be exceeded. If an error occurs in reading the image into memory
+the data is not cached.
+
+CCD_UNMAP: The image access number is decremented but the image
+is not closed against the event it will be used again.
+
+CCD_FLUSH: The image is closed and flushed from the cache.
+
+CCD_GLR, CCD_GLS: Get a real or short image line. If the image data is cached
+then a pointer to the line is quickly returned. If the data is not cached then
+IMIO is used to get the pointer.
+.endhelp ---------------------------------------------------------------------
+
+
+
+# CCD_CACHE -- Open an image and possibly cache it in memory.
+
+pointer procedure ccd_cache (image, ccdtype)
+
+char image[ARB] # Image to be opened
+int ccdtype # Image type
+
+int i, nc, nl, nbytes
+pointer sp, str, pcache, pcache1, im
+
+int sizeof()
+pointer immap(), imgs2r(), imgs2s()
+bool streq(), ccdcheck()
+errchk immap, imgs2r, imgs2s
+
+include "ccdcache.com"
+
+define done_ 99
+
+begin
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ # Check if the image is cached.
+ for (i=1; i<=ccd_ncache; i=i+1) {
+ pcache = Memi[ccd_pcache+i-1]
+ im = CCD_IM(pcache)
+ call imstats (im, IM_IMAGENAME, Memc[str], SZ_LINE)
+ if (streq (image, Memc[str]))
+ break
+ }
+
+ # If the image is not cached open it and allocate memory.
+ if (i > ccd_ncache) {
+ im = immap (image, READ_ONLY, 0)
+ ccd_ncache = i
+ call realloc (ccd_pcache, ccd_ncache, TY_INT)
+ call malloc (pcache, CCD_LENCACHE, TY_STRUCT)
+ Memi[ccd_pcache+i-1] = pcache
+ CCD_IM(pcache) = im
+ CCD_NACCESS(pcache) = 0
+ CCD_SZDATA(pcache) = 0
+ CCD_DATA(pcache) = NULL
+ CCD_BUFR(pcache) = NULL
+ CCD_BUFS(pcache) = NULL
+ }
+
+ # If not caching the image data or if the image data has already
+ # been cached we are done.
+ if ((ccd_maxcache == 0) || (CCD_SZDATA(pcache) > 0))
+ goto done_
+
+ # Don't cache unprocessed calibration image data.
+ # This is the only really CCDRED specific code.
+ if (ccdcheck (im, ccdtype))
+ goto done_
+
+ # Check image is 2D and a supported pixel type.
+ if (IM_NDIM(im) != 2)
+ goto done_
+ if ((IM_PIXTYPE(im) != TY_REAL) && (IM_PIXTYPE(im) !=TY_SHORT))
+ goto done_
+
+ # Compute the size of the image data.
+ nc = IM_LEN(im,1)
+ nl = IM_LEN(im,2)
+ nbytes = nc * nl * sizeof (IM_PIXTYPE(im)) * SZB_CHAR
+
+ # Free memory not in use.
+ if (ccd_szcache + nbytes > ccd_maxcache) {
+ for (i=1; i<=ccd_ncache; i=i+1) {
+ pcache1 = Memi[ccd_pcache+i-1]
+ if (CCD_NACCESS(pcache1) == 0) {
+ if (CCD_SZDATA(pcache1) > 0) {
+ ccd_szcache = ccd_szcache - CCD_SZDATA(pcache1)
+ CCD_SZDATA(pcache1) = 0
+ CCD_DATA(pcache1) = NULL
+ call mfree (CCD_BUFR(pcache1), TY_REAL)
+ call mfree (CCD_BUFS(pcache1), TY_SHORT)
+ call imseti (CCD_IM(pcache1), IM_CANCEL, YES)
+ if (ccd_szcache + nbytes > ccd_maxcache)
+ break
+ }
+ }
+ }
+ }
+ if (ccd_szcache + nbytes > ccd_maxcache)
+ goto done_
+
+ # Cache the image data
+ iferr {
+ switch (IM_PIXTYPE (im)) {
+ case TY_SHORT:
+ CCD_DATA(pcache) = imgs2s (im, 1, nc, 1, nl)
+ case TY_REAL:
+ CCD_DATA(pcache) = imgs2r (im, 1, nc, 1, nl)
+ }
+ ccd_szcache = ccd_szcache + nbytes
+ CCD_SZDATA(pcache) = nbytes
+ } then {
+ call imunmap (im)
+ im = immap (image, READ_ONLY, 0)
+ CCD_IM(pcache) = im
+ CCD_SZDATA(pcache) = 0
+ }
+
+done_
+ CCD_NACCESS(pcache) = CCD_NACCESS(pcache) + 1
+ call sfree (sp)
+ return (im)
+end
+
+
+# CCD_OPEN -- Initialize the CCD image cache.
+
+procedure ccd_open (max_cache)
+
+int max_cache # Maximum cache size in bytes
+
+int max_size, begmem()
+include "ccdcache.com"
+
+begin
+ ccd_ncache = 0
+ ccd_maxcache = max_cache
+ ccd_szcache = 0
+ call malloc (ccd_pcache, 1, TY_INT)
+
+ # Ask for the maximum physical memory.
+ if (ccd_maxcache > 0) {
+ ccd_oldsize = begmem (0, ccd_oldsize, max_size)
+ call fixmem (max_size)
+ }
+end
+
+
+# CCD_UNMAP -- Unmap an image.
+# Don't actually unmap the image since it may be opened again.
+
+procedure ccd_unmap (im)
+
+pointer im # IMIO pointer
+
+int i
+pointer pcache
+include "ccdcache.com"
+
+begin
+ for (i=1; i<=ccd_ncache; i=i+1) {
+ pcache = Memi[ccd_pcache+i-1]
+ if (CCD_IM(pcache) == im) {
+ CCD_NACCESS(pcache) = CCD_NACCESS(pcache) - 1
+ return
+ }
+ }
+
+ call imunmap (im)
+end
+
+
+# CCD_FLUSH -- Close image and flush from cache.
+
+procedure ccd_flush (im)
+
+pointer im # IMIO pointer
+
+int i
+pointer pcache
+include "ccdcache.com"
+
+begin
+ for (i=1; i<=ccd_ncache; i=i+1) {
+ pcache = Memi[ccd_pcache+i-1]
+ if (CCD_IM(pcache) == im) {
+ ccd_ncache = ccd_ncache - 1
+ ccd_szcache = ccd_szcache - CCD_SZDATA(pcache)
+ call mfree (CCD_BUFR(pcache), TY_REAL)
+ call mfree (CCD_BUFS(pcache), TY_SHORT)
+ call mfree (pcache, TY_STRUCT)
+ for (; i<=ccd_ncache; i=i+1)
+ Memi[ccd_pcache+i-1] = Memi[ccd_pcache+i]
+ break
+ }
+ }
+
+ call imunmap (im)
+end
+
+
+# CCD_CLOSE -- Close the image cache.
+
+procedure ccd_close ()
+
+int i
+pointer pcache
+include "ccdcache.com"
+
+begin
+ for (i=1; i<=ccd_ncache; i=i+1) {
+ pcache = Memi[ccd_pcache+i-1]
+ call imunmap (CCD_IM(pcache))
+ call mfree (CCD_BUFR(pcache), TY_REAL)
+ call mfree (CCD_BUFS(pcache), TY_SHORT)
+ call mfree (pcache, TY_STRUCT)
+ }
+ call mfree (ccd_pcache, TY_INT)
+
+ # Restore memory.
+ call fixmem (ccd_oldsize)
+end
+
+
+# CCD_GLR -- Get a line of real data from the image.
+# If the image data is cached this is fast (particularly if the datatype
+# matches). If the image data is not cached then use IMIO.
+
+pointer procedure ccd_glr (im, col1, col2, line)
+
+pointer im # IMIO pointer
+int col1, col2 # Columns
+int line # Line
+
+int i
+pointer pcache, data, bufr, imgs2r()
+errchk malloc
+include "ccdcache.com"
+
+begin
+ # Quick test for cached data.
+ if (ccd_maxcache == 0)
+ return (imgs2r (im, col1, col2, line, line))
+
+ # Return cached data.
+ if (IM_PIXTYPE(im) == TY_REAL) {
+ for (i=1; i<=ccd_ncache; i=i+1) {
+ pcache = Memi[ccd_pcache+i-1]
+ if (CCD_IM(pcache) == im) {
+ if (CCD_SZDATA(pcache) > 0)
+ return (CCD_DATA(pcache)+(line-1)*IM_LEN(im,1)+col1-1)
+ else
+ break
+ }
+ }
+ } else {
+ for (i=1; i<=ccd_ncache; i=i+1) {
+ pcache = Memi[ccd_pcache+i-1]
+ if (CCD_IM(pcache) == im) {
+ if (CCD_SZDATA(pcache) > 0) {
+ data = CCD_DATA(pcache)+(line-1)*IM_LEN(im,1)+col1-1
+ bufr = CCD_BUFR(pcache)
+ if (bufr == NULL) {
+ call malloc (bufr, IM_LEN(im,1), TY_REAL)
+ CCD_BUFR(pcache) = bufr
+ }
+ call achtsr (Mems[data], Memr[bufr], IM_LEN(im,1))
+ return (bufr)
+ } else
+ break
+ }
+ }
+ }
+
+ # Return uncached data.
+ return (imgs2r (im, col1, col2, line, line))
+end
+
+
+# CCD_GLS -- Get a line of short data from the image.
+# If the image data is cached this is fast (particularly if the datatype
+# matches). If the image data is not cached then use IMIO.
+
+pointer procedure ccd_gls (im, col1, col2, line)
+
+pointer im # IMIO pointer
+int col1, col2 # Columns
+int line # Line
+
+int i
+pointer pcache, data, bufs, imgs2s()
+errchk malloc
+include "ccdcache.com"
+
+begin
+ # Quick test for cached data.
+ if (ccd_maxcache == 0)
+ return (imgs2s (im, col1, col2, line, line))
+
+ # Return cached data.
+ if (IM_PIXTYPE(im) == TY_SHORT) {
+ for (i=1; i<=ccd_ncache; i=i+1) {
+ pcache = Memi[ccd_pcache+i-1]
+ if (CCD_IM(pcache) == im) {
+ if (CCD_SZDATA(pcache) > 0)
+ return (CCD_DATA(pcache)+(line-1)*IM_LEN(im,1)+col1-1)
+ else
+ break
+ }
+ }
+ } else {
+ for (i=1; i<=ccd_ncache; i=i+1) {
+ pcache = Memi[ccd_pcache+i-1]
+ if (CCD_IM(pcache) == im) {
+ if (CCD_SZDATA(pcache) > 0) {
+ data = CCD_DATA(pcache)+(line-1)*IM_LEN(im,1)+col1-1
+ bufs = CCD_BUFS(pcache)
+ if (bufs == NULL) {
+ call malloc (bufs, IM_LEN(im,1), TY_SHORT)
+ CCD_BUFS(pcache) = bufs
+ }
+ call achtrs (Memr[data], Mems[bufs], IM_LEN(im,1))
+ return (bufs)
+ } else
+ break
+ }
+ }
+ }
+
+ # Return uncached data.
+ return (imgs2s (im, col1, col2, line, line))
+end
diff --git a/noao/imred/quadred/src/ccdproc/ccdcheck.x b/noao/imred/quadred/src/ccdproc/ccdcheck.x
new file mode 100644
index 00000000..0dde14f9
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/ccdcheck.x
@@ -0,0 +1,67 @@
+include <imhdr.h>
+include "ccdtypes.h"
+
+# CCDCHECK -- Check processing status.
+
+bool procedure ccdcheck (im, ccdtype)
+
+pointer im # IMIO pointer
+int ccdtype # CCD type
+
+real ccdmean, hdmgetr()
+bool clgetb(), ccdflag()
+long time
+int hdmgeti()
+
+begin
+ if (clgetb ("trim") && !ccdflag (im, "trim"))
+ return (true)
+ if (clgetb ("fixpix") && !ccdflag (im, "fixpix"))
+ return (true)
+ if (clgetb ("overscan") && !ccdflag (im, "overscan"))
+ return (true)
+
+ switch (ccdtype) {
+ case ZERO:
+ if (clgetb ("readcor") && !ccdflag (im, "readcor"))
+ return (true)
+ case DARK:
+ if (clgetb ("zerocor") && !ccdflag (im, "zerocor"))
+ return (true)
+ case FLAT:
+ if (clgetb ("zerocor") && !ccdflag (im, "zerocor"))
+ return (true)
+ if (clgetb ("darkcor") && !ccdflag (im, "darkcor"))
+ return (true)
+ if (clgetb ("scancor") && !ccdflag (im, "scancor"))
+ return (true)
+ iferr (ccdmean = hdmgetr (im, "ccdmean"))
+ return (true)
+ iferr (time = hdmgeti (im, "ccdmeant"))
+ time = IM_MTIME(im)
+ if (time < IM_MTIME(im))
+ return (true)
+ case ILLUM:
+ if (clgetb ("zerocor") && !ccdflag (im, "zerocor"))
+ return (true)
+ if (clgetb ("darkcor") && !ccdflag (im, "darkcor"))
+ return (true)
+ if (clgetb ("flatcor") && !ccdflag (im, "flatcor"))
+ return (true)
+ iferr (ccdmean = hdmgetr (im, "ccdmean"))
+ return (true)
+ default:
+ if (clgetb ("zerocor") && !ccdflag (im, "zerocor"))
+ return (true)
+ if (clgetb ("darkcor") && !ccdflag (im, "darkcor"))
+ return (true)
+ if (clgetb ("flatcor") && !ccdflag (im, "flatcor"))
+ return (true)
+ if (clgetb ("illumcor") && !ccdflag (im, "illumcor"))
+ return (true)
+ if (clgetb ("fringecor") && !ccdflag (im, "fringcor"))
+ return (true)
+ }
+
+ return (false)
+end
diff --git a/noao/imred/quadred/src/ccdproc/ccdcmp.x b/noao/imred/quadred/src/ccdproc/ccdcmp.x
new file mode 100644
index 00000000..a2687934
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/ccdcmp.x
@@ -0,0 +1,23 @@
+# CCD_CMP -- Compare two image names with extensions ignored.
+
+bool procedure ccd_cmp (image1, image2)
+
+char image1[ARB] # First image
+char image2[ARB] # Second image
+
+int i, j, strmatch(), strlen(), strncmp()
+bool streq()
+
+begin
+ if (streq (image1, image2))
+ return (true)
+
+ i = max (strmatch (image1, ".imh"), strmatch (image1, ".hhh"))
+ if (i == 0)
+ i = strlen (image1)
+ j = max (strmatch (image2, ".imh"), strmatch (image2, ".hhh"))
+ if (j == 0)
+ j = strlen (image2)
+
+ return (strncmp (image1, image2, max (i, j)) == 0)
+end
diff --git a/noao/imred/quadred/src/ccdproc/ccddelete.x b/noao/imred/quadred/src/ccdproc/ccddelete.x
new file mode 100644
index 00000000..90931135
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/ccddelete.x
@@ -0,0 +1,55 @@
+# CCDDELETE -- Delete an image by renaming it to a backup image.
+#
+# 1. Get the backup prefix which may be a path name.
+# 2. If no prefix is specified then delete the image without a backup.
+# 3. If there is a prefix then make a backup image name.
+# Rename the image to the backup image name.
+#
+# The backup image name is formed by prepending the backup prefix to the
+# image name. If a previous backup exist append integers to the backup
+# prefix until a nonexistant image name is created.
+
+procedure ccddelete (image)
+
+char image[ARB] # Image to delete (backup)
+
+int i, imaccess()
+pointer sp, prefix, backup
+errchk imdelete, imrename
+
+begin
+ call smark (sp)
+ call salloc (prefix, SZ_FNAME, TY_CHAR)
+ call salloc (backup, SZ_FNAME, TY_CHAR)
+
+ # Get the backup prefix.
+ call clgstr ("backup", Memc[prefix], SZ_FNAME)
+ call xt_stripwhite (Memc[prefix])
+
+ # If there is no prefix then simply delete the image.
+ if (Memc[prefix] == EOS)
+ call imdelete (image)
+
+ # Otherwise create a backup image name which does not exist and
+ # rename the image to the backup image.
+
+ else {
+ i = 0
+ repeat {
+ if (i == 0) {
+ call sprintf (Memc[backup], SZ_FNAME, "%s%s")
+ call pargstr (Memc[prefix])
+ call pargstr (image)
+ } else {
+ call sprintf (Memc[backup], SZ_FNAME, "%s%d%s")
+ call pargstr (Memc[prefix])
+ call pargi (i)
+ call pargstr (image)
+ }
+ i = i + 1
+ } until (imaccess (Memc[backup], READ_ONLY) == NO)
+ call imrename (image, Memc[backup])
+ }
+
+ call sfree (sp)
+end
diff --git a/noao/imred/quadred/src/ccdproc/ccdflag.x b/noao/imred/quadred/src/ccdproc/ccdflag.x
new file mode 100644
index 00000000..427365d2
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/ccdflag.x
@@ -0,0 +1,27 @@
+# CCDFLAG -- Determine if a CCD processing flag is set. This is less than
+# obvious because of the need to use the default value to indicate a
+# false flag.
+
+bool procedure ccdflag (im, name)
+
+pointer im # IMIO pointer
+char name[ARB] # CCD flag name
+
+bool flag, strne()
+pointer sp, str1, str2
+
+begin
+ call smark (sp)
+ call salloc (str1, SZ_LINE, TY_CHAR)
+ call salloc (str2, SZ_LINE, TY_CHAR)
+
+ # Get the flag string value and the default value.
+ # The flag is true if the value and the default do not match.
+
+ call hdmgstr (im, name, Memc[str1], SZ_LINE)
+ call hdmgdef (name, Memc[str2], SZ_LINE)
+ flag = strne (Memc[str1], Memc[str2])
+
+ call sfree (sp)
+ return (flag)
+end
diff --git a/noao/imred/quadred/src/ccdproc/ccdlog.x b/noao/imred/quadred/src/ccdproc/ccdlog.x
new file mode 100644
index 00000000..48453704
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/ccdlog.x
@@ -0,0 +1,46 @@
+include <imhdr.h>
+include <imset.h>
+
+# CCDLOG -- Log information about the processing with the image name.
+#
+# 1. If the package "verbose" parameter is set print the string preceded
+# by the image name.
+# 2. If the package "logfile" parameter is not null append the string,
+# preceded by the image name, to the file.
+
+procedure ccdlog (im, str)
+
+pointer im # IMIO pointer
+char str[ARB] # Log string
+
+int fd, open()
+bool clgetb()
+pointer sp, fname
+errchk open
+
+begin
+ call smark (sp)
+ call salloc (fname, SZ_FNAME, TY_CHAR)
+
+ # Write to the standard error output if "verbose".
+ if (clgetb ("verbose")) {
+ call imstats (im, IM_IMAGENAME, Memc[fname], SZ_FNAME)
+ call eprintf ("%s: %s\n")
+ call pargstr (Memc[fname])
+ call pargstr (str)
+ }
+
+ # Append to the "logfile" if not null.
+ call clgstr ("logfile", Memc[fname], SZ_FNAME)
+ call xt_stripwhite (Memc[fname])
+ if (Memc[fname] != EOS) {
+ fd = open (Memc[fname], APPEND, TEXT_FILE)
+ call imstats (im, IM_IMAGENAME, Memc[fname], SZ_FNAME)
+ call fprintf (fd, "%s: %s\n")
+ call pargstr (Memc[fname])
+ call pargstr (str)
+ call close (fd)
+ }
+
+ call sfree (sp)
+end
diff --git a/noao/imred/quadred/src/ccdproc/ccdmean.x b/noao/imred/quadred/src/ccdproc/ccdmean.x
new file mode 100644
index 00000000..d38ea97b
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/ccdmean.x
@@ -0,0 +1,50 @@
+include <imhdr.h>
+
+
+# CCDMEAN -- Compute mean and add to header if needed.
+
+procedure ccdmean (input)
+
+char input[ARB] # Input image
+
+int i, nc, nl, hdmgeti()
+long time, clktime()
+bool clgetb()
+real mean, hdmgetr(), asumr()
+pointer in, immap(), imgl2r()
+errchk immap
+
+begin
+ # Check if this operation has been done.
+
+ in = immap (input, READ_WRITE, 0)
+ ifnoerr (mean = hdmgetr (in, "ccdmean")) {
+ iferr (time = hdmgeti (in, "ccdmeant"))
+ time = IM_MTIME(in)
+ if (time >= IM_MTIME(in)) {
+ call imunmap (in)
+ return
+ }
+ }
+
+ if (clgetb ("noproc")) {
+ call eprintf (
+ " [TO BE DONE] Compute mean of image\n")
+ call pargstr (input)
+ call imunmap (in)
+ return
+ }
+
+ # Compute and record the mean.
+ nc = IM_LEN(in,1)
+ nl = IM_LEN(in,2)
+ mean = 0.
+ do i = 1, nl
+ mean = mean + asumr (Memr[imgl2r(in,i)], nc)
+ mean = mean / (nc * nl)
+ time = clktime (long(0))
+ call hdmputr (in, "ccdmean", mean)
+ call hdmputi (in, "ccdmeant", int (time))
+
+ call imunmap (in)
+end
diff --git a/noao/imred/quadred/src/ccdproc/ccdnscan.x b/noao/imred/quadred/src/ccdproc/ccdnscan.x
new file mode 100644
index 00000000..3a9fbeba
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/ccdnscan.x
@@ -0,0 +1,38 @@
+include "ccdtypes.h"
+
+
+# CCDNSCAN -- Return the number CCD scan rows.
+#
+# If not found in the header return the "nscan" parameter for objects and
+# 1 for calibration images.
+
+int procedure ccdnscan (im, ccdtype)
+
+pointer im #I Image
+int ccdtype #I CCD type
+int nscan #O Number of scan lines
+
+bool clgetb()
+char type, clgetc()
+int hdmgeti(), clgeti()
+
+begin
+ iferr (nscan = hdmgeti (im, "nscanrow")) {
+ switch (ccdtype) {
+ case ZERO, DARK, FLAT, ILLUM, FRINGE:
+ nscan = 1
+ default:
+ type = clgetc ("scantype")
+ if (type == 's')
+ nscan = clgeti ("nscan")
+ else {
+ if (clgetb ("scancor"))
+ nscan = INDEFI
+ else
+ nscan = 1
+ }
+ }
+ }
+
+ return (nscan)
+end
diff --git a/noao/imred/quadred/src/ccdproc/ccdproc.par b/noao/imred/quadred/src/ccdproc/ccdproc.par
new file mode 100644
index 00000000..f20207a7
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/ccdproc.par
@@ -0,0 +1,43 @@
+images,s,a,"",,,List of CCD images to correct
+ccdtype,s,h,"",,,CCD image type to correct
+max_cache,i,h,0,0,,Maximum image caching memory (in Mbytes)
+noproc,b,h,no,,,"List processing steps only?
+"
+fixpix,b,h,yes,,,Fix bad CCD lines and columns?
+overscan,b,h,yes,,,Apply overscan strip correction?
+trim,b,h,yes,,,Trim the image?
+zerocor,b,h,yes,,,Apply zero level correction?
+darkcor,b,h,no,,,Apply dark count correction?
+flatcor,b,h,yes,,,Apply flat field correction?
+illumcor,b,h,no,,,Apply illumination correction?
+fringecor,b,h,no,,,Apply fringe correction?
+readcor,b,h,no,,,Convert zero level image to readout correction?
+scancor,b,h,no,,,"Convert flat field image to scan correction?
+"
+readaxis,s,h,"line","column|line",, Read out axis (column|line)
+fixfile,s,h,"",,,File describing the bad lines and columns
+biassec,s,h,"",,,Overscan strip image section
+trimsec,s,h,"",,,Trim data section
+zero,s,h,"",,,Zero level calibration image
+dark,s,h,"",,,Dark count calibration image
+flat,s,h,"",,,Flat field images
+illum,s,h,"",,,Illumination correction images
+fringe,s,h,"",,,Fringe correction images
+minreplace,r,h,1.,,,Minimum flat field value
+scantype,s,h,"shortscan","shortscan|longscan",,Scan type (shortscan|longscan)
+nscan,i,h,1,1,,"Number of short scan lines
+"
+interactive,b,h,no,,,Fit overscan interactively?
+function,s,h,"legendre",,,Fitting function
+order,i,h,1,1,,Number of polynomial terms or spline pieces
+sample,s,h,"*",,,Sample points to fit
+naverage,i,h,1,,,Number of sample points to combine
+niterate,i,h,1,0,,Number of rejection iterations
+low_reject,r,h,3.,0.,,Low sigma rejection factor
+high_reject,r,h,3.,0.,,High sigma rejection factor
+grow,r,h,0.,0.,,"Rejection growing radius
+"
+verbose,b,h,)_.verbose,,,Print log information to the standard output?
+logfile,f,h,)_.logfile,,,Text log file
+backup,s,h,)_.backup,,,Backup directory or prefix
+output,s,h,"",,,Not used
diff --git a/noao/imred/quadred/src/ccdproc/ccdproc.x b/noao/imred/quadred/src/ccdproc/ccdproc.x
new file mode 100644
index 00000000..1b2a133c
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/ccdproc.x
@@ -0,0 +1,106 @@
+include <error.h>
+include "ccdred.h"
+include "ccdtypes.h"
+
+# CCDPROC -- Process a CCD image of a specified CCD image type.
+#
+# The input image is corrected for bad pixels, overscan levels, zero
+# levels, dark counts, flat field, illumination, and fringing. It may also
+# be trimmed. The checking of whether to apply each correction, getting the
+# required parameters, and logging the operations is left to separate
+# procedures, one for each correction. The actual processing is done by
+# a specialized procedure designed to be very efficient. These
+# procedures may also process calibration images if necessary.
+# The specified image type overrides the image type in the image header.
+# There are two data type paths; one for short data types and one for
+# all other data types (usually real).
+
+procedure ccdproc (input, ccdtype)
+
+char input[ARB] # CCD image to process
+int ccdtype # CCD type of image (independent of header).
+
+pointer sp, output, str, in, out, ccd, immap()
+errchk immap, set_output, ccddelete
+errchk set_fixpix, set_zero, set_dark, set_flat, set_illum, set_fringe
+
+begin
+ call smark (sp)
+ call salloc (output, SZ_FNAME, TY_CHAR)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ # Map the image, make a working output image and set the processing
+ # parameters.
+
+ in = immap (input, READ_ONLY, 0)
+ call mktemp ("tmp", Memc[output], SZ_FNAME)
+ call set_output (in, out, Memc[output])
+ call set_proc (in, out, ccd)
+ call set_sections (ccd)
+ call set_trim (ccd)
+ call set_fixpix (ccd)
+ call set_overscan (ccd)
+
+ # Set processing appropriate for the various image types.
+ switch (ccdtype) {
+ case ZERO:
+ case DARK:
+ call set_zero (ccd)
+ case FLAT:
+ call set_zero (ccd)
+ call set_dark (ccd)
+ CORS(ccd, FINDMEAN) = YES
+ CORS(ccd, MINREP) = YES
+ case ILLUM:
+ call set_zero (ccd)
+ call set_dark (ccd)
+ call set_flat (ccd)
+ case OBJECT, COMP:
+ call set_zero (ccd)
+ call set_dark (ccd)
+ call set_flat (ccd)
+ call set_illum (ccd)
+ call set_fringe (ccd)
+ default:
+ call set_zero (ccd)
+ call set_dark (ccd)
+ call set_flat (ccd)
+ call set_illum (ccd)
+ call set_fringe (ccd)
+ CORS(ccd, FINDMEAN) = YES
+ }
+
+ # Do the processing if the COR flag is set.
+ if (COR(ccd) == YES) {
+ call doproc (ccd)
+ call set_header (ccd)
+
+ # Replace the input by the output image.
+ call imunmap (in)
+ call imunmap (out)
+ iferr (call ccddelete (input)) {
+ call imdelete (Memc[output])
+ call error (1,
+ "Can't delete or make backup of original image")
+ }
+ call imrename (Memc[output], input)
+ } else {
+ # Delete the temporary output image leaving the input unchanged.
+ call imunmap (in)
+ iferr (call imunmap (out))
+ ;
+ iferr (call imdelete (Memc[output]))
+ ;
+ }
+ call free_proc (ccd)
+
+ # Do special processing for calibration images.
+ switch (ccdtype) {
+ case ZERO:
+ call readcor (input)
+ case FLAT:
+ call ccdmean (input)
+ }
+
+ call sfree (sp)
+end
diff --git a/noao/imred/quadred/src/ccdproc/ccdred.h b/noao/imred/quadred/src/ccdproc/ccdred.h
new file mode 100644
index 00000000..ef41f592
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/ccdred.h
@@ -0,0 +1,155 @@
+# CCDRED Data Structures and Definitions
+
+# The CCD structure: This structure is used to communicate processing
+# parameters between the package procedures. It contains pointers to
+# data, calibration image IMIO pointers, scaling parameters, and the
+# correction flags. The corrections flags indicate which processing
+# operations are to be performed. The subsection parameters do not
+# include a step size. A step size is assumed. If arbitrary subsampling
+# is desired this would be the next generalization.
+
+define LEN_CCD 75 # Length of CCD structure
+
+# CCD data coordinates
+define CCD_C1 Memi[$1] # CCD starting column
+define CCD_C2 Memi[$1+1] # CCD ending column
+define CCD_L1 Memi[$1+2] # CCD starting line
+define CCD_L2 Memi[$1+3] # CCD ending line
+
+# Input data
+define IN_IM Memi[$1+4] # Input image pointer
+define IN_C1 Memi[$1+5] # Input data starting column
+define IN_C2 Memi[$1+6] # Input data ending column
+define IN_L1 Memi[$1+7] # Input data starting line
+define IN_L2 Memi[$1+8] # Input data ending line
+define IN_NSEC Memi[$1+71] # Number of input pieces
+define IN_SEC Memi[$1+72] # Pointer to sections (c1,c2,l1,l2)xn
+
+# Output data
+define OUT_IM Memi[$1+9] # Output image pointer
+define OUT_C1 Memi[$1+10] # Output data starting column
+define OUT_C2 Memi[$1+11] # Output data ending column
+define OUT_L1 Memi[$1+12] # Output data starting line
+define OUT_L2 Memi[$1+13] # Output data ending line
+define OUT_SEC Memi[$1+73] # Pointer to sections (c1,c2,l1,l2)xn
+
+# Zero level data
+define ZERO_IM Memi[$1+14] # Zero level image pointer
+define ZERO_C1 Memi[$1+15] # Zero level data starting column
+define ZERO_C2 Memi[$1+16] # Zero level data ending column
+define ZERO_L1 Memi[$1+17] # Zero level data starting line
+define ZERO_L2 Memi[$1+18] # Zero level data ending line
+
+# Dark count data
+define DARK_IM Memi[$1+19] # Dark count image pointer
+define DARK_C1 Memi[$1+20] # Dark count data starting column
+define DARK_C2 Memi[$1+21] # Dark count data ending column
+define DARK_L1 Memi[$1+22] # Dark count data starting line
+define DARK_L2 Memi[$1+23] # Dark count data ending line
+
+# Flat field data
+define FLAT_IM Memi[$1+24] # Flat field image pointer
+define FLAT_C1 Memi[$1+25] # Flat field data starting column
+define FLAT_C2 Memi[$1+26] # Flat field data ending column
+define FLAT_L1 Memi[$1+27] # Flat field data starting line
+define FLAT_L2 Memi[$1+28] # Flat field data ending line
+
+# Illumination data
+define ILLUM_IM Memi[$1+29] # Illumination image pointer
+define ILLUM_C1 Memi[$1+30] # Illumination data starting column
+define ILLUM_C2 Memi[$1+31] # Illumination data ending column
+define ILLUM_L1 Memi[$1+32] # Illumination data starting line
+define ILLUM_L2 Memi[$1+33] # Illumination data ending line
+
+# Fringe data
+define FRINGE_IM Memi[$1+34] # Fringe image pointer
+define FRINGE_C1 Memi[$1+35] # Fringe data starting column
+define FRINGE_C2 Memi[$1+36] # Fringe data ending column
+define FRINGE_L1 Memi[$1+37] # Fringe data starting line
+define FRINGE_L2 Memi[$1+38] # Fringe data ending line
+
+# Trim section
+define TRIM_C1 Memi[$1+39] # Trim starting column
+define TRIM_C2 Memi[$1+40] # Trim ending column
+define TRIM_L1 Memi[$1+41] # Trim starting line
+define TRIM_L2 Memi[$1+42] # Trim ending line
+
+# Bias section
+define BIAS_C1 Memi[$1+43] # Bias starting column
+define BIAS_C2 Memi[$1+44] # Bias ending column
+define BIAS_L1 Memi[$1+45] # Bias starting line
+define BIAS_L2 Memi[$1+46] # Bias ending line
+define BIAS_SEC Memi[$1+74] # Multiple bias sections
+
+define READAXIS Memi[$1+47] # Read out axis (1=cols, 2=lines)
+define CALCTYPE Memi[$1+48] # Calculation data type
+define NBADCOLS Memi[$1+49] # Number of column interpolation regions
+define BADCOLS Memi[$1+50] # Pointer to col interpolation regions
+define NBADLINES Memi[$1+51] # Number of line interpolation regions
+define BADLINES Memi[$1+52] # Pointer to line interpolation regions
+define OVERSCAN_VEC Memi[$1+53] # Pointer to overscan vector
+define DARKSCALE Memr[P2R($1+54)] # Dark count scale factor
+define FRINGESCALE Memr[P2R($1+55)] # Fringe scale factor
+define FLATSCALE Memr[P2R($1+56)] # Flat field scale factor
+define ILLUMSCALE Memr[P2R($1+57)] # Illumination scale factor
+define MINREPLACE Memr[P2R($1+58)] # Minimum replacement value
+define MEAN Memr[P2R($1+59)] # Mean of output image
+define COR Memi[$1+60] # Overall correction flag
+define CORS Memi[$1+61+($2-1)] # Individual correction flags
+
+# Individual components of input, output, and bias section pieces.
+define IN_SC1 Memi[IN_SEC($1)+4*$2-4]
+define IN_SC2 Memi[IN_SEC($1)+4*$2-3]
+define IN_SL1 Memi[IN_SEC($1)+4*$2-2]
+define IN_SL2 Memi[IN_SEC($1)+4*$2-1]
+define OUT_SC1 Memi[OUT_SEC($1)+4*$2-4]
+define OUT_SC2 Memi[OUT_SEC($1)+4*$2-3]
+define OUT_SL1 Memi[OUT_SEC($1)+4*$2-2]
+define OUT_SL2 Memi[OUT_SEC($1)+4*$2-1]
+define BIAS_SC1 Memi[BIAS_SEC($1)+4*$2-4]
+define BIAS_SC2 Memi[BIAS_SEC($1)+4*$2-3]
+define BIAS_SL1 Memi[BIAS_SEC($1)+4*$2-2]
+define BIAS_SL2 Memi[BIAS_SEC($1)+4*$2-1]
+
+# The correction array contains the following elements with array indices
+# given by the macro definitions.
+
+define NCORS 10 # Number of corrections
+
+define FIXPIX 1 # Fix bad pixels
+define TRIM 2 # Trim image
+define OVERSCAN 3 # Apply overscan correction
+define ZEROCOR 4 # Apply zero level correction
+define DARKCOR 5 # Apply dark count correction
+define FLATCOR 6 # Apply flat field correction
+define ILLUMCOR 7 # Apply illumination correction
+define FRINGECOR 8 # Apply fringe correction
+define FINDMEAN 9 # Find the mean of the output image
+define MINREP 10 # Check and replace minimum value
+
+# The following definitions identify the correction values in the correction
+# array. They are defined in terms of bit fields so that it is possible to
+# add corrections to form unique combination corrections. Some of
+# these combinations are implemented as compound operations for efficiency.
+
+define O 001B # overscan
+define Z 002B # zero level
+define D 004B # dark count
+define F 010B # flat field
+define I 020B # Illumination
+define Q 040B # Fringe
+
+# The following correction combinations are recognized.
+
+define ZO 003B # zero level + overscan
+define DO 005B # dark count + overscan
+define DZ 006B # dark count + zero level
+define DZO 007B # dark count + zero level + overscan
+define FO 011B # flat field + overscan
+define FZ 012B # flat field + zero level
+define FZO 013B # flat field + zero level + overscan
+define FD 014B # flat field + dark count
+define FDO 015B # flat field + dark count + overscan
+define FDZ 016B # flat field + dark count + zero level
+define FDZO 017B # flat field + dark count + zero level + overscan
+define QI 060B # fringe + illumination
diff --git a/noao/imred/quadred/src/ccdproc/ccdsection.x b/noao/imred/quadred/src/ccdproc/ccdsection.x
new file mode 100644
index 00000000..aced216a
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/ccdsection.x
@@ -0,0 +1,100 @@
+include <ctype.h>
+
+# CCD_SECTION -- Parse a 2D image section into its elements.
+# 1. The default values must be set by the caller.
+# 2. A null image section is OK.
+# 3. The first nonwhitespace character must be '['.
+# 4. The last interpreted character must be ']'.
+#
+# This procedure should be replaced with an IMIO procedure at some
+# point.
+
+procedure ccd_section (section, x1, x2, xstep, y1, y2, ystep)
+
+char section[ARB] # Image section
+int x1, x2, xstep # X image section parameters
+int y1, y2, ystep # X image section parameters
+
+int i, ip, a, b, c, temp, ctoi()
+define error_ 99
+
+begin
+ # Decode the section string.
+ ip = 1
+ while (IS_WHITE(section[ip]))
+ ip = ip + 1
+ if (section[ip] == '[')
+ ip = ip + 1
+ else if (section[ip] == EOS)
+ return
+ else
+ goto error_
+
+ do i = 1, 2 {
+ while (IS_WHITE(section[ip]))
+ ip = ip + 1
+
+ # Default values
+ if (i == 1) {
+ a = x1
+ b = x2
+ c = xstep
+ } else {
+ a = y1
+ b = y2
+ c = ystep
+ }
+
+ # Get a:b:c. Allow notation such as "-*:c"
+ # (or even "-:c") where the step is obviously negative.
+
+ if (ctoi (section, ip, temp) > 0) { # a
+ a = temp
+ if (section[ip] == ':') {
+ ip = ip + 1
+ if (ctoi (section, ip, b) == 0) # a:b
+ goto error_
+ } else
+ b = a
+ } else if (section[ip] == '-') { # -*
+ temp = a
+ a = b
+ b = temp
+ ip = ip + 1
+ if (section[ip] == '*')
+ ip = ip + 1
+ } else if (section[ip] == '*') # *
+ ip = ip + 1
+ if (section[ip] == ':') { # ..:step
+ ip = ip + 1
+ if (ctoi (section, ip, c) == 0)
+ goto error_
+ else if (c == 0)
+ goto error_
+ }
+ if (a > b && c > 0)
+ c = -c
+
+ if (i == 1) {
+ x1 = a
+ x2 = b
+ xstep = c
+ } else {
+ y1 = a
+ y2 = b
+ ystep = c
+ }
+
+ while (IS_WHITE(section[ip]))
+ ip = ip + 1
+ if (section[ip] == ',')
+ ip = ip + 1
+ }
+
+ if (section[ip] != ']')
+ goto error_
+
+ return
+error_
+ call error (0, "Error in image section specification")
+end
diff --git a/noao/imred/quadred/src/ccdproc/ccdsubsets.x b/noao/imred/quadred/src/ccdproc/ccdsubsets.x
new file mode 100644
index 00000000..6152897f
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/ccdsubsets.x
@@ -0,0 +1,92 @@
+# CCDSUBSET -- Return the CCD subset identifier.
+#
+# 1. Get the subset string and search the subset record file for the ID string.
+# 2. If the subset string is not in the record file define a default ID string
+# based on the first word of the subset string. If the first word is not
+# unique append a integer to the first word until it is unique.
+# 3. Add the new subset string and identifier to the record file.
+# 4. Since the ID string is used to generate image names replace all
+# nonimage name characters with '_'.
+#
+# It is an error if the record file cannot be created or written when needed.
+
+procedure ccdsubset (im, subset, sz_name)
+
+pointer im # Image
+char subset[sz_name] # CCD subset identifier
+int sz_name # Size of subset string
+
+bool streq()
+int i, fd, ctowrd(), open(), fscan()
+pointer sp, fname, str1, str2, subset1, subset2, subset3
+errchk open
+
+begin
+ call smark (sp)
+ call salloc (fname, SZ_FNAME, TY_CHAR)
+ call salloc (str1, SZ_LINE, TY_CHAR)
+ call salloc (str2, SZ_LINE, TY_CHAR)
+ call salloc (subset1, SZ_LINE, TY_CHAR)
+ call salloc (subset2, SZ_LINE, TY_CHAR)
+ call salloc (subset3, SZ_LINE, TY_CHAR)
+
+ # Get the subset record file and the subset string.
+ call clgstr ("ssfile", Memc[fname], SZ_LINE)
+ call hdmgstr (im, "subset", Memc[str1], SZ_LINE)
+
+ # The default subset identifier is the first word of the subset string.
+ i = 1
+ i = ctowrd (Memc[str1], i, Memc[subset1], SZ_LINE)
+
+ # A null subset string is ok. If not null check for conflict
+ # with previous subset IDs.
+ if (Memc[str1] != EOS) {
+ call strcpy (Memc[subset1], Memc[subset3], SZ_LINE)
+
+ # Search the subset record file for the same subset string.
+ # If found use the ID string. If the subset ID has been
+ # used for another subset string then increment an integer
+ # suffix to the default ID and check the list again.
+
+ i = 1
+ ifnoerr (fd = open (Memc[fname], READ_ONLY, TEXT_FILE)) {
+ while (fscan (fd) != EOF) {
+ call gargwrd (Memc[str2], SZ_LINE)
+ call gargwrd (Memc[subset2], SZ_LINE)
+ if (streq (Memc[str1], Memc[str2])) {
+ i = 0
+ call strcpy (Memc[subset2], Memc[subset1], SZ_LINE)
+ break
+ } if (streq (Memc[subset1], Memc[subset2])) {
+ call sprintf (Memc[subset1], SZ_LINE, "%s%d")
+ call pargstr (Memc[subset3])
+ call pargi (i)
+ i = i + 1
+ call seek (fd, BOF)
+ }
+ }
+ call close (fd)
+ }
+
+ # If the subset is not in the record file add it.
+ if (i > 0) {
+ fd = open (Memc[fname], APPEND, TEXT_FILE)
+ call fprintf (fd, "'%s'\t%s\n")
+ call pargstr (Memc[str1])
+ call pargstr (Memc[subset1])
+ call close (fd)
+ }
+ }
+
+ # Set the subset ID string and replace magic characters by '_'
+ # since the subset ID is used in forming image names.
+
+ call strcpy (Memc[subset1], subset, sz_name)
+ for (i=1; subset[i]!=EOS; i=i+1)
+ switch (subset[i]) {
+ case '-','+','?','*','[',']',' ','\t':
+ subset[i] = '_'
+ }
+
+ call sfree (sp)
+end
diff --git a/noao/imred/quadred/src/ccdproc/ccdtypes.h b/noao/imred/quadred/src/ccdproc/ccdtypes.h
new file mode 100644
index 00000000..0d5d4caf
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/ccdtypes.h
@@ -0,0 +1,14 @@
+# Standard CCD image types.
+
+define CCDTYPES "|object|zero|dark|flat|illum|fringe|other|comp|"
+
+define NONE -1
+define UNKNOWN 0
+define OBJECT 1
+define ZERO 2
+define DARK 3
+define FLAT 4
+define ILLUM 5
+define FRINGE 6
+define OTHER 7
+define COMP 8
diff --git a/noao/imred/quadred/src/ccdproc/ccdtypes.x b/noao/imred/quadred/src/ccdproc/ccdtypes.x
new file mode 100644
index 00000000..bf6d29e2
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/ccdtypes.x
@@ -0,0 +1,72 @@
+include "ccdtypes.h"
+
+# CCDTYPES -- Return the CCD type name string.
+# CCDTYPEI -- Return the CCD type code.
+
+
+# CCDTYPES -- Return the CCD type name string.
+
+procedure ccdtypes (im, name, sz_name)
+
+pointer im # Image
+char name[sz_name] # CCD type name
+int sz_name # Size of name string
+
+int strdic()
+pointer sp, str
+
+begin
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ # Get the image type string. If none then return "none".
+ # Otherwise get the corresponding package image type string.
+ # If the image type is unknown return "unknown" otherwise return
+ # the package name.
+
+ call hdmgstr (im, "imagetyp", Memc[str], SZ_LINE)
+ if (Memc[str] == EOS) {
+ call strcpy ("none", name, sz_name)
+ } else {
+ call hdmname (Memc[str], name, sz_name)
+ if (name[1] == EOS)
+ call strcpy (Memc[str], name, sz_name)
+ if (strdic (name, name, sz_name, CCDTYPES) == UNKNOWN)
+ call strcpy ("unknown", name, sz_name)
+ }
+
+ call sfree (sp)
+end
+
+
+# CCDTYPEI -- Return the CCD type code.
+
+int procedure ccdtypei (im)
+
+pointer im # Image
+int ccdtype # CCD type (returned)
+
+pointer sp, str1, str2
+int strdic()
+
+begin
+ call smark (sp)
+ call salloc (str1, SZ_LINE, TY_CHAR)
+ call salloc (str2, SZ_LINE, TY_CHAR)
+
+ # Get the image type and if there is none then return the NONE code.
+ call hdmgstr (im, "imagetyp", Memc[str1], SZ_LINE)
+ if (Memc[str1] == EOS) {
+ ccdtype = NONE
+
+ # Otherwise get the package type and convert to an image type code.
+ } else {
+ call hdmname (Memc[str1], Memc[str2], SZ_LINE)
+ if (Memc[str2] == EOS)
+ call strcpy (Memc[str1], Memc[str2], SZ_LINE)
+ ccdtype = strdic (Memc[str2], Memc[str2], SZ_LINE, CCDTYPES)
+ }
+
+ call sfree (sp)
+ return (ccdtype)
+end
diff --git a/noao/imred/quadred/src/ccdproc/cor.gx b/noao/imred/quadred/src/ccdproc/cor.gx
new file mode 100644
index 00000000..189f9437
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/cor.gx
@@ -0,0 +1,362 @@
+include "ccdred.h"
+
+
+.help cor Feb87 noao.imred.ccdred
+.nf ----------------------------------------------------------------------------
+cor -- Process CCD image lines
+
+These procedures are the heart of the CCD processing. They do the desired
+set of processing operations on the image line data as efficiently as
+possible. They are called by the PROC procedures. There are four procedures
+one for each readout axis and one for short and real image data.
+Some sets of operations are coded as single compound operations for efficiency.
+To keep the number of combinations managable only the most common
+combinations are coded as compound operations. The combinations
+consist of any set of line overscan, column overscan, zero level, dark
+count, and flat field and any set of illumination and fringe
+correction. The corrections are applied in place to the output vector.
+
+The column readout procedure is more complicated in order to handle
+zero level and flat field corrections specified as one dimensional
+readout corrections instead of two dimensional calibration images.
+Column readout format is probably extremely rare and the 1D readout
+corrections are used only for special types of data.
+.ih
+SEE ALSO
+proc, ccdred.h
+.endhelp -----------------------------------------------------------------------
+
+$for (sr)
+# COR1 -- Correct image lines with readout axis 1 (lines).
+
+procedure cor1$t (cors, out, overscan, zero, dark, flat, illum,
+ fringe, n, darkscale, flatscale, illumscale, frgscale)
+
+int cors[ARB] # Correction flags
+PIXEL out[n] # Output data
+real overscan # Overscan value
+PIXEL zero[n] # Zero level correction
+PIXEL dark[n] # Dark count correction
+PIXEL flat[n] # Flat field correction
+PIXEL illum[n] # Illumination correction
+PIXEL fringe[n] # Fringe correction
+int n # Number of pixels
+real darkscale # Dark count scale factor
+real flatscale # Flat field scale factor
+real illumscale # Illumination scale factor
+real frgscale # Fringe scale factor
+
+int i, op
+
+begin
+ op = cors[OVERSCAN] + cors[ZEROCOR] + cors[DARKCOR] + cors[FLATCOR]
+ switch (op) {
+ case O: # overscan
+ do i = 1, n
+ out[i] = out[i] - overscan
+ case Z: # zero level
+ do i = 1, n
+ out[i] = out[i] - zero[i]
+
+ case ZO: # zero level + overscan
+ do i = 1, n
+ out[i] = out[i] - overscan - zero[i]
+
+ case D: # dark count
+ do i = 1, n
+ out[i] = out[i] - darkscale * dark[i]
+ case DO: # dark count + overscan
+ do i = 1, n
+ out[i] = out[i] - overscan - darkscale * dark[i]
+ case DZ: # dark count + zero level
+ do i = 1, n
+ out[i] = out[i] - zero[i] - darkscale * dark[i]
+ case DZO: # dark count + zero level + overscan
+ do i = 1, n
+ out[i] = out[i] - overscan - zero[i] - darkscale * dark[i]
+
+ case F: # flat field
+ do i = 1, n
+ out[i] = out[i] * flatscale / flat[i]
+ case FO: # flat field + overscan
+ do i = 1, n
+ out[i] = (out[i] - overscan) * flatscale / flat[i]
+ case FZ: # flat field + zero level
+ do i = 1, n
+ out[i] = (out[i] - zero[i]) * flatscale / flat[i]
+ case FZO: # flat field + zero level + overscan
+ do i = 1, n
+ out[i] = (out[i] - overscan - zero[i]) * flatscale /
+ flat[i]
+ case FD: # flat field + dark count
+ do i = 1, n
+ out[i] = (out[i] - darkscale * dark[i]) * flatscale / flat[i]
+ case FDO: # flat field + dark count + overscan
+ do i = 1, n
+ out[i] = (out[i] - overscan - darkscale * dark[i]) *
+ flatscale / flat[i]
+ case FDZ: # flat field + dark count + zero level
+ do i = 1, n
+ out[i] = (out[i] - zero[i] - darkscale * dark[i]) *
+ flatscale / flat[i]
+ case FDZO: # flat field + dark count + zero level + overscan
+ do i = 1, n
+ out[i] = (out[i] - overscan - zero[i] -
+ darkscale * dark[i]) * flatscale / flat[i]
+ }
+
+ # Often these operations will not be performed so test for no
+ # correction rather than go through the switch.
+
+ op = cors[ILLUMCOR] + cors[FRINGECOR]
+ if (op != 0) {
+ switch (op) {
+ case I: # illumination
+ do i = 1, n
+ out[i] = out[i] * illumscale / illum[i]
+ case Q: # fringe
+ do i = 1, n
+ out[i] = out[i] - frgscale * fringe[i]
+ case QI: # fringe + illumination
+ do i = 1, n
+ out[i] = out[i]*illumscale/illum[i] - frgscale*fringe[i]
+ }
+ }
+end
+
+
+# COR2 -- Correct lines for readout axis 2 (columns). This procedure is
+# more complex than when the readout is along the image lines because the
+# zero level and/or flat field corrections may be single readout column
+# vectors.
+
+procedure cor2$t (line, cors, out, overscan, zero, dark, flat, illum,
+ fringe, n, zeroim, flatim, darkscale, flatscale, illumscale, frgscale)
+
+int line # Line to be corrected
+int cors[ARB] # Correction flags
+PIXEL out[n] # Output data
+real overscan[n] # Overscan value
+PIXEL zero[n] # Zero level correction
+PIXEL dark[n] # Dark count correction
+PIXEL flat[n] # Flat field correction
+PIXEL illum[n] # Illumination correction
+PIXEL fringe[n] # Fringe correction
+int n # Number of pixels
+pointer zeroim # Zero level IMIO pointer (NULL if 1D vector)
+pointer flatim # Flat field IMIO pointer (NULL if 1D vector)
+real darkscale # Dark count scale factor
+real flatscale # Flat field scale factor
+real illumscale # Illumination scale factor
+real frgscale # Fringe scale factor
+
+PIXEL zeroval
+real flatval
+int i, op
+
+begin
+ op = cors[OVERSCAN] + cors[ZEROCOR] + cors[DARKCOR] + cors[FLATCOR]
+ switch (op) {
+ case O: # overscan
+ do i = 1, n
+ out[i] = out[i] - overscan[i]
+ case Z: # zero level
+ if (zeroim != NULL)
+ do i = 1, n
+ out[i] = out[i] - zero[i]
+ else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = out[i] - zeroval
+ }
+
+ case ZO: # zero level + overscan
+ if (zeroim != NULL)
+ do i = 1, n
+ out[i] = out[i] - overscan[i] - zero[i]
+ else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = out[i] - overscan[i] - zeroval
+ }
+
+ case D: # dark count
+ do i = 1, n
+ out[i] = out[i] - darkscale * dark[i]
+ case DO: # dark count + overscan
+ do i = 1, n
+ out[i] = out[i] - overscan[i] - darkscale * dark[i]
+ case DZ: # dark count + zero level
+ if (zeroim != NULL)
+ do i = 1, n
+ out[i] = out[i] - zero[i] - darkscale * dark[i]
+ else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = out[i] - zeroval - darkscale * dark[i]
+ }
+ case DZO: # dark count + zero level + overscan
+ if (zeroim != NULL)
+ do i = 1, n
+ out[i] = out[i] - overscan[i] - zero[i] -
+ darkscale * dark[i]
+ else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = out[i] - overscan[i] - zeroval -
+ darkscale * dark[i]
+ }
+
+ case F: # flat field
+ if (flatim != NULL) {
+ do i = 1, n
+ out[i] = out[i] * flatscale / flat[i]
+ } else {
+ flatval = flatscale / flat[line]
+ do i = 1, n
+ out[i] = out[i] * flatval
+ }
+ case FO: # flat field + overscan
+ if (flatim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - overscan[i]) * flatscale / flat[i]
+ } else {
+ flatval = flatscale / flat[line]
+ do i = 1, n
+ out[i] = (out[i] - overscan[i]) * flatval
+ }
+ case FZ: # flat field + zero level
+ if (flatim != NULL) {
+ if (zeroim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - zero[i]) * flatscale / flat[i]
+ } else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = (out[i] - zeroval) * flatscale / flat[i]
+ }
+ } else {
+ flatval = flatscale / flat[line]
+ if (zeroim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - zero[i]) * flatval
+ } else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = (out[i] - zeroval) * flatval
+ }
+ }
+ case FZO: # flat field + zero level + overscan
+ if (flatim != NULL) {
+ if (zeroim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - zero[i]) *
+ flatscale / flat[i]
+ } else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - zeroval) *
+ flatscale / flat[i]
+ }
+ } else {
+ flatval = flatscale / flat[line]
+ if (zeroim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - zero[i]) * flatval
+ } else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - zeroval) * flatval
+ }
+ }
+ case FD: # flat field + dark count
+ if (flatim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - darkscale * dark[i]) * flatscale/flat[i]
+ } else {
+ flatval = flatscale / flat[line]
+ do i = 1, n
+ out[i] = (out[i] - darkscale * dark[i]) * flatval
+ }
+ case FDO: # flat field + dark count + overscan
+ if (flatim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - darkscale * dark[i]) *
+ flatscale / flat[i]
+ } else {
+ flatval = flatscale / flat[line]
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - darkscale * dark[i]) *
+ flatval
+ }
+ case FDZ: # flat field + dark count + zero level
+ if (flatim != NULL) {
+ if (zeroim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - zero[i] - darkscale * dark[i]) *
+ flatscale / flat[i]
+ } else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = (out[i] - zeroval - darkscale * dark[i]) *
+ flatscale / flat[i]
+ }
+ } else {
+ flatval = flatscale / flat[line]
+ if (zeroim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - zero[i] - darkscale * dark[i]) *
+ flatval
+ } else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = (out[i] - zeroval - darkscale * dark[i]) *
+ flatval
+ }
+ }
+ case FDZO: # flat field + dark count + zero level + overscan
+ if (flatim != NULL) {
+ if (zeroim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - zero[i] -
+ darkscale * dark[i]) * flatscale / flat[i]
+ } else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - zeroval -
+ darkscale * dark[i]) * flatscale / flat[i]
+ }
+ } else {
+ flatval = flatscale / flat[line]
+ if (zeroim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - zero[i] -
+ darkscale * dark[i]) * flatval
+ } else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - zeroval -
+ darkscale * dark[i]) * flatval
+ }
+ }
+ }
+
+ # Often these operations will not be performed so test for no
+ # correction rather than go through the switch.
+
+ op = cors[ILLUMCOR] + cors[FRINGECOR]
+ if (op != 0) {
+ switch (op) {
+ case I: # illumination
+ do i = 1, n
+ out[i] = out[i] * illumscale / illum[i]
+ case Q: # fringe
+ do i = 1, n
+ out[i] = out[i] - frgscale * fringe[i]
+ case QI: # fringe + illumination
+ do i = 1, n
+ out[i] = out[i]*illumscale/illum[i] - frgscale*fringe[i]
+ }
+ }
+end
+$endfor
diff --git a/noao/imred/quadred/src/ccdproc/corinput.gx b/noao/imred/quadred/src/ccdproc/corinput.gx
new file mode 100644
index 00000000..241cc34d
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/corinput.gx
@@ -0,0 +1,220 @@
+include <imhdr.h>
+include "ccdred.h"
+
+$for (sr)
+# CORINPUT -- Get an input image line, fix the bad pixels, and trim.
+# Return the corrected input line in the output array.
+
+procedure corinput$t (in, line, ccd, output, ncols)
+
+pointer in # Input IMIO pointer
+int line # Corrected output line
+pointer ccd # CCD pointer
+PIXEL output[ncols] # Output data (returned)
+int ncols # Number of output columns
+
+int i, inline
+pointer inbuf, imgl2$t()
+
+begin
+ # Determine the input line in terms of the trimmed output line.
+ if (IN_SEC(ccd) == NULL)
+ inline = IN_L1(ccd) + line - 1
+ else {
+ do i = 1, IN_NSEC(ccd) {
+ if (line < OUT_SL1(ccd,i) || line > OUT_SL2(ccd,i))
+ next
+ inline = IN_SL1(ccd,i) + line - OUT_SL1(ccd,i)
+ break
+ }
+ }
+
+ # If there are bad lines call a procedure to fix them. Otherwise
+ # read the image line directly.
+
+ if (NBADLINES(ccd) != 0)
+ call lfix$t (in, inline, Mems[BADLINES(ccd)], IM_LEN(in,1),
+ IM_LEN(in,2), NBADLINES(ccd), inbuf)
+ else
+ inbuf = imgl2$t (in, inline)
+
+ # IF there are bad columns call a procedure to fix them.
+ if (NBADCOLS(ccd) != 0)
+ call cfix$t (inline, Mems[BADCOLS(ccd)], IM_LEN(in,1),
+ IM_LEN(in,2), NBADCOLS(ccd), Mem$t[inbuf])
+
+ # Move the pixels to the output line.
+ if (IN_SEC(ccd) == NULL)
+ call amov$t (Mem$t[inbuf+IN_C1(ccd)-OUT_C1(ccd)], output, ncols)
+ else {
+ do i = 1, IN_NSEC(ccd) {
+ if (inline < IN_SL1(ccd,i) || inline > IN_SL2(ccd,i))
+ next
+ call amov$t (Mem$t[inbuf+IN_SC1(ccd,i)-OUT_C1(ccd)],
+ output[OUT_SC1(ccd,i)], OUT_SC2(ccd,i)-OUT_SC1(ccd,i)+1)
+ }
+ }
+end
+
+
+# CFIX -- Interpolate across bad columns defined in the bad column array.
+
+procedure cfix$t (line, badcols, ncols, nlines, nbadcols, data)
+
+int line # Line to be fixed
+short badcols[2, nlines, nbadcols] # Bad column array
+int ncols # Number of columns
+int nlines # Number of lines
+int nbadcols # Number of bad column regions
+PIXEL data[ncols] # Data to be fixed
+
+PIXEL val
+real del
+int i, j, col1, col2
+
+begin
+ do i = 1, nbadcols {
+ col1 = badcols[1, line, i]
+ if (col1 == 0) # No bad columns
+ return
+ col2 = badcols[2, line, i]
+ if (col1 == 1) { # Bad first column
+ val = data[col2+1]
+ do j = col1, col2
+ data[j] = val
+ } else if (col2 == ncols) { # Bad last column
+ val = data[col1-1]
+ do j = col1, col2
+ data[j] = val
+ } else { # Interpolate
+ del = (data[col2+1] - data[col1-1]) / (col2 - col1 + 2)
+ val = data[col1-1] + del
+ do j = col1, col2
+ data[j] = val + (j - col1) * del
+ }
+ }
+end
+
+
+# LFIX -- Get image line and replace bad pixels by interpolation from
+# neighboring lines. Internal buffers are used to keep the last fixed
+# line and the next good line. They are allocated with LFIXINIT and
+# freed with LFIXFREE.
+
+procedure lfix$t (im, line, badlines, ncols, nlines, nbadlines, data)
+
+pointer im # IMIO pointer
+int line # Line to be obtained and fixed
+short badlines[2,nlines,nbadlines] # Bad line region array
+int ncols # Number of columns in image
+int nlines # Number of lines in images
+int nbadlines # Number of bad line regions
+pointer data # Data line pointer (returned)
+
+real wt1, wt2
+int i, nextgood, lastgood, col1, col2
+pointer imgl2$t()
+
+pointer lastbuf, nextbuf
+common /lfixcom/ lastbuf, nextbuf, lastgood
+
+begin
+ # If this line has bad pixels replace them. Otherwise just
+ # read the line.
+
+ if (badlines[1, line, 1] != 0) {
+ # Save the last line which has already been fixed.
+ if (line != 1)
+ call amov$t (Mem$t[data], Mem$t[lastbuf], ncols)
+
+ # Determine the next line with no bad line pixels. Note that
+ # this requirement is overly strict since the bad columns
+ # may not be the same in neighboring lines.
+
+ nextgood = 0
+ do i = line+1, nlines {
+ if (badlines[1, i, 1] == 0) {
+ nextgood = i
+ break
+ }
+ }
+
+ # If the next good line is not the same as previously
+ # read the data line and store it in a buffer.
+
+ if ((nextgood != lastgood) && (nextgood != 0)) {
+ data = imgl2$t (im, nextgood)
+ call amov$t (Mem$t[data], Mem$t[nextbuf], ncols)
+ lastgood = nextgood
+ }
+
+ # Get the data line.
+ data = imgl2$t (im, line)
+
+ # Interpolate the bad columns. At the ends of the image use
+ # extension otherwise use linear interpolation.
+
+ if (line == 1) { # First line is bad
+ do i = 1, nbadlines {
+ col1 = badlines[1,line,i] - 1
+ if (col1 == -1)
+ break
+ col2 = badlines[2,line,i]
+ call amov$t (Mem$t[nextbuf+col1], Mem$t[data+col1],
+ col2-col1)
+ }
+ } else if (nextgood == 0) { # Last line is bad
+ do i = 1, nbadlines {
+ col1 = badlines[1,line,i] - 1
+ if (col1 == -1)
+ break
+ col2 = badlines[2,line,i]
+ call amov$t (Mem$t[lastbuf+col1], Mem$t[data+col1],
+ col2-col1)
+ }
+ } else { # Interpolate
+ wt1 = 1. / (nextgood - line + 1)
+ wt2 = 1. - wt1
+ do i = 1, nbadlines {
+ col1 = badlines[1,line,i] - 1
+ if (col1 == -1)
+ break
+ col2 = badlines[2,line,i] - 1
+ call awsu$t (Mem$t[nextbuf+col1], Mem$t[lastbuf+col1],
+ Mem$t[data+col1], col2-col1+1, wt1, wt2)
+ }
+ }
+ } else
+ data = imgl2$t (im, line)
+end
+
+
+# LFIXINIT -- Allocate internal buffers.
+
+procedure lfixinit$t (im)
+
+pointer im # IMIO pointer
+
+int lastgood
+pointer lastbuf, nextbuf
+common /lfixcom/ lastbuf, nextbuf, lastgood
+
+begin
+ call malloc (lastbuf, IM_LEN(im,1), TY_PIXEL)
+ call malloc (nextbuf, IM_LEN(im,1), TY_PIXEL)
+ lastgood=0
+end
+
+# LFIXFREE -- Free memory when the last line has been obtained.
+
+procedure lfixfree$t ()
+
+int lastgood
+pointer lastbuf, nextbuf
+common /lfixcom/ lastbuf, nextbuf, lastgood
+
+begin
+ call mfree (lastbuf, TY_PIXEL)
+ call mfree (nextbuf, TY_PIXEL)
+end
+$endfor
diff --git a/noao/imred/quadred/src/ccdproc/doc/ccdproc.hlp b/noao/imred/quadred/src/ccdproc/doc/ccdproc.hlp
new file mode 100644
index 00000000..e942a299
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/doc/ccdproc.hlp
@@ -0,0 +1,778 @@
+.help ccdproc Aug01 noao.imred.quadred
+.ih
+NAME
+ccdproc -- Process CCD images
+.ih
+SYNOPSIS
+This is the main processing task for CCD data in single image or
+\fBquadformat\fR image formats.
+.ih
+USAGE
+ccdproc images
+.ih
+PARAMETERS
+.ls images
+List of input CCD images to process. The list may include processed
+images and calibration images.
+.le
+.ls output = ""
+List of output images. If no list is given then the processing will replace
+the input images with the processed images. If a list is given it must
+match the input image list. \fINote that any dependent calibration images
+still be processed in-place with optional backup.\fR
+.le
+.ls ccdtype = ""
+CCD image type to select from the input image list. If no type is given
+then all input images will be selected. The recognized types are described
+in \fBccdtypes\fR.
+.le
+.ls max_cache = 0
+Maximum image caching memory (in Mbytes). If there is sufficient memory
+the calibration images, such as zero level, dark count, and flat fields,
+will be cached in memory when processing many input images. This
+reduces the disk I/O and makes the task run a little faster. If the
+value is zero image caching is not used.
+.le
+.ls noproc = no
+List processing steps only?
+.le
+
+.ce
+PROCESSING SWITCHES
+.ls fixpix = yes
+Fix bad CCD lines and columns by linear interpolation from neighboring
+lines and columns? If yes then a bad pixel mask, image, or file must be
+specified.
+.le
+.ls overscan = yes
+Apply overscan or prescan bias correction? If yes then the overscan
+image section and the readout axis must be specified.
+.le
+.ls trim = yes
+Trim the image of the overscan region and bad edge lines and columns?
+If yes then the trim section must be specified.
+.le
+.ls zerocor = yes
+Apply zero level correction? If yes a zero level image must be specified.
+.le
+.ls darkcor = yes
+Apply dark count correction? If yes a dark count image must be specified.
+.le
+.ls flatcor = yes
+Apply flat field correction? If yes flat field images must be specified.
+.le
+.ls illumcor = no
+Apply iillumination correction? If yes iillumination images must be specified.
+.le
+.ls fringecor = no
+Apply fringe correction? If yes fringe images must be specified.
+.le
+.ls readcor = no
+Convert zero level images to readout correction images? If yes then
+zero level images are averaged across the readout axis to form one
+dimensional zero level readout correction images.
+.le
+.ls scancor = no
+Convert zero level, dark count and flat field images to scan mode flat
+field images? If yes then the form of scan mode correction is specified by
+the parameter \fIscantype\fR.
+.le
+
+.ce
+PROCESSING PARAMETERS
+.ls readaxis = "line"
+Read out axis specified as "line" or "column".
+.le
+.ls fixfile
+Bad pixel mask, image, or file. If "image" is specified then the name is
+specified in the image header or instrument translation file. If "BPM" is
+specified then the standard BPM image header keyword defines a bad pixel
+mask. A bad pixel mask is a compact format (".pl" extension) with zero
+values indicating good pixels and non-zero values indicating bad pixels. A
+bad pixel image is a regular image in which zero values are good pixels and
+non-zero values are bad pixels. A bad pixel file specifies bad pixels or
+rectangular bad pixel regions as described later. The direction of
+interpolation is determined by the mask value with a value of two
+interpolating across columns, a value of three interpolating across lines,
+and any other non-zero value interpolating along the narrowest dimension.
+.le
+.ls biassec
+Overscan bias strip image section. If "image" is specified then the overscan
+bias section is specified in the image header or instrument translation file.
+Only the part of the bias section along the readout axis is used. The
+length of the bias region fit is defined by the trim section. If one
+wants to limit the region of the overscan used in the fit to be less
+than that of the trim section then the sample region parameter,
+\fIsample\fR, should be used. It is an error if no section or the
+whole image is specified.
+.le
+.ls trimsec
+Image section for trimming. If "image" is specified then the trim image
+section is specified in the image header or instrument translation file.
+However, for \fIquadformat\fR data this parameter is not used and the trim
+sections are assumed to be in the image header.
+.le
+.ls zero = ""
+Zero level calibration image. The zero level image may be one or two
+dimensional. The CCD image type and subset are not checked for these
+images and they take precedence over any zero level calibration images
+given in the input list.
+.le
+.ls dark = ""
+Dark count calibration image. The CCD image type and subset are not checked
+for these images and they take precedence over any dark count calibration
+images given in the input list.
+.le
+.ls flat = ""
+Flat field calibration images. The flat field images may be one or
+two dimensional. The CCD image type is not checked for these
+images and they take precedence over any flat field calibration images given
+in the input list. The flat field image with the same subset as the
+input image being processed is selected.
+.le
+.ls illum = ""
+Iillumination correction images. The CCD image type is not checked for these
+images and they take precedence over any iillumination correction images given
+in the input list. The iillumination image with the same subset as the
+input image being processed is selected.
+.le
+.ls fringe = ""
+Fringe correction images. The CCD image type is not checked for these
+images and they take precedence over any fringe correction images given
+in the input list. The fringe image with the same subset as the
+input image being processed is selected.
+.le
+.ls minreplace = 1.
+When processing flat fields, pixel values below this value (after
+all other processing such as overscan, zero, and dark corrections) are
+replaced by this value. This allows flat fields processed by \fBccdproc\fR
+to be certain to avoid divide by zero problems when applied to object
+images.
+.le
+.ls scantype = "shortscan"
+Type of scan format used in creating the CCD images. The modes are:
+.ls "shortscan"
+The CCD is scanned over a number of lines and then read out as a regular
+two dimensional image. In this mode unscanned zero level, dark count and
+flat fields are numerically scanned to form scanned flat fields comparable
+to the observations.
+.le
+.ls "longscan"
+In this mode the CCD is clocked and read out continuously to form a long
+strip. Flat fields are averaged across the readout axis to
+form a one dimensional flat field readout correction image. This assumes
+that all recorded image lines are clocked over the entire active area of the
+CCD.
+.le
+.le
+.ls nscan
+Number of object scan readout lines used in short scan mode. This parameter
+is used when the scan type is "shortscan" and the number of scan lines
+cannot be determined from the object image header (using the keyword
+nscanrows or it's translation).
+.le
+
+
+.ce
+OVERSCAN FITTING PARAMETERS
+
+There are two types of overscan (or prescan) determinations. One determines
+a independent overscan value for each line and is only available for a
+\fIreadaxis\fR of 1. The other averages the overscan along the readout
+direction to make an overscan vector, fits a smoothing function to the vector,
+and then evaluate and then evaluates the smooth function at each readout
+line or column. The line-by-line determination only uses the
+\fIfunction\fR parameter and the smoothing determinations uses all
+the following parameters.
+
+.ls function = "legendre"
+Line-by-line determination of the overscan is specified by:
+
+.nf
+ mean - the mean of the biassec columns at each line
+ median - the median of the biassec columns at each line
+ minmax - the mean at each line with the min and max excluded
+.fi
+
+The smoothed overscan vector may be fit by one of the functions:
+
+.nf
+ legendre - legendre polynomial
+ chebyshev - chebyshev polynomial
+ spline1 - linear spline
+ spline3 - cubic spline
+.fi
+.le
+.ls order = 1
+Number of polynomial terms or spline pieces in the overscan fit.
+.le
+.ls sample = "*"
+Sample points to use in the overscan fit. The string "*" specified all
+points otherwise an \fBicfit\fR range string is used.
+.le
+.ls naverage = 1
+Number of points to average or median to form fitting points. Positive
+numbers specify averages and negative numbers specify medians.
+.le
+.ls niterate = 1
+Number of rejection iterations to remove deviant points from the overscan fit.
+If 0 then no points are rejected.
+.le
+.ls low_reject = 3., high_reject = 3.
+Low and high sigma rejection factors for rejecting deviant points from the
+overscan fit.
+.le
+.ls grow = 0.
+One dimensional growing radius for rejection of neighbors to deviant points.
+.le
+.ls interactive = no
+Fit the overscan vector interactively? If yes and the overscan function type
+is one of the \fBicfit\fR types then the average overscan vector is fit
+interactively using the \fBicfit\fR package. If no then the fitting parameters
+given below are used.
+.le
+
+The parameters \fIverbose\fR, \fIlogfile\fR, and \fIbackup\fR default to
+the package parameters but may be specified to override the package
+values. This is used by the \fBquadproc\fR script task. These parameters
+are described in the help topic "quadred.package".
+.ih
+DESCRIPTION
+\fBCcdproc\fR processes CCD images to correct and calibrate for
+detector defects, readout bias, zero level bias, dark counts,
+response, iillumination, and fringing. It also trims unwanted
+lines and columns and changes the pixel datatype. It is efficient
+and easy to use; all one has to do is set the parameters and then
+begin processing the images. The task takes care of most of the
+record keeping and automatically does the prerequisite processing
+of calibration images. Beneath this simplicity there is much that
+is going on. In this section a simple description of the usage is
+given. The following sections present more detailed discussions
+on the different operations performed and the order and logic
+of the processing steps. For a user's guide to the \fBccdred\fR
+package see \fBguide\fR. Much of the ease of use derives from using
+information in the image header. If this information is missing
+see section 13.
+
+One begins by setting the task parameters. There are many parameters
+but they may be easily reviewed and modified using the task \fBeparam\fR.
+The input CCD images to be processed are given as an image list.
+Previously processed images are ignored and calibration images are
+recognized, provided the CCD image types are in the image header (see
+\fBinstruments\fR and \fBccdtypes\fR). Therefore it is permissible to
+use simple image templates such as "*.imh". The \fIccdtype\fR parameter
+may be used to select only certain types of CCD images to process
+(see \fBccdtypes\fR).
+
+The processing operations are selected by boolean (yes/no) parameters.
+Because calibration images are recognized and processed appropriately,
+the processing operations for object images should be set.
+Any combination of operations may be specified and the operations are
+performed simultaneously. While it is possible to do operations in
+separate steps this is much less efficient. Two of the operation
+parameters apply only to zero level and flat field images. These
+are used for certain types of CCDs and modes of operation.
+
+The processing steps selected have related parameters which must be
+set. These are things like image sections defining the overscan and
+trim regions and calibration images. There are a number of parameters
+used for fitting the overscan or prescan bias section. These are
+parameters used by the standard IRAF curve fitting package \fBicfit\fR.
+The parameters are described in more detail in the following sections.
+
+In addition to the task parameters there are package parameters
+which affect \fBccdproc\fR. These include the instrument and subset
+files, the text and plot log files, the output pixel datatype,
+the amount of memory available for calibration image caching,
+the verbose parameter for logging to the terminal, and the backup
+prefix. These are described in \fBccdred\fR.
+
+Calibration images are specified by task parameters and/or in the
+input image list. If more than one calibration image is specified
+then the first one encountered is used and a warning is issued for the
+extra images. Calibration images specified by
+task parameters take precedence over calibration images in the input list.
+These images also need not have a CCD image type parameter since the task
+parameter identifies the type of calibration image. This method is
+best if there is only one calibration image for all images
+to be processed. This is almost always true for zero level and dark
+count images. If no calibration image is specified by task parameter
+then calibration images in the input image list are identified and
+used. This requires that the images have CCD image types recognized
+by the package. This method is useful if one may simply say "*.imh"
+as the image list to process all images or if the images are broken
+up into groups, in "@" files for example, each with their own calibration
+frames.
+
+When an input image is processed the task first determines the processing
+parameters and calibration images. If a requested operation has been
+done it is skipped and if all requested operations have been completed then
+no processing takes place. When it determines that a calibration image
+is required it checks for the image from the task parameter and then
+for a calibration image of the proper type in the input list.
+
+Having
+selected a calibration image it checks if it has been processed by
+looking for the image header flag CCDPROC. If it is not present then
+the calibration image is processed. When any image has been processed
+the CCDPROC flag is added. For images processed directly by \fBccdproc\fR
+the individual processing flags are checked even if the CCDPROC flag is
+present. However, the automatic processing of the calibration images is
+only done if the CCDPROC flag is absent! This is to make the task more
+efficient by not having to check every flag for every calibration image
+for every input image. Thus, if additional processing
+steps are added after images have been partially reduced then input images
+will be processed for the new steps but calibration images will not be
+processed automatically.
+
+After the calibration images have been identified, and processed if
+necessary, the images may be cached in memory. This is done when there
+are more than two input images (it is actually less efficient to
+cache the calibration images for one or two input images) and the parameter
+\fImax_cache\fR is greater than zero. When caching, as many calibration
+images as allowed by the specified memory are read into memory and
+kept there for all the input images. Cached images are, therefore,
+only read once from disk which reduces the amount of disk I/O. This
+makes a modest decrease in the execution time. It is not dramatic
+because the actual processing is fairly CPU intensive.
+
+Once the processing parameters and calibration images have been determined
+the input image is processed for all the desired operations in one step;
+i.e. there are no intermediate results or images. This makes the task
+efficient. If a matching list of output images is given then the processed
+image is written to the specified output image name. If no output image
+list is given then the corrected image is output as a temporary image until
+the entire image has been processed. When the image has been completely
+processed then the original image is deleted (or renamed using the
+specified backup prefix) and the corrected image replaces the original
+image. Using a temporary image protects the data in the event of an abort
+or computer failure. Keeping the original image name eliminates much of
+the record keeping and the need to generate new image names.
+.sh
+1. Fixpix
+Regions of bad lines and columns may be replaced by linear
+interpolation from neighboring lines and columns when the parameter
+\fIfixpix\fR is set. This algorithm is the same as used in the
+task \fBfixpix\fR. The bad pixels may be specified by a pixel mask,
+an image, or a text file. For the mask or image, values of zero indicate
+good pixels and other values indicate bad pixels to be replaced.
+
+The text file consists of lines with four fields, the starting and
+ending columns and the starting and ending lines. Any number of
+regions may be specified. Comment lines beginning with the character
+'#' may be included. The description applies directly to the input
+image (before trimming) so different files are needed for previously
+trimmed or subsection readouts. The data in this file is internally
+turned into the same description as a bad pixel mask with values of
+two for regions which are narrower or equal across the columns and
+a value of three for regions narrower across lines.
+
+The direction of interpolation is determined from the values in the
+mask, image, or the converted text file. A value of two interpolates
+across columns, a value of three interpolates across lines, and any
+other value interpolates across the narrowest dimension of bad pixels
+and using column interpolation if the two dimensions are equal.
+
+The bad pixel description may be specified explicitly with the parameter
+\fIfixfile\fR or indirectly if the parameter has the value "image". In the
+latter case the instrument file must contain the name of the file.
+.sh
+2. Overscan
+If an overscan or prescan correction is specified (\fIoverscan\fR
+parameter) then the image section (\fIbiassec\fR parameter) defines
+the overscan region.
+
+There are two types of overscan (or prescan) determinations. One determines
+a independent overscan value for each line and is only available for a
+\fIreadaxis\fR of 1. The other averages the overscan along the readout
+direction to make an overscan vector, fits a smoothing function to the vector,
+and then evaluate and then evaluates the smooth function at each readout
+line or column.
+
+The line-by-line determination provides an mean, median, or
+mean with the minimum and maximum values excluded. The median
+is lowest value of the middle two when the number of overscan columns
+is even rather than the mean.
+
+The smoothed overscan vector determination uses the \fBicfit\fR options
+including interactive fitting. The fitting function is generally either a
+constant (polynomial of 1 term) or a high order function which fits the
+large scale shape of the overscan vector. Bad pixel rejection is also
+available to eliminate cosmic ray events. The function fitting may be done
+interactively using the standard \fBicfit\fR iteractive graphical curve
+fitting tool. Regardless of whether the fit is done interactively, the
+overscan vector and the fit may be recorded for later review in a metacode
+plot file named by the parameter \fIccdred.plotfile\fR. The mean value of
+the bias function is also recorded in the image header and log file.
+.sh
+3. Trim
+When the parameter \fItrim\fR is set the input image will be trimmed to
+the image section given by the parameter \fItrimsec\fR. This trim
+should, of course, be the same as that used for the calibration images.
+.sh
+4. Zerocor
+After the readout bias is subtracted, as defined by the overscan or prescan
+region, there may still be a zero level bias. This level may be two
+dimensional or one dimensional (the same for every readout line). A
+zero level calibration is obtained by taking zero length exposures;
+generally many are taken and combined. To apply this zero
+level calibration the parameter \fIzerocor\fR is set. In addition if
+the zero level bias is only readout dependent then the parameter \fIreadcor\fR
+is set to reduce two dimensional zero level images to one dimensional
+images. The zero level images may be specified by the parameter \fIzero\fR
+or given in the input image list (provided the CCD image type is defined).
+
+When the zero level image is needed to correct an input image it is checked
+to see if it has been processed and, if not, it is processed automatically.
+Processing of zero level images consists of bad pixel replacement,
+overscan correction, trimming, and averaging to one dimension if the
+readout correction is specified.
+.sh
+5. Darkcor
+Dark counts are subtracted by scaling a dark count calibration image to
+the same exposure time as the input image and subtracting. The
+exposure time used is the dark time which may be different than the
+actual integration or exposure time. A dark count calibration image is
+obtained by taking a very long exposure with the shutter closed; i.e.
+an exposure with no light reaching the detector. The dark count
+correction is selected with the parameter \fIdarkcor\fR and the dark
+count calibration image is specified either with the parameter
+\fIdark\fR or as one of the input images. The dark count image is
+automatically processed as needed. Processing of dark count images
+consists of bad pixel replacement, overscan and zero level correction,
+and trimming.
+.sh
+6. Flatcor
+The relative detector pixel response is calibrated by dividing by a
+scaled flat field calibration image. A flat field image is obtained by
+exposure to a spatially uniform source of light such as an lamp or
+twilight sky. Flat field images may be corrected for the spectral
+signature in spectroscopic images (see \fBresponse\fR and
+\fBapnormalize\fR), or for iillumination effects (see \fBmkillumflat\fR
+or \fBmkskyflat\fR). For more on flat fields and iillumination corrections
+see \fBflatfields\fR. The flat field response is dependent on the
+wavelength of light so if different filters or spectroscopic wavelength
+coverage are used a flat field calibration for each one is required.
+The different flat fields are automatically selected by a subset
+parameter (see \fBsubsets\fR).
+
+Flat field calibration is selected with the parameter \fBflatcor\fR
+and the flat field images are specified with the parameter \fBflat\fR
+or as part of the input image list. The appropriate subset is automatically
+selected for each input image processed. The flat field image is
+automatically processed as needed. Processing consists of bad pixel
+replacement, overscan subtraction, zero level subtraction, dark count
+subtraction, and trimming. Also if a scan mode is used and the
+parameter \fIscancor\fR is specified then a scan mode correction is
+applied (see below). The processing also computes the mean of the
+flat field image which is used later to scale the flat field before
+division into the input image. For scan mode flat fields the ramp
+part is included in computing the mean which will affect the level
+of images processed with this flat field. Note that there is no check for
+division by zero in the interest of efficiency. If division by zero
+does occur a fatal error will occur. The flat field can be fixed by
+replacing small values using a task such as \fBimreplace\fR or
+during processing using the \fIminreplace\fR parameter. Note that the
+\fIminreplace\fR parameter only applies to flat fields processed by
+\fBccdproc\fR.
+.sh
+7. Illumcor
+CCD images processed through the flat field calibration may not be
+completely flat (in the absence of objects). In particular, a blank
+sky image may still show gradients. This residual nonflatness is called
+the iillumination pattern. It may be introduced even if the detector is
+uniformly illuminated by the sky because the flat field lamp
+iillumination may be nonuniform. The iillumination pattern is found from a
+blank sky, or even object image, by heavily smoothing and rejecting
+objects using sigma clipping. The iillumination calibration image is
+divided into the data being processed to remove the iillumination
+pattern. The iillumination pattern is a function of the subset so there
+must be an iillumination correction image for each subset to be
+processed. The tasks \fBmkillumcor\fR and \fBmkskycor\fR are used to
+create the iillumination correction images. For more on iillumination
+corrections see \fBflatfields\fR.
+
+An alternative to treating the iillumination correction as a separate
+operation is to combine the flat field and iillumination correction
+into a corrected flat field image before processing the object
+images. This will save some processing time but does require creating
+the flat field first rather than correcting the images at the same
+time or later. There are two methods, removing the large scale
+shape of the flat field and combining a blank sky image iillumination
+with the flat field. These methods are discussed further in the
+tasks which create them; \fBmkillumcor\fR and \fBmkskycor\fR.
+.sh
+8. Fringecor
+There may be a fringe pattern in the images due to the night sky lines.
+To remove this fringe pattern a blank sky image is heavily smoothed
+to produce an iillumination image which is then subtracted from the
+original sky image. The residual fringe pattern is scaled to the
+exposure time of the image to be fringe corrected and then subtracted.
+Because the intensity of the night sky lines varies with time an
+additional scaling factor may be given in the image header.
+The fringe pattern is a function of the subset so there must be
+a fringe correction image for each subset to be processed.
+The task \fBmkfringecor\fR is used to create the fringe correction images.
+.sh
+9. Readcor
+If a zero level correction is desired (\fIzerocor\fR parameter)
+and the parameter \fIreadcor\fR is yes then a single zero level
+correction vector is applied to each readout line or column. Use of a
+readout correction rather than a two dimensional zero level image
+depends on the nature of the detector or if the CCD is operated in
+longscan mode (see below). The readout correction is specified by a
+one dimensional image (\fIzero\fR parameter) and the readout axis
+(\fIreadaxis\fR parameter). If the zero level image is two dimensional
+then it is automatically processed to a one dimensional image by
+averaging across the readout axis. Note that this modifies the zero
+level calibration image.
+.sh
+10. Scancor
+CCD detectors may be operated in several modes in astronomical
+applications. The most common is as a direct imager where each pixel
+integrates one point in the sky or spectrum. However, the design of most CCD's
+allows the sky to be scanned across the CCD while shifting the
+accumulating signal at the same rate. \fBCcdproc\fR provides for two
+scanning modes called "shortscan" and "longscan". The type of scan
+mode is set with the parameter \fIscanmode\fR.
+
+In "shortscan" mode the detector is scanned over a specified number of
+lines (not necessarily at sideral rates). The lines that scroll off the
+detector during the integration are thrown away. At the end of the
+integration the detector is read out in the same way as an unscanned
+observation. The advantage of this mode is that the small scale, zero
+level, dark count and flat field responses are averaged in one dimension
+over the number of lines scanned. A zero level, dark count or flat field may be
+observed in the same way in which case there is no difference in the
+processing from unscanned imaging and the parameter \fIscancor\fR may be
+no. If it is yes, though, checking is done to insure that the calibration
+image used has the same number of scan lines as the object being
+processed. However, one obtains an increase in the statistical accuracy of
+if they are not scanned during the observation but
+digitally scanned during the processing. In shortscan mode with
+\fIscancor\fR set to yes, zero level, dark count and flat field images are
+digitally scanned, if needed, by the same number of scan lines as the
+object. The number of scan lines is determined from the object image
+header using the keyword nscanrow (or it's translation). If not found the
+object is assumed to have been scanned with the value given by the
+\fInscan\fR parameter. Zero, dark and flat calibration images are assumed
+to be unscanned if the header keyword is not found.
+
+If a scanned zero level, dark count or flat field image is not found
+matching the object then one may be created from the unscanned calibration
+image. The image will have the root name of the unscanned image with an
+extension of the number of scan rows; i.e. Flat1.32 is created from Flat1
+with a digital scanning of 32 lines.
+
+In "longscan" mode the detector is continuously read out to produce an
+arbitrarily long strip. Provided data which has not passed over the entire
+detector is thrown away, the zero level, dark count, and flat field
+corrections will be one dimensional. If \fIscancor\fR is specified and the
+scan mode is "longscan" then a one dimensional zero level, dark count, and
+flat field correction will be applied.
+.sh
+11. Processing Steps
+The following describes the steps taken by the task. This detailed
+outline provides the most detailed specification of the task.
+
+.ls 5 (1)
+An image to be processed is first checked that it is of the specified
+CCD image type. If it is not the desired type then go on to the next image.
+.le
+.ls (2)
+A temporary output image is created of the specified pixel data type
+(\fBccdred.pixeltype\fR). The header parameters are copied from the
+input image.
+.le
+.ls (3)
+If trimming is specified and the image has not been trimmed previously,
+the trim section is determined.
+.le
+.ls (4)
+If bad pixel replacement is specified and this has not been done
+previously, the bad pixel file is determined either from the task
+parameter or the instrument translation file. The bad pixel regions
+are read. If the image has been trimmed previously and the bad pixel
+file contains the word "untrimmed" then the bad pixel coordinates are
+translated to those of the trimmed image.
+.le
+.ls (5)
+If an overscan correction is specified and this correction has not been
+applied, the overscan section is averaged along the readout axis. If
+trimming is to be done the overscan section is trimmed to the same
+limits. A function is fit either interactively or noninteractively to
+the overscan vector. The function is used to produce the overscan
+vector to be subtracted from the image. This is done in real
+arithmetic.
+.le
+.ls (6)
+If the image is a zero level image go to processing step 12.
+If a zero level correction is desired and this correction has not been
+performed, find the zero level calibration image. If the zero level
+calibration image has not been processed it is processed at this point.
+This is done by going to processing step 1 for this image. After the
+calibration image has been processed, processing of the input image
+continues from this point.
+The processed calibration image may be
+cached in memory if it has not been previously and if there is enough memory.
+.le
+.ls (7)
+If the image is a dark count image go to processing step 12.
+If a dark count correction is desired and this correction has not been
+performed, find the dark count calibration image. If the dark count
+calibration image has not been processed it is processed at this point.
+This is done by going to processing step 1 for this image. After the
+calibration image has been processed, processing of the input image
+continues from this point. The ratio of the input image dark time
+to the dark count image dark time is determined to be multiplied with
+each pixel of the dark count image before subtracting from the input
+image.
+The processed calibration image may be
+cached in memory if it has not been previously and if there is enough memory.
+.le
+.ls (8)
+If the image is a flat field image go to processing step 12. If a flat
+field correction is desired and this correction has not been performed,
+find the flat field calibration image of the appropriate subset. If
+the flat field calibration image has not been processed it is processed
+at this point. This is done by going to processing step 1 for this
+image. After the calibration image has been processed, processing of
+the input image continues from this point. The mean of the image
+is determined from the image header to be used for scaling. If no
+mean is found then a unit scaling is used.
+The processed calibration image may be
+cached in memory if it has not been previously and if there is enough memory.
+.le
+.ls (9)
+If the image is an iillumination image go to processing step 12. If an
+iillumination correction is desired and this correction has not been performed,
+find the iillumination calibration image of the appropriate subset.
+The iillumination image must have the "mkillum" processing flag or the
+\fBccdproc\fR will abort with an error. The mean of the image
+is determined from the image header to be used for scaling. If no
+mean is found then a unit scaling is used. The processed calibration
+image may be
+cached in memory if it has not been previously and there is enough memory.
+.le
+.ls (10)
+If the image is a fringe image go to processing step 12. If a fringe
+correction is desired and this correction has not been performed,
+find the fringe calibration image of the appropriate subset.
+The iillumination image must have the "mkfringe" processing flag or the
+\fBccdproc\fR will abort with an error. The ratio of the input
+image exposure time to the fringe image exposure time is determined.
+If there is a fringe scaling in the image header then this factor
+is multiplied by the exposure time ratio. This factor is used
+for scaling. The processed calibration image may be
+cached in memory if it has not been previously and there is enough memory.
+.le
+.ls (11)
+If there are no processing operations flagged, delete the temporary output
+image, which has been opened but not used, and go to 14.
+.le
+.ls (12)
+The input image is processed line by line with trimmed lines ignored.
+A line of the input image is read. Bad pixel replacement and trimming
+is applied to the image. Image lines from the calibration images
+are read from disk or the image cache. If the calibration is one
+dimensional (such as a readout zero
+level correction or a longscan flat field correction) then the image
+vector is read only once. Note that IRAF image I/O is buffered for
+efficiency and accessing a line at a time does not mean that image
+lines are read from disk a line at a time. Given the input line, the
+calibration images, the overscan vector, and the various scale factors
+a special data path for each combination of corrections is used to
+perform all the processing in the most efficient manner. If the
+image is a flat field any pixels less than the \fIminreplace\fR
+parameter are replaced by that minimum value. Also a mean is
+computed for the flat field and stored as the CCDMEAN keyword and
+the time, in a internal format, when this value was calculated is stored
+in the CCDMEANT keyword. The time is checked against the image modify
+time to determine if the value is valid or needs to be recomputed.
+.le
+.ls (13)
+The input image is deleted or renamed to a backup image. The temporary
+output image is renamed to the input image name.
+.le
+.ls (14)
+If the image is a zero level image and the readout correction is specified
+then it is averaged to a one dimensional readout correction.
+.le
+.ls (15)
+If the image is a zero level, dark count, or flat field image and the scan
+mode correction is specified then the correction is applied. For shortscan
+mode a modified two dimensional image is produced while for longscan mode a
+one dimensional average image is produced.
+.le
+.ls (16)
+The processing is completed and either the next input image is processed
+beginning at step 1 or, if it is a calibration image which is being
+processed for an input image, control returns to the step which initiated
+the calibration image processing.
+.le
+.sh
+12. Processing Arithmetic
+The \fBccdproc\fR task has two data paths, one for real image pixel datatypes
+and one for short integer pixel datatype. In addition internal arithmetic
+is based on the rules of FORTRAN. For efficiency there is
+no checking for division by zero in the flat field calibration.
+The following rules describe the processing arithmetic and data paths.
+
+.ls (1)
+If the input, output, or any calibration image is of type real the
+real data path is used. This means all image data is converted to
+real on input. If all the images are of type short all input data
+is kept as short integers. Thus, if all the images are of the same type
+there is no datatype conversion on input resulting in greater
+image I/O efficiency.
+.le
+.ls (2)
+In the real data path the processing arithmetic is always real and,
+if the output image is of short pixel datatype, the result
+is truncated.
+.le
+.ls (3)
+The overscan vector and the scale factors for dark count, flat field,
+iillumination, and fringe calibrations are always of type real. Therefore,
+in the short data path any processing which includes these operations
+will be coerced to real arithmetic and the result truncated at the end
+of the computation.
+.le
+.sh
+13. In the Absence of Image Header Information
+The tasks in the \fBccdred\fR package are most convenient to use when
+the CCD image type, subset, and exposure time are contained in the
+image header. The ability to redefine which header parameters contain
+this information makes it possible to use the package at many different
+observatories (see \fBinstruments\fR). However, in the absence of any
+image header information the tasks may still be used effectively.
+There are two ways to proceed. One way is to use \fBccdhedit\fR
+to place the information in the image header.
+
+The second way is to specify the processing operations more explicitly
+than is needed when the header information is present. The parameter
+\fIccdtype\fR is set to "" or to "none". The calibration images are
+specified explicitly by task parameter since they cannot be recognized
+in the input list. Only one subset at a time may be processed.
+
+If dark count and fringe corrections are to be applied the exposure
+times must be added to all the images. Alternatively, the dark count
+and fringe images may be scaled explicitly for each input image. This
+works because the exposure times default to 1 if they are not given in
+the image header.
+.ih
+EXAMPLES
+The user's \fBguide\fR presents a tutorial in the use of this task.
+
+1. In general all that needs to be done is to set the task parameters
+and enter
+
+ cl> ccdproc *.imh &
+
+This will run in the background and process all images which have not
+been processed previously.
+.ih
+SEE ALSO
+package, quadformat, instruments, ccdtypes, flatfields, icfit, ccdred,
+guide, mkillumcor, mkskycor, mkfringecor
+.endhelp
diff --git a/noao/imred/quadred/src/ccdproc/doproc.x b/noao/imred/quadred/src/ccdproc/doproc.x
new file mode 100644
index 00000000..909c6f12
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/doproc.x
@@ -0,0 +1,29 @@
+include "ccdred.h"
+
+# DOPROC -- Call the appropriate processing procedure.
+#
+# There are four data type paths depending on the readout axis and
+# the calculation data type.
+
+procedure doproc (ccd)
+
+pointer ccd # CCD processing structure
+
+begin
+ switch (READAXIS (ccd)) {
+ case 1:
+ switch (CALCTYPE (ccd)) {
+ case TY_SHORT:
+ call proc1s (ccd)
+ default:
+ call proc1r (ccd)
+ }
+ case 2:
+ switch (CALCTYPE (ccd)) {
+ case TY_SHORT:
+ call proc2s (ccd)
+ default:
+ call proc2r (ccd)
+ }
+ }
+end
diff --git a/noao/imred/quadred/src/ccdproc/generic/ccdred.h b/noao/imred/quadred/src/ccdproc/generic/ccdred.h
new file mode 100644
index 00000000..ef41f592
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/generic/ccdred.h
@@ -0,0 +1,155 @@
+# CCDRED Data Structures and Definitions
+
+# The CCD structure: This structure is used to communicate processing
+# parameters between the package procedures. It contains pointers to
+# data, calibration image IMIO pointers, scaling parameters, and the
+# correction flags. The corrections flags indicate which processing
+# operations are to be performed. The subsection parameters do not
+# include a step size. A step size is assumed. If arbitrary subsampling
+# is desired this would be the next generalization.
+
+define LEN_CCD 75 # Length of CCD structure
+
+# CCD data coordinates
+define CCD_C1 Memi[$1] # CCD starting column
+define CCD_C2 Memi[$1+1] # CCD ending column
+define CCD_L1 Memi[$1+2] # CCD starting line
+define CCD_L2 Memi[$1+3] # CCD ending line
+
+# Input data
+define IN_IM Memi[$1+4] # Input image pointer
+define IN_C1 Memi[$1+5] # Input data starting column
+define IN_C2 Memi[$1+6] # Input data ending column
+define IN_L1 Memi[$1+7] # Input data starting line
+define IN_L2 Memi[$1+8] # Input data ending line
+define IN_NSEC Memi[$1+71] # Number of input pieces
+define IN_SEC Memi[$1+72] # Pointer to sections (c1,c2,l1,l2)xn
+
+# Output data
+define OUT_IM Memi[$1+9] # Output image pointer
+define OUT_C1 Memi[$1+10] # Output data starting column
+define OUT_C2 Memi[$1+11] # Output data ending column
+define OUT_L1 Memi[$1+12] # Output data starting line
+define OUT_L2 Memi[$1+13] # Output data ending line
+define OUT_SEC Memi[$1+73] # Pointer to sections (c1,c2,l1,l2)xn
+
+# Zero level data
+define ZERO_IM Memi[$1+14] # Zero level image pointer
+define ZERO_C1 Memi[$1+15] # Zero level data starting column
+define ZERO_C2 Memi[$1+16] # Zero level data ending column
+define ZERO_L1 Memi[$1+17] # Zero level data starting line
+define ZERO_L2 Memi[$1+18] # Zero level data ending line
+
+# Dark count data
+define DARK_IM Memi[$1+19] # Dark count image pointer
+define DARK_C1 Memi[$1+20] # Dark count data starting column
+define DARK_C2 Memi[$1+21] # Dark count data ending column
+define DARK_L1 Memi[$1+22] # Dark count data starting line
+define DARK_L2 Memi[$1+23] # Dark count data ending line
+
+# Flat field data
+define FLAT_IM Memi[$1+24] # Flat field image pointer
+define FLAT_C1 Memi[$1+25] # Flat field data starting column
+define FLAT_C2 Memi[$1+26] # Flat field data ending column
+define FLAT_L1 Memi[$1+27] # Flat field data starting line
+define FLAT_L2 Memi[$1+28] # Flat field data ending line
+
+# Illumination data
+define ILLUM_IM Memi[$1+29] # Illumination image pointer
+define ILLUM_C1 Memi[$1+30] # Illumination data starting column
+define ILLUM_C2 Memi[$1+31] # Illumination data ending column
+define ILLUM_L1 Memi[$1+32] # Illumination data starting line
+define ILLUM_L2 Memi[$1+33] # Illumination data ending line
+
+# Fringe data
+define FRINGE_IM Memi[$1+34] # Fringe image pointer
+define FRINGE_C1 Memi[$1+35] # Fringe data starting column
+define FRINGE_C2 Memi[$1+36] # Fringe data ending column
+define FRINGE_L1 Memi[$1+37] # Fringe data starting line
+define FRINGE_L2 Memi[$1+38] # Fringe data ending line
+
+# Trim section
+define TRIM_C1 Memi[$1+39] # Trim starting column
+define TRIM_C2 Memi[$1+40] # Trim ending column
+define TRIM_L1 Memi[$1+41] # Trim starting line
+define TRIM_L2 Memi[$1+42] # Trim ending line
+
+# Bias section
+define BIAS_C1 Memi[$1+43] # Bias starting column
+define BIAS_C2 Memi[$1+44] # Bias ending column
+define BIAS_L1 Memi[$1+45] # Bias starting line
+define BIAS_L2 Memi[$1+46] # Bias ending line
+define BIAS_SEC Memi[$1+74] # Multiple bias sections
+
+define READAXIS Memi[$1+47] # Read out axis (1=cols, 2=lines)
+define CALCTYPE Memi[$1+48] # Calculation data type
+define NBADCOLS Memi[$1+49] # Number of column interpolation regions
+define BADCOLS Memi[$1+50] # Pointer to col interpolation regions
+define NBADLINES Memi[$1+51] # Number of line interpolation regions
+define BADLINES Memi[$1+52] # Pointer to line interpolation regions
+define OVERSCAN_VEC Memi[$1+53] # Pointer to overscan vector
+define DARKSCALE Memr[P2R($1+54)] # Dark count scale factor
+define FRINGESCALE Memr[P2R($1+55)] # Fringe scale factor
+define FLATSCALE Memr[P2R($1+56)] # Flat field scale factor
+define ILLUMSCALE Memr[P2R($1+57)] # Illumination scale factor
+define MINREPLACE Memr[P2R($1+58)] # Minimum replacement value
+define MEAN Memr[P2R($1+59)] # Mean of output image
+define COR Memi[$1+60] # Overall correction flag
+define CORS Memi[$1+61+($2-1)] # Individual correction flags
+
+# Individual components of input, output, and bias section pieces.
+define IN_SC1 Memi[IN_SEC($1)+4*$2-4]
+define IN_SC2 Memi[IN_SEC($1)+4*$2-3]
+define IN_SL1 Memi[IN_SEC($1)+4*$2-2]
+define IN_SL2 Memi[IN_SEC($1)+4*$2-1]
+define OUT_SC1 Memi[OUT_SEC($1)+4*$2-4]
+define OUT_SC2 Memi[OUT_SEC($1)+4*$2-3]
+define OUT_SL1 Memi[OUT_SEC($1)+4*$2-2]
+define OUT_SL2 Memi[OUT_SEC($1)+4*$2-1]
+define BIAS_SC1 Memi[BIAS_SEC($1)+4*$2-4]
+define BIAS_SC2 Memi[BIAS_SEC($1)+4*$2-3]
+define BIAS_SL1 Memi[BIAS_SEC($1)+4*$2-2]
+define BIAS_SL2 Memi[BIAS_SEC($1)+4*$2-1]
+
+# The correction array contains the following elements with array indices
+# given by the macro definitions.
+
+define NCORS 10 # Number of corrections
+
+define FIXPIX 1 # Fix bad pixels
+define TRIM 2 # Trim image
+define OVERSCAN 3 # Apply overscan correction
+define ZEROCOR 4 # Apply zero level correction
+define DARKCOR 5 # Apply dark count correction
+define FLATCOR 6 # Apply flat field correction
+define ILLUMCOR 7 # Apply illumination correction
+define FRINGECOR 8 # Apply fringe correction
+define FINDMEAN 9 # Find the mean of the output image
+define MINREP 10 # Check and replace minimum value
+
+# The following definitions identify the correction values in the correction
+# array. They are defined in terms of bit fields so that it is possible to
+# add corrections to form unique combination corrections. Some of
+# these combinations are implemented as compound operations for efficiency.
+
+define O 001B # overscan
+define Z 002B # zero level
+define D 004B # dark count
+define F 010B # flat field
+define I 020B # Illumination
+define Q 040B # Fringe
+
+# The following correction combinations are recognized.
+
+define ZO 003B # zero level + overscan
+define DO 005B # dark count + overscan
+define DZ 006B # dark count + zero level
+define DZO 007B # dark count + zero level + overscan
+define FO 011B # flat field + overscan
+define FZ 012B # flat field + zero level
+define FZO 013B # flat field + zero level + overscan
+define FD 014B # flat field + dark count
+define FDO 015B # flat field + dark count + overscan
+define FDZ 016B # flat field + dark count + zero level
+define FDZO 017B # flat field + dark count + zero level + overscan
+define QI 060B # fringe + illumination
diff --git a/noao/imred/quadred/src/ccdproc/generic/cor.x b/noao/imred/quadred/src/ccdproc/generic/cor.x
new file mode 100644
index 00000000..0dc21310
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/generic/cor.x
@@ -0,0 +1,695 @@
+include "ccdred.h"
+
+
+.help cor Feb87 noao.imred.ccdred
+.nf ----------------------------------------------------------------------------
+cor -- Process CCD image lines
+
+These procedures are the heart of the CCD processing. They do the desired
+set of processing operations on the image line data as efficiently as
+possible. They are called by the PROC procedures. There are four procedures
+one for each readout axis and one for short and real image data.
+Some sets of operations are coded as single compound operations for efficiency.
+To keep the number of combinations managable only the most common
+combinations are coded as compound operations. The combinations
+consist of any set of line overscan, column overscan, zero level, dark
+count, and flat field and any set of illumination and fringe
+correction. The corrections are applied in place to the output vector.
+
+The column readout procedure is more complicated in order to handle
+zero level and flat field corrections specified as one dimensional
+readout corrections instead of two dimensional calibration images.
+Column readout format is probably extremely rare and the 1D readout
+corrections are used only for special types of data.
+.ih
+SEE ALSO
+proc, ccdred.h
+.endhelp -----------------------------------------------------------------------
+
+
+# COR1 -- Correct image lines with readout axis 1 (lines).
+
+procedure cor1s (cors, out, overscan, zero, dark, flat, illum,
+ fringe, n, darkscale, flatscale, illumscale, frgscale)
+
+int cors[ARB] # Correction flags
+short out[n] # Output data
+real overscan # Overscan value
+short zero[n] # Zero level correction
+short dark[n] # Dark count correction
+short flat[n] # Flat field correction
+short illum[n] # Illumination correction
+short fringe[n] # Fringe correction
+int n # Number of pixels
+real darkscale # Dark count scale factor
+real flatscale # Flat field scale factor
+real illumscale # Illumination scale factor
+real frgscale # Fringe scale factor
+
+int i, op
+
+begin
+ op = cors[OVERSCAN] + cors[ZEROCOR] + cors[DARKCOR] + cors[FLATCOR]
+ switch (op) {
+ case O: # overscan
+ do i = 1, n
+ out[i] = out[i] - overscan
+ case Z: # zero level
+ do i = 1, n
+ out[i] = out[i] - zero[i]
+
+ case ZO: # zero level + overscan
+ do i = 1, n
+ out[i] = out[i] - overscan - zero[i]
+
+ case D: # dark count
+ do i = 1, n
+ out[i] = out[i] - darkscale * dark[i]
+ case DO: # dark count + overscan
+ do i = 1, n
+ out[i] = out[i] - overscan - darkscale * dark[i]
+ case DZ: # dark count + zero level
+ do i = 1, n
+ out[i] = out[i] - zero[i] - darkscale * dark[i]
+ case DZO: # dark count + zero level + overscan
+ do i = 1, n
+ out[i] = out[i] - overscan - zero[i] - darkscale * dark[i]
+
+ case F: # flat field
+ do i = 1, n
+ out[i] = out[i] * flatscale / flat[i]
+ case FO: # flat field + overscan
+ do i = 1, n
+ out[i] = (out[i] - overscan) * flatscale / flat[i]
+ case FZ: # flat field + zero level
+ do i = 1, n
+ out[i] = (out[i] - zero[i]) * flatscale / flat[i]
+ case FZO: # flat field + zero level + overscan
+ do i = 1, n
+ out[i] = (out[i] - overscan - zero[i]) * flatscale /
+ flat[i]
+ case FD: # flat field + dark count
+ do i = 1, n
+ out[i] = (out[i] - darkscale * dark[i]) * flatscale / flat[i]
+ case FDO: # flat field + dark count + overscan
+ do i = 1, n
+ out[i] = (out[i] - overscan - darkscale * dark[i]) *
+ flatscale / flat[i]
+ case FDZ: # flat field + dark count + zero level
+ do i = 1, n
+ out[i] = (out[i] - zero[i] - darkscale * dark[i]) *
+ flatscale / flat[i]
+ case FDZO: # flat field + dark count + zero level + overscan
+ do i = 1, n
+ out[i] = (out[i] - overscan - zero[i] -
+ darkscale * dark[i]) * flatscale / flat[i]
+ }
+
+ # Often these operations will not be performed so test for no
+ # correction rather than go through the switch.
+
+ op = cors[ILLUMCOR] + cors[FRINGECOR]
+ if (op != 0) {
+ switch (op) {
+ case I: # illumination
+ do i = 1, n
+ out[i] = out[i] * illumscale / illum[i]
+ case Q: # fringe
+ do i = 1, n
+ out[i] = out[i] - frgscale * fringe[i]
+ case QI: # fringe + illumination
+ do i = 1, n
+ out[i] = out[i]*illumscale/illum[i] - frgscale*fringe[i]
+ }
+ }
+end
+
+
+# COR2 -- Correct lines for readout axis 2 (columns). This procedure is
+# more complex than when the readout is along the image lines because the
+# zero level and/or flat field corrections may be single readout column
+# vectors.
+
+procedure cor2s (line, cors, out, overscan, zero, dark, flat, illum,
+ fringe, n, zeroim, flatim, darkscale, flatscale, illumscale, frgscale)
+
+int line # Line to be corrected
+int cors[ARB] # Correction flags
+short out[n] # Output data
+real overscan[n] # Overscan value
+short zero[n] # Zero level correction
+short dark[n] # Dark count correction
+short flat[n] # Flat field correction
+short illum[n] # Illumination correction
+short fringe[n] # Fringe correction
+int n # Number of pixels
+pointer zeroim # Zero level IMIO pointer (NULL if 1D vector)
+pointer flatim # Flat field IMIO pointer (NULL if 1D vector)
+real darkscale # Dark count scale factor
+real flatscale # Flat field scale factor
+real illumscale # Illumination scale factor
+real frgscale # Fringe scale factor
+
+short zeroval
+real flatval
+int i, op
+
+begin
+ op = cors[OVERSCAN] + cors[ZEROCOR] + cors[DARKCOR] + cors[FLATCOR]
+ switch (op) {
+ case O: # overscan
+ do i = 1, n
+ out[i] = out[i] - overscan[i]
+ case Z: # zero level
+ if (zeroim != NULL)
+ do i = 1, n
+ out[i] = out[i] - zero[i]
+ else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = out[i] - zeroval
+ }
+
+ case ZO: # zero level + overscan
+ if (zeroim != NULL)
+ do i = 1, n
+ out[i] = out[i] - overscan[i] - zero[i]
+ else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = out[i] - overscan[i] - zeroval
+ }
+
+ case D: # dark count
+ do i = 1, n
+ out[i] = out[i] - darkscale * dark[i]
+ case DO: # dark count + overscan
+ do i = 1, n
+ out[i] = out[i] - overscan[i] - darkscale * dark[i]
+ case DZ: # dark count + zero level
+ if (zeroim != NULL)
+ do i = 1, n
+ out[i] = out[i] - zero[i] - darkscale * dark[i]
+ else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = out[i] - zeroval - darkscale * dark[i]
+ }
+ case DZO: # dark count + zero level + overscan
+ if (zeroim != NULL)
+ do i = 1, n
+ out[i] = out[i] - overscan[i] - zero[i] -
+ darkscale * dark[i]
+ else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = out[i] - overscan[i] - zeroval -
+ darkscale * dark[i]
+ }
+
+ case F: # flat field
+ if (flatim != NULL) {
+ do i = 1, n
+ out[i] = out[i] * flatscale / flat[i]
+ } else {
+ flatval = flatscale / flat[line]
+ do i = 1, n
+ out[i] = out[i] * flatval
+ }
+ case FO: # flat field + overscan
+ if (flatim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - overscan[i]) * flatscale / flat[i]
+ } else {
+ flatval = flatscale / flat[line]
+ do i = 1, n
+ out[i] = (out[i] - overscan[i]) * flatval
+ }
+ case FZ: # flat field + zero level
+ if (flatim != NULL) {
+ if (zeroim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - zero[i]) * flatscale / flat[i]
+ } else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = (out[i] - zeroval) * flatscale / flat[i]
+ }
+ } else {
+ flatval = flatscale / flat[line]
+ if (zeroim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - zero[i]) * flatval
+ } else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = (out[i] - zeroval) * flatval
+ }
+ }
+ case FZO: # flat field + zero level + overscan
+ if (flatim != NULL) {
+ if (zeroim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - zero[i]) *
+ flatscale / flat[i]
+ } else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - zeroval) *
+ flatscale / flat[i]
+ }
+ } else {
+ flatval = flatscale / flat[line]
+ if (zeroim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - zero[i]) * flatval
+ } else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - zeroval) * flatval
+ }
+ }
+ case FD: # flat field + dark count
+ if (flatim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - darkscale * dark[i]) * flatscale/flat[i]
+ } else {
+ flatval = flatscale / flat[line]
+ do i = 1, n
+ out[i] = (out[i] - darkscale * dark[i]) * flatval
+ }
+ case FDO: # flat field + dark count + overscan
+ if (flatim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - darkscale * dark[i]) *
+ flatscale / flat[i]
+ } else {
+ flatval = flatscale / flat[line]
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - darkscale * dark[i]) *
+ flatval
+ }
+ case FDZ: # flat field + dark count + zero level
+ if (flatim != NULL) {
+ if (zeroim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - zero[i] - darkscale * dark[i]) *
+ flatscale / flat[i]
+ } else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = (out[i] - zeroval - darkscale * dark[i]) *
+ flatscale / flat[i]
+ }
+ } else {
+ flatval = flatscale / flat[line]
+ if (zeroim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - zero[i] - darkscale * dark[i]) *
+ flatval
+ } else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = (out[i] - zeroval - darkscale * dark[i]) *
+ flatval
+ }
+ }
+ case FDZO: # flat field + dark count + zero level + overscan
+ if (flatim != NULL) {
+ if (zeroim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - zero[i] -
+ darkscale * dark[i]) * flatscale / flat[i]
+ } else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - zeroval -
+ darkscale * dark[i]) * flatscale / flat[i]
+ }
+ } else {
+ flatval = flatscale / flat[line]
+ if (zeroim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - zero[i] -
+ darkscale * dark[i]) * flatval
+ } else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - zeroval -
+ darkscale * dark[i]) * flatval
+ }
+ }
+ }
+
+ # Often these operations will not be performed so test for no
+ # correction rather than go through the switch.
+
+ op = cors[ILLUMCOR] + cors[FRINGECOR]
+ if (op != 0) {
+ switch (op) {
+ case I: # illumination
+ do i = 1, n
+ out[i] = out[i] * illumscale / illum[i]
+ case Q: # fringe
+ do i = 1, n
+ out[i] = out[i] - frgscale * fringe[i]
+ case QI: # fringe + illumination
+ do i = 1, n
+ out[i] = out[i]*illumscale/illum[i] - frgscale*fringe[i]
+ }
+ }
+end
+
+# COR1 -- Correct image lines with readout axis 1 (lines).
+
+procedure cor1r (cors, out, overscan, zero, dark, flat, illum,
+ fringe, n, darkscale, flatscale, illumscale, frgscale)
+
+int cors[ARB] # Correction flags
+real out[n] # Output data
+real overscan # Overscan value
+real zero[n] # Zero level correction
+real dark[n] # Dark count correction
+real flat[n] # Flat field correction
+real illum[n] # Illumination correction
+real fringe[n] # Fringe correction
+int n # Number of pixels
+real darkscale # Dark count scale factor
+real flatscale # Flat field scale factor
+real illumscale # Illumination scale factor
+real frgscale # Fringe scale factor
+
+int i, op
+
+begin
+ op = cors[OVERSCAN] + cors[ZEROCOR] + cors[DARKCOR] + cors[FLATCOR]
+ switch (op) {
+ case O: # overscan
+ do i = 1, n
+ out[i] = out[i] - overscan
+ case Z: # zero level
+ do i = 1, n
+ out[i] = out[i] - zero[i]
+
+ case ZO: # zero level + overscan
+ do i = 1, n
+ out[i] = out[i] - overscan - zero[i]
+
+ case D: # dark count
+ do i = 1, n
+ out[i] = out[i] - darkscale * dark[i]
+ case DO: # dark count + overscan
+ do i = 1, n
+ out[i] = out[i] - overscan - darkscale * dark[i]
+ case DZ: # dark count + zero level
+ do i = 1, n
+ out[i] = out[i] - zero[i] - darkscale * dark[i]
+ case DZO: # dark count + zero level + overscan
+ do i = 1, n
+ out[i] = out[i] - overscan - zero[i] - darkscale * dark[i]
+
+ case F: # flat field
+ do i = 1, n
+ out[i] = out[i] * flatscale / flat[i]
+ case FO: # flat field + overscan
+ do i = 1, n
+ out[i] = (out[i] - overscan) * flatscale / flat[i]
+ case FZ: # flat field + zero level
+ do i = 1, n
+ out[i] = (out[i] - zero[i]) * flatscale / flat[i]
+ case FZO: # flat field + zero level + overscan
+ do i = 1, n
+ out[i] = (out[i] - overscan - zero[i]) * flatscale /
+ flat[i]
+ case FD: # flat field + dark count
+ do i = 1, n
+ out[i] = (out[i] - darkscale * dark[i]) * flatscale / flat[i]
+ case FDO: # flat field + dark count + overscan
+ do i = 1, n
+ out[i] = (out[i] - overscan - darkscale * dark[i]) *
+ flatscale / flat[i]
+ case FDZ: # flat field + dark count + zero level
+ do i = 1, n
+ out[i] = (out[i] - zero[i] - darkscale * dark[i]) *
+ flatscale / flat[i]
+ case FDZO: # flat field + dark count + zero level + overscan
+ do i = 1, n
+ out[i] = (out[i] - overscan - zero[i] -
+ darkscale * dark[i]) * flatscale / flat[i]
+ }
+
+ # Often these operations will not be performed so test for no
+ # correction rather than go through the switch.
+
+ op = cors[ILLUMCOR] + cors[FRINGECOR]
+ if (op != 0) {
+ switch (op) {
+ case I: # illumination
+ do i = 1, n
+ out[i] = out[i] * illumscale / illum[i]
+ case Q: # fringe
+ do i = 1, n
+ out[i] = out[i] - frgscale * fringe[i]
+ case QI: # fringe + illumination
+ do i = 1, n
+ out[i] = out[i]*illumscale/illum[i] - frgscale*fringe[i]
+ }
+ }
+end
+
+
+# COR2 -- Correct lines for readout axis 2 (columns). This procedure is
+# more complex than when the readout is along the image lines because the
+# zero level and/or flat field corrections may be single readout column
+# vectors.
+
+procedure cor2r (line, cors, out, overscan, zero, dark, flat, illum,
+ fringe, n, zeroim, flatim, darkscale, flatscale, illumscale, frgscale)
+
+int line # Line to be corrected
+int cors[ARB] # Correction flags
+real out[n] # Output data
+real overscan[n] # Overscan value
+real zero[n] # Zero level correction
+real dark[n] # Dark count correction
+real flat[n] # Flat field correction
+real illum[n] # Illumination correction
+real fringe[n] # Fringe correction
+int n # Number of pixels
+pointer zeroim # Zero level IMIO pointer (NULL if 1D vector)
+pointer flatim # Flat field IMIO pointer (NULL if 1D vector)
+real darkscale # Dark count scale factor
+real flatscale # Flat field scale factor
+real illumscale # Illumination scale factor
+real frgscale # Fringe scale factor
+
+real zeroval
+real flatval
+int i, op
+
+begin
+ op = cors[OVERSCAN] + cors[ZEROCOR] + cors[DARKCOR] + cors[FLATCOR]
+ switch (op) {
+ case O: # overscan
+ do i = 1, n
+ out[i] = out[i] - overscan[i]
+ case Z: # zero level
+ if (zeroim != NULL)
+ do i = 1, n
+ out[i] = out[i] - zero[i]
+ else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = out[i] - zeroval
+ }
+
+ case ZO: # zero level + overscan
+ if (zeroim != NULL)
+ do i = 1, n
+ out[i] = out[i] - overscan[i] - zero[i]
+ else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = out[i] - overscan[i] - zeroval
+ }
+
+ case D: # dark count
+ do i = 1, n
+ out[i] = out[i] - darkscale * dark[i]
+ case DO: # dark count + overscan
+ do i = 1, n
+ out[i] = out[i] - overscan[i] - darkscale * dark[i]
+ case DZ: # dark count + zero level
+ if (zeroim != NULL)
+ do i = 1, n
+ out[i] = out[i] - zero[i] - darkscale * dark[i]
+ else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = out[i] - zeroval - darkscale * dark[i]
+ }
+ case DZO: # dark count + zero level + overscan
+ if (zeroim != NULL)
+ do i = 1, n
+ out[i] = out[i] - overscan[i] - zero[i] -
+ darkscale * dark[i]
+ else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = out[i] - overscan[i] - zeroval -
+ darkscale * dark[i]
+ }
+
+ case F: # flat field
+ if (flatim != NULL) {
+ do i = 1, n
+ out[i] = out[i] * flatscale / flat[i]
+ } else {
+ flatval = flatscale / flat[line]
+ do i = 1, n
+ out[i] = out[i] * flatval
+ }
+ case FO: # flat field + overscan
+ if (flatim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - overscan[i]) * flatscale / flat[i]
+ } else {
+ flatval = flatscale / flat[line]
+ do i = 1, n
+ out[i] = (out[i] - overscan[i]) * flatval
+ }
+ case FZ: # flat field + zero level
+ if (flatim != NULL) {
+ if (zeroim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - zero[i]) * flatscale / flat[i]
+ } else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = (out[i] - zeroval) * flatscale / flat[i]
+ }
+ } else {
+ flatval = flatscale / flat[line]
+ if (zeroim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - zero[i]) * flatval
+ } else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = (out[i] - zeroval) * flatval
+ }
+ }
+ case FZO: # flat field + zero level + overscan
+ if (flatim != NULL) {
+ if (zeroim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - zero[i]) *
+ flatscale / flat[i]
+ } else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - zeroval) *
+ flatscale / flat[i]
+ }
+ } else {
+ flatval = flatscale / flat[line]
+ if (zeroim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - zero[i]) * flatval
+ } else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - zeroval) * flatval
+ }
+ }
+ case FD: # flat field + dark count
+ if (flatim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - darkscale * dark[i]) * flatscale/flat[i]
+ } else {
+ flatval = flatscale / flat[line]
+ do i = 1, n
+ out[i] = (out[i] - darkscale * dark[i]) * flatval
+ }
+ case FDO: # flat field + dark count + overscan
+ if (flatim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - darkscale * dark[i]) *
+ flatscale / flat[i]
+ } else {
+ flatval = flatscale / flat[line]
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - darkscale * dark[i]) *
+ flatval
+ }
+ case FDZ: # flat field + dark count + zero level
+ if (flatim != NULL) {
+ if (zeroim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - zero[i] - darkscale * dark[i]) *
+ flatscale / flat[i]
+ } else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = (out[i] - zeroval - darkscale * dark[i]) *
+ flatscale / flat[i]
+ }
+ } else {
+ flatval = flatscale / flat[line]
+ if (zeroim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - zero[i] - darkscale * dark[i]) *
+ flatval
+ } else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = (out[i] - zeroval - darkscale * dark[i]) *
+ flatval
+ }
+ }
+ case FDZO: # flat field + dark count + zero level + overscan
+ if (flatim != NULL) {
+ if (zeroim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - zero[i] -
+ darkscale * dark[i]) * flatscale / flat[i]
+ } else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - zeroval -
+ darkscale * dark[i]) * flatscale / flat[i]
+ }
+ } else {
+ flatval = flatscale / flat[line]
+ if (zeroim != NULL) {
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - zero[i] -
+ darkscale * dark[i]) * flatval
+ } else {
+ zeroval = zero[line]
+ do i = 1, n
+ out[i] = (out[i] - overscan[i] - zeroval -
+ darkscale * dark[i]) * flatval
+ }
+ }
+ }
+
+ # Often these operations will not be performed so test for no
+ # correction rather than go through the switch.
+
+ op = cors[ILLUMCOR] + cors[FRINGECOR]
+ if (op != 0) {
+ switch (op) {
+ case I: # illumination
+ do i = 1, n
+ out[i] = out[i] * illumscale / illum[i]
+ case Q: # fringe
+ do i = 1, n
+ out[i] = out[i] - frgscale * fringe[i]
+ case QI: # fringe + illumination
+ do i = 1, n
+ out[i] = out[i]*illumscale/illum[i] - frgscale*fringe[i]
+ }
+ }
+end
+
diff --git a/noao/imred/quadred/src/ccdproc/generic/corinput.x b/noao/imred/quadred/src/ccdproc/generic/corinput.x
new file mode 100644
index 00000000..07afaa41
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/generic/corinput.x
@@ -0,0 +1,436 @@
+include <imhdr.h>
+include "ccdred.h"
+
+
+# CORINPUT -- Get an input image line, fix the bad pixels, and trim.
+# Return the corrected input line in the output array.
+
+procedure corinputs (in, line, ccd, output, ncols)
+
+pointer in # Input IMIO pointer
+int line # Corrected output line
+pointer ccd # CCD pointer
+short output[ncols] # Output data (returned)
+int ncols # Number of output columns
+
+int i, inline
+pointer inbuf, imgl2s()
+
+begin
+ # Determine the input line in terms of the trimmed output line.
+ if (IN_SEC(ccd) == NULL)
+ inline = IN_L1(ccd) + line - 1
+ else {
+ do i = 1, IN_NSEC(ccd) {
+ if (line < OUT_SL1(ccd,i) || line > OUT_SL2(ccd,i))
+ next
+ inline = IN_SL1(ccd,i) + line - OUT_SL1(ccd,i)
+ break
+ }
+ }
+
+ # If there are bad lines call a procedure to fix them. Otherwise
+ # read the image line directly.
+
+ if (NBADLINES(ccd) != 0)
+ call lfixs (in, inline, Mems[BADLINES(ccd)], IM_LEN(in,1),
+ IM_LEN(in,2), NBADLINES(ccd), inbuf)
+ else
+ inbuf = imgl2s (in, inline)
+
+ # IF there are bad columns call a procedure to fix them.
+ if (NBADCOLS(ccd) != 0)
+ call cfixs (inline, Mems[BADCOLS(ccd)], IM_LEN(in,1),
+ IM_LEN(in,2), NBADCOLS(ccd), Mems[inbuf])
+
+ # Move the pixels to the output line.
+ if (IN_SEC(ccd) == NULL)
+ call amovs (Mems[inbuf+IN_C1(ccd)-OUT_C1(ccd)], output, ncols)
+ else {
+ do i = 1, IN_NSEC(ccd) {
+ if (inline < IN_SL1(ccd,i) || inline > IN_SL2(ccd,i))
+ next
+ call amovs (Mems[inbuf+IN_SC1(ccd,i)-OUT_C1(ccd)],
+ output[OUT_SC1(ccd,i)], OUT_SC2(ccd,i)-OUT_SC1(ccd,i)+1)
+ }
+ }
+end
+
+
+# CFIX -- Interpolate across bad columns defined in the bad column array.
+
+procedure cfixs (line, badcols, ncols, nlines, nbadcols, data)
+
+int line # Line to be fixed
+short badcols[2, nlines, nbadcols] # Bad column array
+int ncols # Number of columns
+int nlines # Number of lines
+int nbadcols # Number of bad column regions
+short data[ncols] # Data to be fixed
+
+short val
+real del
+int i, j, col1, col2
+
+begin
+ do i = 1, nbadcols {
+ col1 = badcols[1, line, i]
+ if (col1 == 0) # No bad columns
+ return
+ col2 = badcols[2, line, i]
+ if (col1 == 1) { # Bad first column
+ val = data[col2+1]
+ do j = col1, col2
+ data[j] = val
+ } else if (col2 == ncols) { # Bad last column
+ val = data[col1-1]
+ do j = col1, col2
+ data[j] = val
+ } else { # Interpolate
+ del = (data[col2+1] - data[col1-1]) / (col2 - col1 + 2)
+ val = data[col1-1] + del
+ do j = col1, col2
+ data[j] = val + (j - col1) * del
+ }
+ }
+end
+
+
+# LFIX -- Get image line and replace bad pixels by interpolation from
+# neighboring lines. Internal buffers are used to keep the last fixed
+# line and the next good line. They are allocated with LFIXINIT and
+# freed with LFIXFREE.
+
+procedure lfixs (im, line, badlines, ncols, nlines, nbadlines, data)
+
+pointer im # IMIO pointer
+int line # Line to be obtained and fixed
+short badlines[2,nlines,nbadlines] # Bad line region array
+int ncols # Number of columns in image
+int nlines # Number of lines in images
+int nbadlines # Number of bad line regions
+pointer data # Data line pointer (returned)
+
+real wt1, wt2
+int i, nextgood, lastgood, col1, col2
+pointer imgl2s()
+
+pointer lastbuf, nextbuf
+common /lfixcom/ lastbuf, nextbuf, lastgood
+
+begin
+ # If this line has bad pixels replace them. Otherwise just
+ # read the line.
+
+ if (badlines[1, line, 1] != 0) {
+ # Save the last line which has already been fixed.
+ if (line != 1)
+ call amovs (Mems[data], Mems[lastbuf], ncols)
+
+ # Determine the next line with no bad line pixels. Note that
+ # this requirement is overly strict since the bad columns
+ # may not be the same in neighboring lines.
+
+ nextgood = 0
+ do i = line+1, nlines {
+ if (badlines[1, i, 1] == 0) {
+ nextgood = i
+ break
+ }
+ }
+
+ # If the next good line is not the same as previously
+ # read the data line and store it in a buffer.
+
+ if ((nextgood != lastgood) && (nextgood != 0)) {
+ data = imgl2s (im, nextgood)
+ call amovs (Mems[data], Mems[nextbuf], ncols)
+ lastgood = nextgood
+ }
+
+ # Get the data line.
+ data = imgl2s (im, line)
+
+ # Interpolate the bad columns. At the ends of the image use
+ # extension otherwise use linear interpolation.
+
+ if (line == 1) { # First line is bad
+ do i = 1, nbadlines {
+ col1 = badlines[1,line,i] - 1
+ if (col1 == -1)
+ break
+ col2 = badlines[2,line,i]
+ call amovs (Mems[nextbuf+col1], Mems[data+col1],
+ col2-col1)
+ }
+ } else if (nextgood == 0) { # Last line is bad
+ do i = 1, nbadlines {
+ col1 = badlines[1,line,i] - 1
+ if (col1 == -1)
+ break
+ col2 = badlines[2,line,i]
+ call amovs (Mems[lastbuf+col1], Mems[data+col1],
+ col2-col1)
+ }
+ } else { # Interpolate
+ wt1 = 1. / (nextgood - line + 1)
+ wt2 = 1. - wt1
+ do i = 1, nbadlines {
+ col1 = badlines[1,line,i] - 1
+ if (col1 == -1)
+ break
+ col2 = badlines[2,line,i] - 1
+ call awsus (Mems[nextbuf+col1], Mems[lastbuf+col1],
+ Mems[data+col1], col2-col1+1, wt1, wt2)
+ }
+ }
+ } else
+ data = imgl2s (im, line)
+end
+
+
+# LFIXINIT -- Allocate internal buffers.
+
+procedure lfixinits (im)
+
+pointer im # IMIO pointer
+
+int lastgood
+pointer lastbuf, nextbuf
+common /lfixcom/ lastbuf, nextbuf, lastgood
+
+begin
+ call malloc (lastbuf, IM_LEN(im,1), TY_SHORT)
+ call malloc (nextbuf, IM_LEN(im,1), TY_SHORT)
+ lastgood=0
+end
+
+# LFIXFREE -- Free memory when the last line has been obtained.
+
+procedure lfixfrees ()
+
+int lastgood
+pointer lastbuf, nextbuf
+common /lfixcom/ lastbuf, nextbuf, lastgood
+
+begin
+ call mfree (lastbuf, TY_SHORT)
+ call mfree (nextbuf, TY_SHORT)
+end
+
+# CORINPUT -- Get an input image line, fix the bad pixels, and trim.
+# Return the corrected input line in the output array.
+
+procedure corinputr (in, line, ccd, output, ncols)
+
+pointer in # Input IMIO pointer
+int line # Corrected output line
+pointer ccd # CCD pointer
+real output[ncols] # Output data (returned)
+int ncols # Number of output columns
+
+int i, inline
+pointer inbuf, imgl2r()
+
+begin
+ # Determine the input line in terms of the trimmed output line.
+ if (IN_SEC(ccd) == NULL)
+ inline = IN_L1(ccd) + line - 1
+ else {
+ do i = 1, IN_NSEC(ccd) {
+ if (line < OUT_SL1(ccd,i) || line > OUT_SL2(ccd,i))
+ next
+ inline = IN_SL1(ccd,i) + line - OUT_SL1(ccd,i)
+ break
+ }
+ }
+
+ # If there are bad lines call a procedure to fix them. Otherwise
+ # read the image line directly.
+
+ if (NBADLINES(ccd) != 0)
+ call lfixr (in, inline, Mems[BADLINES(ccd)], IM_LEN(in,1),
+ IM_LEN(in,2), NBADLINES(ccd), inbuf)
+ else
+ inbuf = imgl2r (in, inline)
+
+ # IF there are bad columns call a procedure to fix them.
+ if (NBADCOLS(ccd) != 0)
+ call cfixr (inline, Mems[BADCOLS(ccd)], IM_LEN(in,1),
+ IM_LEN(in,2), NBADCOLS(ccd), Memr[inbuf])
+
+ # Move the pixels to the output line.
+ if (IN_SEC(ccd) == NULL)
+ call amovr (Memr[inbuf+IN_C1(ccd)-OUT_C1(ccd)], output, ncols)
+ else {
+ do i = 1, IN_NSEC(ccd) {
+ if (inline < IN_SL1(ccd,i) || inline > IN_SL2(ccd,i))
+ next
+ call amovr (Memr[inbuf+IN_SC1(ccd,i)-OUT_C1(ccd)],
+ output[OUT_SC1(ccd,i)], OUT_SC2(ccd,i)-OUT_SC1(ccd,i)+1)
+ }
+ }
+end
+
+
+# CFIX -- Interpolate across bad columns defined in the bad column array.
+
+procedure cfixr (line, badcols, ncols, nlines, nbadcols, data)
+
+int line # Line to be fixed
+short badcols[2, nlines, nbadcols] # Bad column array
+int ncols # Number of columns
+int nlines # Number of lines
+int nbadcols # Number of bad column regions
+real data[ncols] # Data to be fixed
+
+real val
+real del
+int i, j, col1, col2
+
+begin
+ do i = 1, nbadcols {
+ col1 = badcols[1, line, i]
+ if (col1 == 0) # No bad columns
+ return
+ col2 = badcols[2, line, i]
+ if (col1 == 1) { # Bad first column
+ val = data[col2+1]
+ do j = col1, col2
+ data[j] = val
+ } else if (col2 == ncols) { # Bad last column
+ val = data[col1-1]
+ do j = col1, col2
+ data[j] = val
+ } else { # Interpolate
+ del = (data[col2+1] - data[col1-1]) / (col2 - col1 + 2)
+ val = data[col1-1] + del
+ do j = col1, col2
+ data[j] = val + (j - col1) * del
+ }
+ }
+end
+
+
+# LFIX -- Get image line and replace bad pixels by interpolation from
+# neighboring lines. Internal buffers are used to keep the last fixed
+# line and the next good line. They are allocated with LFIXINIT and
+# freed with LFIXFREE.
+
+procedure lfixr (im, line, badlines, ncols, nlines, nbadlines, data)
+
+pointer im # IMIO pointer
+int line # Line to be obtained and fixed
+short badlines[2,nlines,nbadlines] # Bad line region array
+int ncols # Number of columns in image
+int nlines # Number of lines in images
+int nbadlines # Number of bad line regions
+pointer data # Data line pointer (returned)
+
+real wt1, wt2
+int i, nextgood, lastgood, col1, col2
+pointer imgl2r()
+
+pointer lastbuf, nextbuf
+common /lfixcom/ lastbuf, nextbuf, lastgood
+
+begin
+ # If this line has bad pixels replace them. Otherwise just
+ # read the line.
+
+ if (badlines[1, line, 1] != 0) {
+ # Save the last line which has already been fixed.
+ if (line != 1)
+ call amovr (Memr[data], Memr[lastbuf], ncols)
+
+ # Determine the next line with no bad line pixels. Note that
+ # this requirement is overly strict since the bad columns
+ # may not be the same in neighboring lines.
+
+ nextgood = 0
+ do i = line+1, nlines {
+ if (badlines[1, i, 1] == 0) {
+ nextgood = i
+ break
+ }
+ }
+
+ # If the next good line is not the same as previously
+ # read the data line and store it in a buffer.
+
+ if ((nextgood != lastgood) && (nextgood != 0)) {
+ data = imgl2r (im, nextgood)
+ call amovr (Memr[data], Memr[nextbuf], ncols)
+ lastgood = nextgood
+ }
+
+ # Get the data line.
+ data = imgl2r (im, line)
+
+ # Interpolate the bad columns. At the ends of the image use
+ # extension otherwise use linear interpolation.
+
+ if (line == 1) { # First line is bad
+ do i = 1, nbadlines {
+ col1 = badlines[1,line,i] - 1
+ if (col1 == -1)
+ break
+ col2 = badlines[2,line,i]
+ call amovr (Memr[nextbuf+col1], Memr[data+col1],
+ col2-col1)
+ }
+ } else if (nextgood == 0) { # Last line is bad
+ do i = 1, nbadlines {
+ col1 = badlines[1,line,i] - 1
+ if (col1 == -1)
+ break
+ col2 = badlines[2,line,i]
+ call amovr (Memr[lastbuf+col1], Memr[data+col1],
+ col2-col1)
+ }
+ } else { # Interpolate
+ wt1 = 1. / (nextgood - line + 1)
+ wt2 = 1. - wt1
+ do i = 1, nbadlines {
+ col1 = badlines[1,line,i] - 1
+ if (col1 == -1)
+ break
+ col2 = badlines[2,line,i] - 1
+ call awsur (Memr[nextbuf+col1], Memr[lastbuf+col1],
+ Memr[data+col1], col2-col1+1, wt1, wt2)
+ }
+ }
+ } else
+ data = imgl2r (im, line)
+end
+
+
+# LFIXINIT -- Allocate internal buffers.
+
+procedure lfixinitr (im)
+
+pointer im # IMIO pointer
+
+int lastgood
+pointer lastbuf, nextbuf
+common /lfixcom/ lastbuf, nextbuf, lastgood
+
+begin
+ call malloc (lastbuf, IM_LEN(im,1), TY_REAL)
+ call malloc (nextbuf, IM_LEN(im,1), TY_REAL)
+ lastgood=0
+end
+
+# LFIXFREE -- Free memory when the last line has been obtained.
+
+procedure lfixfreer ()
+
+int lastgood
+pointer lastbuf, nextbuf
+common /lfixcom/ lastbuf, nextbuf, lastgood
+
+begin
+ call mfree (lastbuf, TY_REAL)
+ call mfree (nextbuf, TY_REAL)
+end
+
diff --git a/noao/imred/quadred/src/ccdproc/generic/mkpkg b/noao/imred/quadred/src/ccdproc/generic/mkpkg
new file mode 100644
index 00000000..0f12b368
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/generic/mkpkg
@@ -0,0 +1,12 @@
+# Make CCDRED Package.
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ cor.x ccdred.h
+ corinput.x ccdred.h <imhdr.h>
+ proc.x ccdred.h <imhdr.h>
+ ;
diff --git a/noao/imred/quadred/src/ccdproc/generic/proc.x b/noao/imred/quadred/src/ccdproc/generic/proc.x
new file mode 100644
index 00000000..0251f4f8
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/generic/proc.x
@@ -0,0 +1,678 @@
+include <imhdr.h>
+include "ccdred.h"
+
+
+.help proc Feb87 noao.imred.ccdred
+.nf ----------------------------------------------------------------------------
+proc -- Process CCD images
+
+These are the main CCD reduction procedures. There is one for each
+readout axis (lines or columns) and one for short and real image data.
+They apply corrections for bad pixels, overscan levels, zero levels,
+dark counts, flat field response, illumination response, and fringe
+effects. The image is also trimmed if it was mapped with an image
+section. The mean value for the output image is computed when the flat
+field or illumination image is processed to form the scale factor for
+these calibrations in order to avoid reading through these image a
+second time.
+
+The processing information and parameters are specified in the CCD
+structure. The processing operations to be performed are specified by
+the correction array CORS in the ccd structure. There is one array
+element for each operation with indices defined symbolically by macro
+definitions (see ccdred.h); i.e. FLATCOR. The value of the array
+element is an integer bit field in which the bit set is the same as the
+array index; i.e element 3 will have the third bit set for an operation
+with array value 2**(3-1)=4. If an operation is not to be performed
+the bit is not set and the array element has the numeric value zero.
+Note that the addition of several correction elements gives a unique
+bit field describing a combination of operations. For efficiency the
+most common combinations are implemented as separate units.
+
+The CCD structure also contains the correction or calibration data
+consisting either pointers to data, IMIO pointers for the calibration
+images, and scale factors.
+
+The processing is performed line-by-line. The procedure CORINPUT is
+called to get an input line. This procedure trims and fixes bad pixels by
+interpolation. The output line and lines from the various calibration
+images are read. The image vectors as well as the overscan vector and
+the scale factors are passed to the procedure COR (which also
+dereferences the pointer data into simple arrays and variables). That
+procedure does the actual corrections apart from bad pixel
+corrections.
+
+The final optional step is to add each corrected output line to form a
+mean. This adds efficiency since the operation is done only if desired
+and the output image data is already in memory so there is no I/O
+penalty.
+
+SEE ALSO
+ ccdred.h, cor, fixpix, setfixpix, setoverscan, settrim,
+ setzero, setdark, setflat, setillum, setfringe
+.endhelp ----------------------------------------------------------------------
+
+
+
+# PROC1 -- Process CCD images with readout axis 1 (lines).
+
+procedure proc1s (ccd)
+
+pointer ccd # CCD structure
+
+int i, line, nlin, ncols, nlines, findmean, rep
+int c1, c2, l1, l2
+real overscan, darkscale, flatscale, illumscale, frgscale, mean
+short minrep
+pointer in, out, zeroim, darkim, flatim, illumim, fringeim
+pointer outbuf, overscan_vec, zerobuf, darkbuf, flatbuf, illumbuf, fringebuf
+
+real asums()
+pointer imgl2s(), impl2s(), ccd_gls()
+
+begin
+ # Initialize. If the correction image is 1D then just get the
+ # data once.
+
+ in = IN_IM(ccd)
+ out = OUT_IM(ccd)
+ nlin = IM_LEN(in,2)
+ ncols = OUT_C2(ccd) - OUT_C1(ccd) + 1
+ nlines = OUT_L2(ccd) - OUT_L1(ccd) + 1
+
+ if (CORS(ccd, FIXPIX) == YES)
+ call lfixinits (in)
+
+ findmean = CORS(ccd, FINDMEAN)
+ if (findmean == YES)
+ mean = 0.
+ rep = CORS(ccd, MINREP)
+ if (rep == YES)
+ minrep = MINREPLACE(ccd)
+
+ overscan_vec = OVERSCAN_VEC(ccd)
+
+ if (CORS(ccd, ZEROCOR) == 0) {
+ zeroim = NULL
+ zerobuf = 1
+ } else if (IM_LEN(ZERO_IM(ccd),2) == 1) {
+ zeroim = NULL
+ zerobuf = ccd_gls (ZERO_IM(ccd), ZERO_C1(ccd), ZERO_C2(ccd), 1)
+ } else
+ zeroim = ZERO_IM(ccd)
+
+ if (CORS(ccd, DARKCOR) == 0) {
+ darkim = NULL
+ darkbuf = 1
+ } else if (IM_LEN(DARK_IM(ccd),2) == 1) {
+ darkim = NULL
+ darkbuf = ccd_gls (DARK_IM(ccd), DARK_C1(ccd), DARK_C2(ccd), 1)
+ darkscale = FLATSCALE(ccd)
+ } else {
+ darkim = DARK_IM(ccd)
+ darkscale = DARKSCALE(ccd)
+ }
+
+ if (CORS(ccd, FLATCOR) == 0) {
+ flatim = NULL
+ flatbuf = 1
+ } else if (IM_LEN(FLAT_IM(ccd),2) == 1) {
+ flatim = NULL
+ flatbuf = ccd_gls (FLAT_IM(ccd), FLAT_C1(ccd), FLAT_C2(ccd), 1)
+ flatscale = FLATSCALE(ccd)
+ } else {
+ flatim = FLAT_IM(ccd)
+ flatscale = FLATSCALE(ccd)
+ }
+
+ if (CORS(ccd, ILLUMCOR) == 0) {
+ illumim = NULL
+ illumbuf = 1
+ } else {
+ illumim = ILLUM_IM(ccd)
+ illumscale = ILLUMSCALE(ccd)
+ }
+
+ if (CORS(ccd, FRINGECOR) == 0) {
+ fringeim = NULL
+ fringebuf = 1
+ } else {
+ fringeim = FRINGE_IM(ccd)
+ frgscale = FRINGESCALE(ccd)
+ }
+
+ # For each line read lines from the input. Procedure CORINPUT
+ # replaces bad pixels by interpolation and applies a trim to the
+ # input. Get lines from the output image and from the zero level,
+ # dark count, flat field, illumination, and fringe images.
+ # Call COR1 to do the actual pixel corrections. Finally, add the
+ # output pixels to a sum for computing the mean.
+ # We must copy data outside of the output data section.
+
+ do line = 2 - OUT_L1(ccd), 0
+ call amovs (
+ Mems[imgl2s(in,IN_L1(ccd)+line-1)+IN_C1(ccd)-OUT_C1(ccd)],
+ Mems[impl2s(out,OUT_L1(ccd)+line-1)], IM_LEN(out,1))
+
+ do line = 1, nlines {
+ outbuf = impl2s (out, OUT_L1(ccd)+line-1)
+ call corinputs (in, line, ccd, Mems[outbuf], IM_LEN(out,1))
+
+ outbuf = outbuf + OUT_C1(ccd) - 1
+ if (overscan_vec != NULL)
+ overscan = Memr[overscan_vec+line-1]
+ if (zeroim != NULL)
+ zerobuf = ccd_gls (zeroim, ZERO_C1(ccd), ZERO_C2(ccd),
+ ZERO_L1(ccd)+line-1)
+ if (darkim != NULL)
+ darkbuf = ccd_gls (darkim, DARK_C1(ccd), DARK_C2(ccd),
+ DARK_L1(ccd)+line-1)
+ if (flatim != NULL)
+ flatbuf = ccd_gls (flatim, FLAT_C1(ccd), FLAT_C2(ccd),
+ FLAT_L1(ccd)+line-1)
+ if (illumim != NULL)
+ illumbuf = ccd_gls (illumim, ILLUM_C1(ccd), ILLUM_C2(ccd),
+ ILLUM_L1(ccd)+line-1)
+ if (fringeim != NULL)
+ fringebuf = ccd_gls (fringeim, FRINGE_C1(ccd), FRINGE_C2(ccd),
+ FRINGE_L1(ccd)+line-1)
+
+ if (OUT_SEC(ccd) == NULL) {
+ call cor1s (CORS(ccd,1), Mems[outbuf],
+ overscan, Mems[zerobuf], Mems[darkbuf],
+ Mems[flatbuf], Mems[illumbuf], Mems[fringebuf], ncols,
+ darkscale, flatscale, illumscale, frgscale)
+ } else {
+ do i = 1, IN_NSEC(ccd) {
+ l1 = OUT_SL1(ccd,i)
+ l2 = OUT_SL2(ccd,i)
+ if (line < l1 || line > l2)
+ next
+ c1 = OUT_SC1(ccd,i) - 1
+ c2 = OUT_SC2(ccd,i) - 1
+ ncols = c2 - c1 + 1
+ if (overscan_vec != NULL)
+ overscan = Memr[overscan_vec+(i-1)*nlin+line-l1]
+
+ call cor1s (CORS(ccd,1), Mems[outbuf+c1],
+ overscan, Mems[zerobuf+c1], Mems[darkbuf+c1],
+ Mems[flatbuf+c1], Mems[illumbuf+c1],
+ Mems[fringebuf+c1], ncols,
+ darkscale, flatscale, illumscale, frgscale)
+ }
+ }
+
+ if (rep == YES)
+ call amaxks (Mems[outbuf], minrep, Mems[outbuf], ncols)
+ if (findmean == YES)
+ mean = mean + asums (Mems[outbuf], ncols)
+ }
+
+ do line = nlines+1, IM_LEN(out,2)-OUT_L1(ccd)+1
+ call amovs (
+ Mems[imgl2s(in,IN_L1(ccd)+line-1)+IN_C1(ccd)-OUT_C1(ccd)],
+ Mems[impl2s(out,OUT_L1(ccd)+line-1)], IM_LEN(out,1))
+
+ # Compute the mean from the sum of the output pixels.
+ if (findmean == YES)
+ MEAN(ccd) = mean / ncols / nlines
+
+ if (CORS(ccd, FIXPIX) == YES)
+ call lfixfrees ()
+end
+
+
+# PROC2 -- Process CCD images with readout axis 2 (columns).
+
+procedure proc2s (ccd)
+
+pointer ccd # CCD structure
+
+int line, ncols, nlines, findmean, rep
+real darkscale, flatscale, illumscale, frgscale, mean
+short minrep
+pointer in, out, zeroim, darkim, flatim, illumim, fringeim
+pointer outbuf, overscan_vec, zerobuf, darkbuf, flatbuf, illumbuf, fringebuf
+
+real asums()
+pointer imgl2s(), impl2s(), imgs2s(), ccd_gls()
+
+begin
+ # Initialize. If the correction image is 1D then just get the
+ # data once.
+
+ in = IN_IM(ccd)
+ out = OUT_IM(ccd)
+ ncols = OUT_C2(ccd) - OUT_C1(ccd) + 1
+ nlines = OUT_L2(ccd) - OUT_L1(ccd) + 1
+
+ if (CORS(ccd, FIXPIX) == YES)
+ call lfixinits (in)
+
+ findmean = CORS(ccd, FINDMEAN)
+ if (findmean == YES)
+ mean = 0.
+ rep = CORS(ccd, MINREP)
+ if (rep == YES)
+ minrep = MINREPLACE(ccd)
+
+ overscan_vec = OVERSCAN_VEC(ccd)
+
+ if (CORS(ccd, ZEROCOR) == 0) {
+ zeroim = NULL
+ zerobuf = 1
+ } else if (IM_LEN(ZERO_IM(ccd),1) == 1) {
+ zeroim = NULL
+ zerobuf = imgs2s (ZERO_IM(ccd), 1, 1, ZERO_L1(ccd), ZERO_L2(ccd))
+ } else
+ zeroim = ZERO_IM(ccd)
+
+ if (CORS(ccd, DARKCOR) == 0) {
+ darkim = NULL
+ darkbuf = 1
+ } else if (IM_LEN(DARK_IM(ccd),1) == 1) {
+ darkim = NULL
+ darkbuf = imgs2s (DARK_IM(ccd), 1, 1, DARK_L1(ccd), DARK_L2(ccd))
+ darkscale = DARKSCALE(ccd)
+ } else {
+ darkim = DARK_IM(ccd)
+ darkscale = DARKSCALE(ccd)
+ }
+
+ if (CORS(ccd, FLATCOR) == 0) {
+ flatim = NULL
+ flatbuf = 1
+ } else if (IM_LEN(FLAT_IM(ccd),1) == 1) {
+ flatim = NULL
+ flatbuf = imgs2s (FLAT_IM(ccd), 1, 1, FLAT_L1(ccd), FLAT_L2(ccd))
+ flatscale = FLATSCALE(ccd)
+ } else {
+ flatim = FLAT_IM(ccd)
+ flatscale = FLATSCALE(ccd)
+ }
+
+ if (CORS(ccd, ILLUMCOR) == 0) {
+ illumim = NULL
+ illumbuf = 1
+ } else {
+ illumim = ILLUM_IM(ccd)
+ illumscale = ILLUMSCALE(ccd)
+ }
+
+ if (CORS(ccd, FRINGECOR) == 0) {
+ fringeim = NULL
+ fringebuf = 1
+ } else {
+ fringeim = FRINGE_IM(ccd)
+ frgscale = FRINGESCALE(ccd)
+ }
+
+ # For each line read lines from the input. Procedure CORINPUT
+ # replaces bad pixels by interpolation and applies a trim to the
+ # input. Get lines from the output image and from the zero level,
+ # dark count, flat field, illumination, and fringe images.
+ # Call COR2 to do the actual pixel corrections. Finally, add the
+ # output pixels to a sum for computing the mean.
+ # We must copy data outside of the output data section.
+
+ do line = 2 - OUT_L1(ccd), 0
+ call amovs (
+ Mems[imgl2s(in,IN_L1(ccd)+line-1)+IN_C1(ccd)-OUT_C1(ccd)],
+ Mems[impl2s(out,OUT_L1(ccd)+line-1)], IM_LEN(out,1))
+
+ do line = 1, nlines {
+ outbuf = impl2s (out, OUT_L1(ccd)+line-1)
+ call corinputs (in, line, ccd, Mems[outbuf], IM_LEN(out,1))
+
+ outbuf = outbuf + OUT_C1(ccd) - 1
+ if (zeroim != NULL)
+ zerobuf = ccd_gls (zeroim, ZERO_C1(ccd), ZERO_C2(ccd),
+ ZERO_L1(ccd)+line-1)
+ if (darkim != NULL)
+ darkbuf = ccd_gls (darkim, DARK_C1(ccd), DARK_C2(ccd),
+ DARK_L1(ccd)+line-1)
+ if (flatim != NULL)
+ flatbuf = ccd_gls (flatim, FLAT_C1(ccd), FLAT_C2(ccd),
+ FLAT_L1(ccd)+line-1)
+ if (illumim != NULL)
+ illumbuf = ccd_gls (illumim, ILLUM_C1(ccd), ILLUM_C2(ccd),
+ ILLUM_L1(ccd)+line-1)
+ if (fringeim != NULL)
+ fringebuf = ccd_gls (fringeim, FRINGE_C1(ccd), FRINGE_C2(ccd),
+ FRINGE_L1(ccd)+line-1)
+
+ call cor2s (line, CORS(ccd,1), Mems[outbuf],
+ Memr[overscan_vec], Mems[zerobuf], Mems[darkbuf],
+ Mems[flatbuf], Mems[illumbuf], Mems[fringebuf], ncols,
+ zeroim, flatim, darkscale, flatscale, illumscale, frgscale)
+
+ if (rep == YES)
+ call amaxks (Mems[outbuf], minrep, Mems[outbuf], ncols)
+ if (findmean == YES)
+ mean = mean + asums (Mems[outbuf], ncols)
+ }
+
+ do line = nlines+1, IM_LEN(out,2)-OUT_L1(ccd)+1
+ call amovs (
+ Mems[imgl2s(in,IN_L1(ccd)+line-1)+IN_C1(ccd)-OUT_C1(ccd)],
+ Mems[impl2s(out,OUT_L1(ccd)+line-1)], IM_LEN(out,1))
+
+ # Compute the mean from the sum of the output pixels.
+ if (findmean == YES)
+ MEAN(ccd) = mean / ncols / nlines
+
+ if (CORS(ccd, FIXPIX) == YES)
+ call lfixfrees ()
+end
+
+# PROC1 -- Process CCD images with readout axis 1 (lines).
+
+procedure proc1r (ccd)
+
+pointer ccd # CCD structure
+
+int i, line, nlin, ncols, nlines, findmean, rep
+int c1, c2, l1, l2
+real overscan, darkscale, flatscale, illumscale, frgscale, mean
+real minrep
+pointer in, out, zeroim, darkim, flatim, illumim, fringeim
+pointer outbuf, overscan_vec, zerobuf, darkbuf, flatbuf, illumbuf, fringebuf
+
+real asumr()
+pointer imgl2r(), impl2r(), ccd_glr()
+
+begin
+ # Initialize. If the correction image is 1D then just get the
+ # data once.
+
+ in = IN_IM(ccd)
+ out = OUT_IM(ccd)
+ nlin = IM_LEN(in,2)
+ ncols = OUT_C2(ccd) - OUT_C1(ccd) + 1
+ nlines = OUT_L2(ccd) - OUT_L1(ccd) + 1
+
+ if (CORS(ccd, FIXPIX) == YES)
+ call lfixinitr (in)
+
+ findmean = CORS(ccd, FINDMEAN)
+ if (findmean == YES)
+ mean = 0.
+ rep = CORS(ccd, MINREP)
+ if (rep == YES)
+ minrep = MINREPLACE(ccd)
+
+ overscan_vec = OVERSCAN_VEC(ccd)
+
+ if (CORS(ccd, ZEROCOR) == 0) {
+ zeroim = NULL
+ zerobuf = 1
+ } else if (IM_LEN(ZERO_IM(ccd),2) == 1) {
+ zeroim = NULL
+ zerobuf = ccd_glr (ZERO_IM(ccd), ZERO_C1(ccd), ZERO_C2(ccd), 1)
+ } else
+ zeroim = ZERO_IM(ccd)
+
+ if (CORS(ccd, DARKCOR) == 0) {
+ darkim = NULL
+ darkbuf = 1
+ } else if (IM_LEN(DARK_IM(ccd),2) == 1) {
+ darkim = NULL
+ darkbuf = ccd_glr (DARK_IM(ccd), DARK_C1(ccd), DARK_C2(ccd), 1)
+ darkscale = FLATSCALE(ccd)
+ } else {
+ darkim = DARK_IM(ccd)
+ darkscale = DARKSCALE(ccd)
+ }
+
+ if (CORS(ccd, FLATCOR) == 0) {
+ flatim = NULL
+ flatbuf = 1
+ } else if (IM_LEN(FLAT_IM(ccd),2) == 1) {
+ flatim = NULL
+ flatbuf = ccd_glr (FLAT_IM(ccd), FLAT_C1(ccd), FLAT_C2(ccd), 1)
+ flatscale = FLATSCALE(ccd)
+ } else {
+ flatim = FLAT_IM(ccd)
+ flatscale = FLATSCALE(ccd)
+ }
+
+ if (CORS(ccd, ILLUMCOR) == 0) {
+ illumim = NULL
+ illumbuf = 1
+ } else {
+ illumim = ILLUM_IM(ccd)
+ illumscale = ILLUMSCALE(ccd)
+ }
+
+ if (CORS(ccd, FRINGECOR) == 0) {
+ fringeim = NULL
+ fringebuf = 1
+ } else {
+ fringeim = FRINGE_IM(ccd)
+ frgscale = FRINGESCALE(ccd)
+ }
+
+ # For each line read lines from the input. Procedure CORINPUT
+ # replaces bad pixels by interpolation and applies a trim to the
+ # input. Get lines from the output image and from the zero level,
+ # dark count, flat field, illumination, and fringe images.
+ # Call COR1 to do the actual pixel corrections. Finally, add the
+ # output pixels to a sum for computing the mean.
+ # We must copy data outside of the output data section.
+
+ do line = 2 - OUT_L1(ccd), 0
+ call amovr (
+ Memr[imgl2r(in,IN_L1(ccd)+line-1)+IN_C1(ccd)-OUT_C1(ccd)],
+ Memr[impl2r(out,OUT_L1(ccd)+line-1)], IM_LEN(out,1))
+
+ do line = 1, nlines {
+ outbuf = impl2r (out, OUT_L1(ccd)+line-1)
+ call corinputr (in, line, ccd, Memr[outbuf], IM_LEN(out,1))
+
+ outbuf = outbuf + OUT_C1(ccd) - 1
+ if (overscan_vec != NULL)
+ overscan = Memr[overscan_vec+line-1]
+ if (zeroim != NULL)
+ zerobuf = ccd_glr (zeroim, ZERO_C1(ccd), ZERO_C2(ccd),
+ ZERO_L1(ccd)+line-1)
+ if (darkim != NULL)
+ darkbuf = ccd_glr (darkim, DARK_C1(ccd), DARK_C2(ccd),
+ DARK_L1(ccd)+line-1)
+ if (flatim != NULL)
+ flatbuf = ccd_glr (flatim, FLAT_C1(ccd), FLAT_C2(ccd),
+ FLAT_L1(ccd)+line-1)
+ if (illumim != NULL)
+ illumbuf = ccd_glr (illumim, ILLUM_C1(ccd), ILLUM_C2(ccd),
+ ILLUM_L1(ccd)+line-1)
+ if (fringeim != NULL)
+ fringebuf = ccd_glr (fringeim, FRINGE_C1(ccd), FRINGE_C2(ccd),
+ FRINGE_L1(ccd)+line-1)
+
+ if (OUT_SEC(ccd) == NULL) {
+ call cor1r (CORS(ccd,1), Memr[outbuf],
+ overscan, Memr[zerobuf], Memr[darkbuf],
+ Memr[flatbuf], Memr[illumbuf], Memr[fringebuf], ncols,
+ darkscale, flatscale, illumscale, frgscale)
+ } else {
+ do i = 1, IN_NSEC(ccd) {
+ l1 = OUT_SL1(ccd,i)
+ l2 = OUT_SL2(ccd,i)
+ if (line < l1 || line > l2)
+ next
+ c1 = OUT_SC1(ccd,i) - 1
+ c2 = OUT_SC2(ccd,i) - 1
+ ncols = c2 - c1 + 1
+ if (overscan_vec != NULL)
+ overscan = Memr[overscan_vec+(i-1)*nlin+line-l1]
+
+ call cor1r (CORS(ccd,1), Memr[outbuf+c1],
+ overscan, Memr[zerobuf+c1], Memr[darkbuf+c1],
+ Memr[flatbuf+c1], Memr[illumbuf+c1],
+ Memr[fringebuf+c1], ncols,
+ darkscale, flatscale, illumscale, frgscale)
+ }
+ }
+
+ if (rep == YES)
+ call amaxkr (Memr[outbuf], minrep, Memr[outbuf], ncols)
+ if (findmean == YES)
+ mean = mean + asumr (Memr[outbuf], ncols)
+ }
+
+ do line = nlines+1, IM_LEN(out,2)-OUT_L1(ccd)+1
+ call amovr (
+ Memr[imgl2r(in,IN_L1(ccd)+line-1)+IN_C1(ccd)-OUT_C1(ccd)],
+ Memr[impl2r(out,OUT_L1(ccd)+line-1)], IM_LEN(out,1))
+
+ # Compute the mean from the sum of the output pixels.
+ if (findmean == YES)
+ MEAN(ccd) = mean / ncols / nlines
+
+ if (CORS(ccd, FIXPIX) == YES)
+ call lfixfreer ()
+end
+
+
+# PROC2 -- Process CCD images with readout axis 2 (columns).
+
+procedure proc2r (ccd)
+
+pointer ccd # CCD structure
+
+int line, ncols, nlines, findmean, rep
+real darkscale, flatscale, illumscale, frgscale, mean
+real minrep
+pointer in, out, zeroim, darkim, flatim, illumim, fringeim
+pointer outbuf, overscan_vec, zerobuf, darkbuf, flatbuf, illumbuf, fringebuf
+
+real asumr()
+pointer imgl2r(), impl2r(), imgs2r(), ccd_glr()
+
+begin
+ # Initialize. If the correction image is 1D then just get the
+ # data once.
+
+ in = IN_IM(ccd)
+ out = OUT_IM(ccd)
+ ncols = OUT_C2(ccd) - OUT_C1(ccd) + 1
+ nlines = OUT_L2(ccd) - OUT_L1(ccd) + 1
+
+ if (CORS(ccd, FIXPIX) == YES)
+ call lfixinitr (in)
+
+ findmean = CORS(ccd, FINDMEAN)
+ if (findmean == YES)
+ mean = 0.
+ rep = CORS(ccd, MINREP)
+ if (rep == YES)
+ minrep = MINREPLACE(ccd)
+
+ overscan_vec = OVERSCAN_VEC(ccd)
+
+ if (CORS(ccd, ZEROCOR) == 0) {
+ zeroim = NULL
+ zerobuf = 1
+ } else if (IM_LEN(ZERO_IM(ccd),1) == 1) {
+ zeroim = NULL
+ zerobuf = imgs2r (ZERO_IM(ccd), 1, 1, ZERO_L1(ccd), ZERO_L2(ccd))
+ } else
+ zeroim = ZERO_IM(ccd)
+
+ if (CORS(ccd, DARKCOR) == 0) {
+ darkim = NULL
+ darkbuf = 1
+ } else if (IM_LEN(DARK_IM(ccd),1) == 1) {
+ darkim = NULL
+ darkbuf = imgs2r (DARK_IM(ccd), 1, 1, DARK_L1(ccd), DARK_L2(ccd))
+ darkscale = DARKSCALE(ccd)
+ } else {
+ darkim = DARK_IM(ccd)
+ darkscale = DARKSCALE(ccd)
+ }
+
+ if (CORS(ccd, FLATCOR) == 0) {
+ flatim = NULL
+ flatbuf = 1
+ } else if (IM_LEN(FLAT_IM(ccd),1) == 1) {
+ flatim = NULL
+ flatbuf = imgs2r (FLAT_IM(ccd), 1, 1, FLAT_L1(ccd), FLAT_L2(ccd))
+ flatscale = FLATSCALE(ccd)
+ } else {
+ flatim = FLAT_IM(ccd)
+ flatscale = FLATSCALE(ccd)
+ }
+
+ if (CORS(ccd, ILLUMCOR) == 0) {
+ illumim = NULL
+ illumbuf = 1
+ } else {
+ illumim = ILLUM_IM(ccd)
+ illumscale = ILLUMSCALE(ccd)
+ }
+
+ if (CORS(ccd, FRINGECOR) == 0) {
+ fringeim = NULL
+ fringebuf = 1
+ } else {
+ fringeim = FRINGE_IM(ccd)
+ frgscale = FRINGESCALE(ccd)
+ }
+
+ # For each line read lines from the input. Procedure CORINPUT
+ # replaces bad pixels by interpolation and applies a trim to the
+ # input. Get lines from the output image and from the zero level,
+ # dark count, flat field, illumination, and fringe images.
+ # Call COR2 to do the actual pixel corrections. Finally, add the
+ # output pixels to a sum for computing the mean.
+ # We must copy data outside of the output data section.
+
+ do line = 2 - OUT_L1(ccd), 0
+ call amovr (
+ Memr[imgl2r(in,IN_L1(ccd)+line-1)+IN_C1(ccd)-OUT_C1(ccd)],
+ Memr[impl2r(out,OUT_L1(ccd)+line-1)], IM_LEN(out,1))
+
+ do line = 1, nlines {
+ outbuf = impl2r (out, OUT_L1(ccd)+line-1)
+ call corinputr (in, line, ccd, Memr[outbuf], IM_LEN(out,1))
+
+ outbuf = outbuf + OUT_C1(ccd) - 1
+ if (zeroim != NULL)
+ zerobuf = ccd_glr (zeroim, ZERO_C1(ccd), ZERO_C2(ccd),
+ ZERO_L1(ccd)+line-1)
+ if (darkim != NULL)
+ darkbuf = ccd_glr (darkim, DARK_C1(ccd), DARK_C2(ccd),
+ DARK_L1(ccd)+line-1)
+ if (flatim != NULL)
+ flatbuf = ccd_glr (flatim, FLAT_C1(ccd), FLAT_C2(ccd),
+ FLAT_L1(ccd)+line-1)
+ if (illumim != NULL)
+ illumbuf = ccd_glr (illumim, ILLUM_C1(ccd), ILLUM_C2(ccd),
+ ILLUM_L1(ccd)+line-1)
+ if (fringeim != NULL)
+ fringebuf = ccd_glr (fringeim, FRINGE_C1(ccd), FRINGE_C2(ccd),
+ FRINGE_L1(ccd)+line-1)
+
+ call cor2r (line, CORS(ccd,1), Memr[outbuf],
+ Memr[overscan_vec], Memr[zerobuf], Memr[darkbuf],
+ Memr[flatbuf], Memr[illumbuf], Memr[fringebuf], ncols,
+ zeroim, flatim, darkscale, flatscale, illumscale, frgscale)
+
+ if (rep == YES)
+ call amaxkr (Memr[outbuf], minrep, Memr[outbuf], ncols)
+ if (findmean == YES)
+ mean = mean + asumr (Memr[outbuf], ncols)
+ }
+
+ do line = nlines+1, IM_LEN(out,2)-OUT_L1(ccd)+1
+ call amovr (
+ Memr[imgl2r(in,IN_L1(ccd)+line-1)+IN_C1(ccd)-OUT_C1(ccd)],
+ Memr[impl2r(out,OUT_L1(ccd)+line-1)], IM_LEN(out,1))
+
+ # Compute the mean from the sum of the output pixels.
+ if (findmean == YES)
+ MEAN(ccd) = mean / ncols / nlines
+
+ if (CORS(ccd, FIXPIX) == YES)
+ call lfixfreer ()
+end
+
diff --git a/noao/imred/quadred/src/ccdproc/hdrmap.com b/noao/imred/quadred/src/ccdproc/hdrmap.com
new file mode 100644
index 00000000..5aa74185
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/hdrmap.com
@@ -0,0 +1,4 @@
+# Common for HDRMAP package.
+
+pointer stp # Symbol table pointer
+common /hdmcom/ stp
diff --git a/noao/imred/quadred/src/ccdproc/hdrmap.x b/noao/imred/quadred/src/ccdproc/hdrmap.x
new file mode 100644
index 00000000..ebcb253e
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/hdrmap.x
@@ -0,0 +1,544 @@
+include <error.h>
+include <syserr.h>
+
+.help hdrmap
+.nf-----------------------------------------------------------------------------
+HDRMAP -- Map translation between task parameters and image header parameters.
+
+In order for tasks to be partially independent of the image header
+parameter names used by different instruments and observatories a
+translation is made between task parameters and image header
+parameters. This translation is given in a file consisting of the task
+parameter name, the image header parameter name, and an optional
+default value. This file is turned into a symbol table. If the
+translation file is not found a null pointer is returned. The package will
+then use the task parameter names directly. Also if there is no
+translation given in the file for a particular parameter it is passed
+on directly. If a parameter is not in the image header then the symbol
+table default value, if given, is returned. This package is layered on
+the IMIO header package.
+
+ hdmopen (fname)
+ hdmclose ()
+ hdmwrite (fname, mode)
+ hdmname (parameter, str, max_char)
+ hdmgdef (parameter, str, max_char)
+ hdmpdef (parameter, str, max_char)
+ y/n = hdmaccf (im, parameter)
+ hdmgstr (im, parameter, str, max_char)
+ ival = hdmgeti (im, parameter)
+ rval = hdmgetr (im, parameter)
+ hdmpstr (im, parameter, str)
+ hdmputi (im, parameter, value)
+ hdmputr (im, parameter, value)
+ hdmgstp (stp)
+ hdmpstp (stp)
+ hdmdelf (im, parameter)
+ hdmparm (name, parameter, max_char)
+
+hdmopen -- Open the translation file and map it into a symbol table pointer.
+hdmclose -- Close the symbol table pointer.
+hdmwrite -- Write out translation file.
+hdmname -- Return the image header parameter name.
+hdmpname -- Put the image header parameter name.
+hdmgdef -- Get the default value as a string (null if none).
+hdmpdef -- Put the default value as a string.
+hdmaccf -- Return whether the image header parameter exists (regardless of
+ whether there is a default value).
+hdmgstr -- Get a string valued parameter. Return default value if not in the
+ image header. Return null string if no default or image value.
+hdmgeti -- Get an integer valued parameter. Return default value if not in
+ the image header and error condition if no default or image value.
+hdmgetr -- Get a real valued parameter. Return default value if not in
+ the image header or error condition if no default or image value.
+hdmpstr -- Put a string valued parameter in the image header.
+hdmputi -- Put an integer valued parameter in the image header.
+hdmputr -- Put a real valued parameter in the image header.
+hdmgstp -- Get the symbol table pointer to save it while another map is used.
+hdmpstp -- Put the symbol table pointer to restore a map.
+hdmdelf -- Delete a field.
+hdmparm -- Return the parameter name corresponding to an image header name.
+.endhelp -----------------------------------------------------------------------
+
+# Symbol table definitions.
+define LEN_INDEX 32 # Length of symtab index
+define LEN_STAB 1024 # Length of symtab string buffer
+define SZ_SBUF 128 # Size of symtab string buffer
+
+define SZ_NAME 79 # Size of translation symbol name
+define SZ_DEFAULT 79 # Size of default string
+define SYMLEN 80 # Length of symbol structure
+
+# Symbol table structure
+define NAME Memc[P2C($1)] # Translation name for symbol
+define DEFAULT Memc[P2C($1+40)] # Default value of parameter
+
+
+# HDMOPEN -- Open the translation file and map it into a symbol table pointer.
+
+procedure hdmopen (fname)
+
+char fname[ARB] # Image header map file
+
+int fd, open(), fscan(), nscan(), errcode()
+pointer sp, parameter, sym, stopen(), stenter()
+include "hdrmap.com"
+
+begin
+ # Create an empty symbol table.
+ stp = stopen (fname, LEN_INDEX, LEN_STAB, SZ_SBUF)
+
+ # Return if file not found.
+ iferr (fd = open (fname, READ_ONLY, TEXT_FILE)) {
+ if (errcode () != SYS_FNOFNAME)
+ call erract (EA_WARN)
+ return
+ }
+
+ call smark (sp)
+ call salloc (parameter, SZ_NAME, TY_CHAR)
+
+ # Read the file an enter the translations in the symbol table.
+ while (fscan(fd) != EOF) {
+ call gargwrd (Memc[parameter], SZ_NAME)
+ if ((nscan() == 0) || (Memc[parameter] == '#'))
+ next
+ sym = stenter (stp, Memc[parameter], SYMLEN)
+ call gargwrd (NAME(sym), SZ_NAME)
+ call gargwrd (DEFAULT(sym), SZ_DEFAULT)
+ }
+
+ call close (fd)
+ call sfree (sp)
+end
+
+
+# HDMCLOSE -- Close the symbol table pointer.
+
+procedure hdmclose ()
+
+include "hdrmap.com"
+
+begin
+ if (stp != NULL)
+ call stclose (stp)
+end
+
+
+# HDMWRITE -- Write out translation file.
+
+procedure hdmwrite (fname, mode)
+
+char fname[ARB] # Image header map file
+int mode # Access mode (APPEND, NEW_FILE)
+
+int fd, open(), stridxs()
+pointer sym, sthead(), stnext(), stname()
+errchk open
+include "hdrmap.com"
+
+begin
+ # If there is no symbol table do nothing.
+ if (stp == NULL)
+ return
+
+ fd = open (fname, mode, TEXT_FILE)
+
+ sym = sthead (stp)
+ for (sym = sthead (stp); sym != NULL; sym = stnext (stp, sym)) {
+ if (stridxs (" ", Memc[stname (stp, sym)]) > 0)
+ call fprintf (fd, "'%s'%30t")
+ else
+ call fprintf (fd, "%s%30t")
+ call pargstr (Memc[stname (stp, sym)])
+ if (stridxs (" ", NAME(sym)) > 0)
+ call fprintf (fd, " '%s'%10t")
+ else
+ call fprintf (fd, " %s%10t")
+ call pargstr (NAME(sym))
+ if (DEFAULT(sym) != EOS) {
+ if (stridxs (" ", DEFAULT(sym)) > 0)
+ call fprintf (fd, " '%s'")
+ else
+ call fprintf (fd, " %s")
+ call pargstr (DEFAULT(sym))
+ }
+ call fprintf (fd, "\n")
+ }
+
+ call close (fd)
+end
+
+
+# HDMNAME -- Return the image header parameter name
+
+procedure hdmname (parameter, str, max_char)
+
+char parameter[ARB] # Parameter name
+char str[max_char] # String containing mapped parameter name
+int max_char # Maximum characters in string
+
+pointer sym, stfind()
+include "hdrmap.com"
+
+begin
+ if (stp != NULL)
+ sym = stfind (stp, parameter)
+ else
+ sym = NULL
+
+ if (sym != NULL)
+ call strcpy (NAME(sym), str, max_char)
+ else
+ call strcpy (parameter, str, max_char)
+end
+
+
+# HDMPNAME -- Put the image header parameter name
+
+procedure hdmpname (parameter, str)
+
+char parameter[ARB] # Parameter name
+char str[ARB] # String containing mapped parameter name
+
+pointer sym, stfind(), stenter()
+include "hdrmap.com"
+
+begin
+ if (stp == NULL)
+ return
+
+ sym = stfind (stp, parameter)
+ if (sym == NULL) {
+ sym = stenter (stp, parameter, SYMLEN)
+ DEFAULT(sym) = EOS
+ }
+
+ call strcpy (str, NAME(sym), SZ_NAME)
+end
+
+
+# HDMGDEF -- Get the default value as a string (null string if none).
+
+procedure hdmgdef (parameter, str, max_char)
+
+char parameter[ARB] # Parameter name
+char str[max_char] # String containing default value
+int max_char # Maximum characters in string
+
+pointer sym, stfind()
+include "hdrmap.com"
+
+begin
+ if (stp != NULL)
+ sym = stfind (stp, parameter)
+ else
+ sym = NULL
+
+ if (sym != NULL)
+ call strcpy (DEFAULT(sym), str, max_char)
+ else
+ str[1] = EOS
+end
+
+
+# HDMPDEF -- PUt the default value as a string.
+
+procedure hdmpdef (parameter, str)
+
+char parameter[ARB] # Parameter name
+char str[ARB] # String containing default value
+
+pointer sym, stfind(), stenter()
+include "hdrmap.com"
+
+begin
+ if (stp == NULL)
+ return
+
+ sym = stfind (stp, parameter)
+ if (sym == NULL) {
+ sym = stenter (stp, parameter, SYMLEN)
+ call strcpy (parameter, NAME(sym), SZ_NAME)
+ }
+
+ call strcpy (str, DEFAULT(sym), SZ_DEFAULT)
+end
+
+
+# HDMACCF -- Return whether the image header parameter exists (regardless of
+# whether there is a default value).
+
+int procedure hdmaccf (im, parameter)
+
+pointer im # IMIO pointer
+char parameter[ARB] # Parameter name
+
+int imaccf()
+pointer sym, stfind()
+include "hdrmap.com"
+
+begin
+ if (stp != NULL)
+ sym = stfind (stp, parameter)
+ else
+ sym = NULL
+
+ if (sym != NULL)
+ return (imaccf (im, NAME(sym)))
+ else
+ return (imaccf (im, parameter))
+end
+
+
+# HDMGSTR -- Get a string valued parameter. Return default value if not in
+# the image header. Return null string if no default or image value.
+
+procedure hdmgstr (im, parameter, str, max_char)
+
+pointer im # IMIO pointer
+char parameter[ARB] # Parameter name
+char str[max_char] # String value to return
+int max_char # Maximum characters in returned string
+
+pointer sym, stfind()
+include "hdrmap.com"
+
+begin
+ if (stp != NULL)
+ sym = stfind (stp, parameter)
+ else
+ sym = NULL
+
+ if (sym != NULL) {
+ iferr (call imgstr (im, NAME(sym), str, max_char))
+ call strcpy (DEFAULT(sym), str, max_char)
+ } else {
+ iferr (call imgstr (im, parameter, str, max_char))
+ str[1] = EOS
+ }
+end
+
+
+# HDMGETR -- Get a real valued parameter. Return default value if not in
+# the image header. Return error condition if no default or image value.
+
+real procedure hdmgetr (im, parameter)
+
+pointer im # IMIO pointer
+char parameter[ARB] # Parameter name
+
+int ip, ctor()
+real value, imgetr()
+pointer sym, stfind()
+include "hdrmap.com"
+
+begin
+ if (stp != NULL)
+ sym = stfind (stp, parameter)
+ else
+ sym = NULL
+
+ if (sym != NULL) {
+ iferr (value = imgetr (im, NAME(sym))) {
+ ip = 1
+ if (ctor (DEFAULT(sym), ip, value) == 0)
+ call error (0, "HDMGETR: No value found")
+ }
+ } else
+ value = imgetr (im, parameter)
+
+ return (value)
+end
+
+
+# HDMGETI -- Get an integer valued parameter. Return default value if not in
+# the image header. Return error condition if no default or image value.
+
+int procedure hdmgeti (im, parameter)
+
+pointer im # IMIO pointer
+char parameter[ARB] # Parameter name
+
+int ip, ctoi()
+int value, imgeti()
+pointer sym, stfind()
+include "hdrmap.com"
+
+begin
+ if (stp != NULL)
+ sym = stfind (stp, parameter)
+ else
+ sym = NULL
+
+ if (sym != NULL) {
+ iferr (value = imgeti (im, NAME(sym))) {
+ ip = 1
+ if (ctoi (DEFAULT(sym), ip, value) == 0)
+ call error (0, "HDMGETI: No value found")
+ }
+ } else
+ value = imgeti (im, parameter)
+
+ return (value)
+end
+
+
+# HDMPSTR -- Put a string valued parameter in the image header.
+
+procedure hdmpstr (im, parameter, str)
+
+pointer im # IMIO pointer
+char parameter[ARB] # Parameter name
+char str[ARB] # String value
+
+int imaccf(), imgftype()
+pointer sym, stfind()
+include "hdrmap.com"
+
+begin
+ if (stp != NULL)
+ sym = stfind (stp, parameter)
+ else
+ sym = NULL
+
+ if (sym != NULL) {
+ if (imaccf (im, NAME(sym)) == YES)
+ if (imgftype (im, NAME(sym)) != TY_CHAR)
+ call imdelf (im, NAME(sym))
+ call imastr (im, NAME(sym), str)
+ } else {
+ if (imaccf (im, parameter) == YES)
+ if (imgftype (im, parameter) != TY_CHAR)
+ call imdelf (im, parameter)
+ call imastr (im, parameter, str)
+ }
+end
+
+
+# HDMPUTI -- Put an integer valued parameter in the image header.
+
+procedure hdmputi (im, parameter, value)
+
+pointer im # IMIO pointer
+char parameter[ARB] # Parameter name
+int value # Integer value to put
+
+pointer sym, stfind()
+include "hdrmap.com"
+
+begin
+ if (stp != NULL)
+ sym = stfind (stp, parameter)
+ else
+ sym = NULL
+
+ if (sym != NULL)
+ call imaddi (im, NAME(sym), value)
+ else
+ call imaddi (im, parameter, value)
+end
+
+
+# HDMPUTR -- Put a real valued parameter in the image header.
+
+procedure hdmputr (im, parameter, value)
+
+pointer im # IMIO pointer
+char parameter[ARB] # Parameter name
+real value # Real value to put
+
+pointer sym, stfind()
+include "hdrmap.com"
+
+begin
+ if (stp != NULL)
+ sym = stfind (stp, parameter)
+ else
+ sym = NULL
+
+ if (sym != NULL)
+ call imaddr (im, NAME(sym), value)
+ else
+ call imaddr (im, parameter, value)
+end
+
+
+# HDMGSTP -- Get the symbol table pointer to save a translation map.
+# The symbol table is restored with HDMPSTP.
+
+procedure hdmgstp (ptr)
+
+pointer ptr # Symbol table pointer to return
+
+include "hdrmap.com"
+
+begin
+ ptr = stp
+end
+
+
+# HDMPSTP -- Put a symbol table pointer to restore a header map.
+# The symbol table is optained with HDMGSTP.
+
+procedure hdmpstp (ptr)
+
+pointer ptr # Symbol table pointer to restore
+
+include "hdrmap.com"
+
+begin
+ stp = ptr
+end
+
+
+# HDMDELF -- Delete a field. It is an error if the field does not exist.
+
+procedure hdmdelf (im, parameter)
+
+pointer im # IMIO pointer
+char parameter[ARB] # Parameter name
+
+pointer sym, stfind()
+include "hdrmap.com"
+
+begin
+ if (stp != NULL)
+ sym = stfind (stp, parameter)
+ else
+ sym = NULL
+
+ if (sym != NULL)
+ call imdelf (im, NAME(sym))
+ else
+ call imdelf (im, parameter)
+end
+
+
+# HDMPARAM -- Get parameter given the image header name.
+
+procedure hdmparam (name, parameter, max_char)
+
+char name[ARB] # Image header name
+char parameter[max_char] # Parameter
+int max_char # Maximum size of parameter string
+
+bool streq()
+pointer sym, sthead(), stname(), stnext()
+include "hdrmap.com"
+
+begin
+ if (stp != NULL)
+ sym = sthead (stp)
+ else
+ sym = NULL
+
+ while (sym != NULL) {
+ if (streq (NAME(sym), name)) {
+ call strcpy (Memc[stname(stp, sym)], parameter, max_char)
+ return
+ }
+ sym = stnext (stp, sym)
+ }
+ call strcpy (name, parameter, max_char)
+end
diff --git a/noao/imred/quadred/src/ccdproc/mkpkg b/noao/imred/quadred/src/ccdproc/mkpkg
new file mode 100644
index 00000000..7f263c15
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/mkpkg
@@ -0,0 +1,78 @@
+# Make QUADRED Package.
+
+$call relink
+$exit
+
+update:
+ $call relink
+ $call install
+ ;
+
+relink:
+ $update libpkg.a
+ $call quadred
+ ;
+
+install:
+ $move xx_quadred.e noaobin$x_quadred.e
+ ;
+
+quadred:
+ $omake x_quadred.x
+ $link x_quadred.o libpkg.a -lxtools -lcurfit -lgsurfit -lncar -lgks\
+ -o xx_quadred.e
+ ;
+
+generic:
+ $set GEN = "$$generic -k"
+
+ $ifolder (generic/ccdred.h, ccdred.h)
+ $copy ccdred.h generic/ccdred.h $endif
+ $ifolder (generic/proc.x, proc.gx)
+ $(GEN) proc.gx -o generic/proc.x $endif
+ $ifolder (generic/cor.x, cor.gx)
+ $(GEN) cor.gx -o generic/cor.x $endif
+ $ifolder (generic/corinput.x, corinput.gx)
+ $(GEN) corinput.gx -o generic/corinput.x $endif
+ ;
+
+libpkg.a:
+ $ifeq (USE_GENERIC, yes) $call generic $endif
+ @generic
+
+ calimage.x ccdtypes.h <error.h> <imset.h>
+ ccdcache.x ccdcache.com ccdcache.h <imhdr.h> <imset.h> <mach.h>\
+ ccdcache.com
+ ccdcheck.x ccdtypes.h <imhdr.h>
+ ccdcmp.x
+ ccddelete.x
+ ccdflag.x
+ ccdlog.x <imhdr.h> <imset.h>
+ ccdmean.x <imhdr.h>
+ ccdnscan.x ccdtypes.h
+ ccdproc.x ccdred.h ccdtypes.h <error.h>
+ ccdsection.x <ctype.h>
+ ccdsubsets.x
+ ccdtypes.x ccdtypes.h
+ doproc.x ccdred.h
+ hdrmap.x hdrmap.com <error.h>
+ readcor.x <imhdr.h>
+ scancor.x <imhdr.h> <imset.h>
+ setdark.x ccdred.h ccdtypes.h <imhdr.h>
+ setfixpix.x ccdred.h <imhdr.h>
+ setflat.x ccdred.h ccdtypes.h <imhdr.h>
+ setfringe.x ccdred.h ccdtypes.h <imhdr.h>
+ setheader.x ccdred.h <imhdr.h>
+ setillum.x ccdred.h ccdtypes.h <imhdr.h>
+ setinput.x ccdtypes.h <error.h>
+ setinteract.x <pkg/xtanswer.h>
+ setoutput.x <imhdr.h> <imset.h>
+ setoverscan.x ccdred.h <imhdr.h> <imset.h> <pkg/xtanswer.h>\
+ <pkg/gtools.h>
+ setproc.x ccdred.h <imhdr.h>
+ setsections.x ccdred.h <imhdr.h>
+ settrim.x ccdred.h <imhdr.h> <imset.h>
+ setzero.x ccdred.h ccdtypes.h <imhdr.h>
+ t_ccdproc.x ccdred.h ccdtypes.h <error.h> <imhdr.h>
+ timelog.x <time.h>
+ ;
diff --git a/noao/imred/quadred/src/ccdproc/proc.gx b/noao/imred/quadred/src/ccdproc/proc.gx
new file mode 100644
index 00000000..b6604179
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/proc.gx
@@ -0,0 +1,379 @@
+include <imhdr.h>
+include "ccdred.h"
+
+
+.help proc Feb87 noao.imred.ccdred
+.nf ----------------------------------------------------------------------------
+proc -- Process CCD images
+
+These are the main CCD reduction procedures. There is one for each
+readout axis (lines or columns) and one for short and real image data.
+They apply corrections for bad pixels, overscan levels, zero levels,
+dark counts, flat field response, illumination response, and fringe
+effects. The image is also trimmed if it was mapped with an image
+section. The mean value for the output image is computed when the flat
+field or illumination image is processed to form the scale factor for
+these calibrations in order to avoid reading through these image a
+second time.
+
+The processing information and parameters are specified in the CCD
+structure. The processing operations to be performed are specified by
+the correction array CORS in the ccd structure. There is one array
+element for each operation with indices defined symbolically by macro
+definitions (see ccdred.h); i.e. FLATCOR. The value of the array
+element is an integer bit field in which the bit set is the same as the
+array index; i.e element 3 will have the third bit set for an operation
+with array value 2**(3-1)=4. If an operation is not to be performed
+the bit is not set and the array element has the numeric value zero.
+Note that the addition of several correction elements gives a unique
+bit field describing a combination of operations. For efficiency the
+most common combinations are implemented as separate units.
+
+The CCD structure also contains the correction or calibration data
+consisting either pointers to data, IMIO pointers for the calibration
+images, and scale factors.
+
+The processing is performed line-by-line. The procedure CORINPUT is
+called to get an input line. This procedure trims and fixes bad pixels by
+interpolation. The output line and lines from the various calibration
+images are read. The image vectors as well as the overscan vector and
+the scale factors are passed to the procedure COR (which also
+dereferences the pointer data into simple arrays and variables). That
+procedure does the actual corrections apart from bad pixel
+corrections.
+
+The final optional step is to add each corrected output line to form a
+mean. This adds efficiency since the operation is done only if desired
+and the output image data is already in memory so there is no I/O
+penalty.
+
+SEE ALSO
+ ccdred.h, cor, fixpix, setfixpix, setoverscan, settrim,
+ setzero, setdark, setflat, setillum, setfringe
+.endhelp ----------------------------------------------------------------------
+
+
+$for (sr)
+# PROC1 -- Process CCD images with readout axis 1 (lines).
+
+procedure proc1$t (ccd)
+
+pointer ccd # CCD structure
+
+int i, line, nlin, ncols, nlines, findmean, rep
+int c1, c2, l1, l2
+real overscan, darkscale, flatscale, illumscale, frgscale, mean
+PIXEL minrep
+pointer in, out, zeroim, darkim, flatim, illumim, fringeim
+pointer outbuf, overscan_vec, zerobuf, darkbuf, flatbuf, illumbuf, fringebuf
+
+$if (datatype == csir)
+real asum$t()
+$else $if (datatype == ld)
+double asum$t()
+$else
+PIXEL asum$t()
+$endif $endif
+pointer imgl2$t(), impl2$t(), ccd_gl$t()
+
+begin
+ # Initialize. If the correction image is 1D then just get the
+ # data once.
+
+ in = IN_IM(ccd)
+ out = OUT_IM(ccd)
+ nlin = IM_LEN(in,2)
+ ncols = OUT_C2(ccd) - OUT_C1(ccd) + 1
+ nlines = OUT_L2(ccd) - OUT_L1(ccd) + 1
+
+ if (CORS(ccd, FIXPIX) == YES)
+ call lfixinit$t (in)
+
+ findmean = CORS(ccd, FINDMEAN)
+ if (findmean == YES)
+ mean = 0.
+ rep = CORS(ccd, MINREP)
+ if (rep == YES)
+ minrep = MINREPLACE(ccd)
+
+ overscan_vec = OVERSCAN_VEC(ccd)
+
+ if (CORS(ccd, ZEROCOR) == 0) {
+ zeroim = NULL
+ zerobuf = 1
+ } else if (IM_LEN(ZERO_IM(ccd),2) == 1) {
+ zeroim = NULL
+ zerobuf = ccd_gl$t (ZERO_IM(ccd), ZERO_C1(ccd), ZERO_C2(ccd), 1)
+ } else
+ zeroim = ZERO_IM(ccd)
+
+ if (CORS(ccd, DARKCOR) == 0) {
+ darkim = NULL
+ darkbuf = 1
+ } else if (IM_LEN(DARK_IM(ccd),2) == 1) {
+ darkim = NULL
+ darkbuf = ccd_gl$t (DARK_IM(ccd), DARK_C1(ccd), DARK_C2(ccd), 1)
+ darkscale = FLATSCALE(ccd)
+ } else {
+ darkim = DARK_IM(ccd)
+ darkscale = DARKSCALE(ccd)
+ }
+
+ if (CORS(ccd, FLATCOR) == 0) {
+ flatim = NULL
+ flatbuf = 1
+ } else if (IM_LEN(FLAT_IM(ccd),2) == 1) {
+ flatim = NULL
+ flatbuf = ccd_gl$t (FLAT_IM(ccd), FLAT_C1(ccd), FLAT_C2(ccd), 1)
+ flatscale = FLATSCALE(ccd)
+ } else {
+ flatim = FLAT_IM(ccd)
+ flatscale = FLATSCALE(ccd)
+ }
+
+ if (CORS(ccd, ILLUMCOR) == 0) {
+ illumim = NULL
+ illumbuf = 1
+ } else {
+ illumim = ILLUM_IM(ccd)
+ illumscale = ILLUMSCALE(ccd)
+ }
+
+ if (CORS(ccd, FRINGECOR) == 0) {
+ fringeim = NULL
+ fringebuf = 1
+ } else {
+ fringeim = FRINGE_IM(ccd)
+ frgscale = FRINGESCALE(ccd)
+ }
+
+ # For each line read lines from the input. Procedure CORINPUT
+ # replaces bad pixels by interpolation and applies a trim to the
+ # input. Get lines from the output image and from the zero level,
+ # dark count, flat field, illumination, and fringe images.
+ # Call COR1 to do the actual pixel corrections. Finally, add the
+ # output pixels to a sum for computing the mean.
+ # We must copy data outside of the output data section.
+
+ do line = 2 - OUT_L1(ccd), 0
+ call amov$t (
+ Mem$t[imgl2$t(in,IN_L1(ccd)+line-1)+IN_C1(ccd)-OUT_C1(ccd)],
+ Mem$t[impl2$t(out,OUT_L1(ccd)+line-1)], IM_LEN(out,1))
+
+ do line = 1, nlines {
+ outbuf = impl2$t (out, OUT_L1(ccd)+line-1)
+ call corinput$t (in, line, ccd, Mem$t[outbuf], IM_LEN(out,1))
+
+ outbuf = outbuf + OUT_C1(ccd) - 1
+ if (overscan_vec != NULL)
+ overscan = Memr[overscan_vec+line-1]
+ if (zeroim != NULL)
+ zerobuf = ccd_gl$t (zeroim, ZERO_C1(ccd), ZERO_C2(ccd),
+ ZERO_L1(ccd)+line-1)
+ if (darkim != NULL)
+ darkbuf = ccd_gl$t (darkim, DARK_C1(ccd), DARK_C2(ccd),
+ DARK_L1(ccd)+line-1)
+ if (flatim != NULL)
+ flatbuf = ccd_gl$t (flatim, FLAT_C1(ccd), FLAT_C2(ccd),
+ FLAT_L1(ccd)+line-1)
+ if (illumim != NULL)
+ illumbuf = ccd_gl$t (illumim, ILLUM_C1(ccd), ILLUM_C2(ccd),
+ ILLUM_L1(ccd)+line-1)
+ if (fringeim != NULL)
+ fringebuf = ccd_gl$t (fringeim, FRINGE_C1(ccd), FRINGE_C2(ccd),
+ FRINGE_L1(ccd)+line-1)
+
+ if (OUT_SEC(ccd) == NULL) {
+ call cor1$t (CORS(ccd,1), Mem$t[outbuf],
+ overscan, Mem$t[zerobuf], Mem$t[darkbuf],
+ Mem$t[flatbuf], Mem$t[illumbuf], Mem$t[fringebuf], ncols,
+ darkscale, flatscale, illumscale, frgscale)
+ } else {
+ do i = 1, IN_NSEC(ccd) {
+ l1 = OUT_SL1(ccd,i)
+ l2 = OUT_SL2(ccd,i)
+ if (line < l1 || line > l2)
+ next
+ c1 = OUT_SC1(ccd,i) - 1
+ c2 = OUT_SC2(ccd,i) - 1
+ ncols = c2 - c1 + 1
+ if (overscan_vec != NULL)
+ overscan = Memr[overscan_vec+(i-1)*nlin+line-l1]
+
+ call cor1$t (CORS(ccd,1), Mem$t[outbuf+c1],
+ overscan, Mem$t[zerobuf+c1], Mem$t[darkbuf+c1],
+ Mem$t[flatbuf+c1], Mem$t[illumbuf+c1],
+ Mem$t[fringebuf+c1], ncols,
+ darkscale, flatscale, illumscale, frgscale)
+ }
+ }
+
+ if (rep == YES)
+ call amaxk$t (Mem$t[outbuf], minrep, Mem$t[outbuf], ncols)
+ if (findmean == YES)
+ mean = mean + asum$t (Mem$t[outbuf], ncols)
+ }
+
+ do line = nlines+1, IM_LEN(out,2)-OUT_L1(ccd)+1
+ call amov$t (
+ Mem$t[imgl2$t(in,IN_L1(ccd)+line-1)+IN_C1(ccd)-OUT_C1(ccd)],
+ Mem$t[impl2$t(out,OUT_L1(ccd)+line-1)], IM_LEN(out,1))
+
+ # Compute the mean from the sum of the output pixels.
+ if (findmean == YES)
+ MEAN(ccd) = mean / ncols / nlines
+
+ if (CORS(ccd, FIXPIX) == YES)
+ call lfixfree$t ()
+end
+
+
+# PROC2 -- Process CCD images with readout axis 2 (columns).
+
+procedure proc2$t (ccd)
+
+pointer ccd # CCD structure
+
+int line, ncols, nlines, findmean, rep
+real darkscale, flatscale, illumscale, frgscale, mean
+PIXEL minrep
+pointer in, out, zeroim, darkim, flatim, illumim, fringeim
+pointer outbuf, overscan_vec, zerobuf, darkbuf, flatbuf, illumbuf, fringebuf
+
+$if (datatype == csir)
+real asum$t()
+$else $if (datatype == ld)
+double asum$t()
+$else
+PIXEL asum$t()
+$endif $endif
+pointer imgl2$t(), impl2$t(), imgs2$t(), ccd_gl$t()
+
+begin
+ # Initialize. If the correction image is 1D then just get the
+ # data once.
+
+ in = IN_IM(ccd)
+ out = OUT_IM(ccd)
+ ncols = OUT_C2(ccd) - OUT_C1(ccd) + 1
+ nlines = OUT_L2(ccd) - OUT_L1(ccd) + 1
+
+ if (CORS(ccd, FIXPIX) == YES)
+ call lfixinit$t (in)
+
+ findmean = CORS(ccd, FINDMEAN)
+ if (findmean == YES)
+ mean = 0.
+ rep = CORS(ccd, MINREP)
+ if (rep == YES)
+ minrep = MINREPLACE(ccd)
+
+ overscan_vec = OVERSCAN_VEC(ccd)
+
+ if (CORS(ccd, ZEROCOR) == 0) {
+ zeroim = NULL
+ zerobuf = 1
+ } else if (IM_LEN(ZERO_IM(ccd),1) == 1) {
+ zeroim = NULL
+ zerobuf = imgs2$t (ZERO_IM(ccd), 1, 1, ZERO_L1(ccd), ZERO_L2(ccd))
+ } else
+ zeroim = ZERO_IM(ccd)
+
+ if (CORS(ccd, DARKCOR) == 0) {
+ darkim = NULL
+ darkbuf = 1
+ } else if (IM_LEN(DARK_IM(ccd),1) == 1) {
+ darkim = NULL
+ darkbuf = imgs2$t (DARK_IM(ccd), 1, 1, DARK_L1(ccd), DARK_L2(ccd))
+ darkscale = DARKSCALE(ccd)
+ } else {
+ darkim = DARK_IM(ccd)
+ darkscale = DARKSCALE(ccd)
+ }
+
+ if (CORS(ccd, FLATCOR) == 0) {
+ flatim = NULL
+ flatbuf = 1
+ } else if (IM_LEN(FLAT_IM(ccd),1) == 1) {
+ flatim = NULL
+ flatbuf = imgs2$t (FLAT_IM(ccd), 1, 1, FLAT_L1(ccd), FLAT_L2(ccd))
+ flatscale = FLATSCALE(ccd)
+ } else {
+ flatim = FLAT_IM(ccd)
+ flatscale = FLATSCALE(ccd)
+ }
+
+ if (CORS(ccd, ILLUMCOR) == 0) {
+ illumim = NULL
+ illumbuf = 1
+ } else {
+ illumim = ILLUM_IM(ccd)
+ illumscale = ILLUMSCALE(ccd)
+ }
+
+ if (CORS(ccd, FRINGECOR) == 0) {
+ fringeim = NULL
+ fringebuf = 1
+ } else {
+ fringeim = FRINGE_IM(ccd)
+ frgscale = FRINGESCALE(ccd)
+ }
+
+ # For each line read lines from the input. Procedure CORINPUT
+ # replaces bad pixels by interpolation and applies a trim to the
+ # input. Get lines from the output image and from the zero level,
+ # dark count, flat field, illumination, and fringe images.
+ # Call COR2 to do the actual pixel corrections. Finally, add the
+ # output pixels to a sum for computing the mean.
+ # We must copy data outside of the output data section.
+
+ do line = 2 - OUT_L1(ccd), 0
+ call amov$t (
+ Mem$t[imgl2$t(in,IN_L1(ccd)+line-1)+IN_C1(ccd)-OUT_C1(ccd)],
+ Mem$t[impl2$t(out,OUT_L1(ccd)+line-1)], IM_LEN(out,1))
+
+ do line = 1, nlines {
+ outbuf = impl2$t (out, OUT_L1(ccd)+line-1)
+ call corinput$t (in, line, ccd, Mem$t[outbuf], IM_LEN(out,1))
+
+ outbuf = outbuf + OUT_C1(ccd) - 1
+ if (zeroim != NULL)
+ zerobuf = ccd_gl$t (zeroim, ZERO_C1(ccd), ZERO_C2(ccd),
+ ZERO_L1(ccd)+line-1)
+ if (darkim != NULL)
+ darkbuf = ccd_gl$t (darkim, DARK_C1(ccd), DARK_C2(ccd),
+ DARK_L1(ccd)+line-1)
+ if (flatim != NULL)
+ flatbuf = ccd_gl$t (flatim, FLAT_C1(ccd), FLAT_C2(ccd),
+ FLAT_L1(ccd)+line-1)
+ if (illumim != NULL)
+ illumbuf = ccd_gl$t (illumim, ILLUM_C1(ccd), ILLUM_C2(ccd),
+ ILLUM_L1(ccd)+line-1)
+ if (fringeim != NULL)
+ fringebuf = ccd_gl$t (fringeim, FRINGE_C1(ccd), FRINGE_C2(ccd),
+ FRINGE_L1(ccd)+line-1)
+
+ call cor2$t (line, CORS(ccd,1), Mem$t[outbuf],
+ Memr[overscan_vec], Mem$t[zerobuf], Mem$t[darkbuf],
+ Mem$t[flatbuf], Mem$t[illumbuf], Mem$t[fringebuf], ncols,
+ zeroim, flatim, darkscale, flatscale, illumscale, frgscale)
+
+ if (rep == YES)
+ call amaxk$t (Mem$t[outbuf], minrep, Mem$t[outbuf], ncols)
+ if (findmean == YES)
+ mean = mean + asum$t (Mem$t[outbuf], ncols)
+ }
+
+ do line = nlines+1, IM_LEN(out,2)-OUT_L1(ccd)+1
+ call amov$t (
+ Mem$t[imgl2$t(in,IN_L1(ccd)+line-1)+IN_C1(ccd)-OUT_C1(ccd)],
+ Mem$t[impl2$t(out,OUT_L1(ccd)+line-1)], IM_LEN(out,1))
+
+ # Compute the mean from the sum of the output pixels.
+ if (findmean == YES)
+ MEAN(ccd) = mean / ncols / nlines
+
+ if (CORS(ccd, FIXPIX) == YES)
+ call lfixfree$t ()
+end
+$endfor
diff --git a/noao/imred/quadred/src/ccdproc/readcor.x b/noao/imred/quadred/src/ccdproc/readcor.x
new file mode 100644
index 00000000..61fbd836
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/readcor.x
@@ -0,0 +1,138 @@
+include <imhdr.h>
+
+# READCOR -- Create a readout image.
+# Assume it is appropriate to perform this operation on the input image.
+# There is no CCD type checking.
+
+procedure readcor (input)
+
+char input[ARB] # Input image
+int readaxis # Readout axis
+
+int i, nc, nl, c1, c2, cs, l1, l2, ls
+int in_c1, in_c2, in_l1, in_l2, ccd_c1, ccd_c2, ccd_l1, ccd_l2
+pointer sp, output, str, in, out, data
+
+real asumr()
+int clgwrd()
+bool clgetb(), ccdflag()
+pointer immap(), imgl2r(), impl2r(), imps2r()
+errchk immap, ccddelete
+
+begin
+ # Check if this operation is desired.
+ if (!clgetb ("readcor"))
+ return
+
+ # Check if this operation has been done. Unfortunately this requires
+ # mapping the image.
+
+ in = immap (input, READ_ONLY, 0)
+ if (ccdflag (in, "readcor")) {
+ call imunmap (in)
+ return
+ }
+
+ if (clgetb ("noproc")) {
+ call eprintf (
+ " [TO BE DONE] Convert %s to readout correction\n")
+ call pargstr (input)
+ call imunmap (in)
+ return
+ }
+
+ call smark (sp)
+ call salloc (output, SZ_FNAME, TY_CHAR)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ # The default data section is the entire image.
+ nc = IM_LEN(in,1)
+ nl = IM_LEN(in,2)
+ c1 = 1
+ c2 = nc
+ cs = 1
+ l1 = 1
+ l2 = nl
+ ls = 1
+ call hdmgstr (in, "datasec", Memc[str], SZ_LINE)
+ call ccd_section (Memc[str], c1, c2, cs, l1, l2, ls)
+ if ((c1<1)||(c2>nc)||(l1<1)||(l2>nl)||(cs!=1)||(ls!=1))
+ call error (0, "Error in DATASEC parameter")
+ in_c1 = c1
+ in_c2 = c2
+ in_l1 = l1
+ in_l2 = l2
+
+ # The default ccd section is the data section.
+ call hdmgstr (in, "ccdsec", Memc[str], SZ_LINE)
+ call ccd_section (Memc[str], c1, c2, cs, l1, l2, ls)
+ if ((cs != 1) || (ls != 1))
+ call error (0, "Error in CCDSEC parameter")
+ ccd_c1 = c1
+ ccd_c2 = c2
+ ccd_l1 = l1
+ ccd_l2 = l2
+ if ((in_c2-in_c1 != ccd_c2-ccd_c1) || (in_l2-in_l1 != ccd_l2-ccd_l1))
+ call error (0, "Size of DATASEC and CCDSEC do not agree")
+
+ # Determine the readout axis.
+ readaxis = clgwrd ("readaxis", Memc[str], SZ_LINE, "|lines|columns|")
+
+ # Create output.
+ call mktemp ("tmp", Memc[output], SZ_FNAME)
+ call set_output (in, out, Memc[output])
+
+ # Average across the readout axis.
+ switch (readaxis) {
+ case 1:
+ IM_LEN(out,2) = 1
+ data = impl2r (out, 1)
+ call aclrr (Memr[data], nc)
+ nc = in_c2 - in_c1 + 1
+ nl = in_l2 - in_l1 + 1
+ data = data + in_c1 - 1
+ do i = in_l1, in_l2
+ call aaddr (Memr[imgl2r(in,i)+in_c1-1], Memr[data],
+ Memr[data], nc)
+ call adivkr (Memr[data], real (nl), Memr[data], nc)
+ call sprintf (Memc[str], SZ_LINE, "[%d:%d,1:1]")
+ call pargi (in_c1)
+ call pargi (in_c2)
+ call hdmpstr (out, "datasec", Memc[str])
+ call sprintf (Memc[str], SZ_LINE, "[%d:%d,*]")
+ call pargi (ccd_c1)
+ call pargi (ccd_c2)
+ call hdmpstr (out, "ccdsec", Memc[str])
+ case 2:
+ IM_LEN(out,1) = 1
+ data = imps2r (out, 1, 1, 1, nl)
+ call aclrr (Memr[data], nl)
+ nc = in_c2 - in_c1 + 1
+ nl = in_l2 - in_l1 + 1
+ do i = in_l1, in_l2
+ Memr[data+i-1] = asumr (Memr[imgl2r(in,i)+in_c1-1], nc) / nc
+ call sprintf (Memc[str], SZ_LINE, "[1:1,%d:%d]")
+ call pargi (in_l1)
+ call pargi (in_l2)
+ call hdmpstr (out, "datasec", Memc[str])
+ call sprintf (Memc[str], SZ_LINE, "[*,%d:%d]")
+ call pargi (ccd_l1)
+ call pargi (ccd_l2)
+ call hdmpstr (out, "ccdsec", Memc[str])
+ }
+
+ # Log the operation.
+ call sprintf (Memc[str], SZ_LINE,
+ "Converted to readout format")
+ call timelog (Memc[str], SZ_LINE)
+ call ccdlog (in, Memc[str])
+ call hdmpstr (out, "readcor", Memc[str])
+
+ # Replace the input image by the output image.
+ call imunmap (in)
+ call imunmap (out)
+ call ccddelete (input)
+ call imrename (Memc[output], input)
+
+ call sfree (sp)
+end
diff --git a/noao/imred/quadred/src/ccdproc/scancor.x b/noao/imred/quadred/src/ccdproc/scancor.x
new file mode 100644
index 00000000..6a5eb84c
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/scancor.x
@@ -0,0 +1,340 @@
+include <imhdr.h>
+include <imset.h>
+
+define SCANTYPES "|shortscan|longscan|"
+define SHORTSCAN 1 # Short scan accumulation, normal readout
+define LONGSCAN 2 # Long scan continuous readout
+
+# SCANCOR -- Create a scanned image from an unscanned image.
+
+procedure scancor (input, output, nscan, minreplace)
+
+char input[ARB] # Input image
+char output[ARB] # Output image (must be new image)
+int nscan # Number of scan lines
+real minreplace # Minmum value of output
+
+int scantype # Type of scan format
+int readaxis # Readout axis
+
+int clgwrd()
+pointer sp, str, in, out, immap()
+errchk immap
+
+begin
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ # Determine readout axis and create the temporary output image.
+ scantype = clgwrd ("scantype", Memc[str], SZ_LINE, SCANTYPES)
+ readaxis = clgwrd ("readaxis", Memc[str], SZ_LINE, "|lines|columns|")
+
+ # Make the output scanned image.
+ in = immap (input, READ_ONLY, 0)
+ call set_output (in, out, output)
+
+ switch (scantype) {
+ case SHORTSCAN:
+ call shortscan (in, out, nscan, minreplace, readaxis)
+ case LONGSCAN:
+ call longscan (in, out, readaxis)
+ }
+
+ # Log the operation.
+ switch (scantype) {
+ case SHORTSCAN:
+ call sprintf (Memc[str], SZ_LINE,
+ "Converted to shortscan from %s with nscan=%d")
+ call pargstr (input)
+ call pargi (nscan)
+ call hdmputi (out, "nscanrow", nscan)
+ case LONGSCAN:
+ call sprintf (Memc[str], SZ_LINE, "Converted to longscan from %s")
+ call pargstr (input)
+ }
+ call timelog (Memc[str], SZ_LINE)
+ call ccdlog (out, Memc[str])
+ call hdmpstr (out, "scancor", Memc[str])
+
+ call imunmap (in)
+ call imunmap (out)
+
+ call sfree (sp)
+end
+
+
+# SHORTSCAN -- Make a shortscan mode image by using a moving average.
+#
+# NOTE!! The value of nscan used here is increased by 1 because the
+# current information in the image header is actually the number of
+# scan steps and NOT the number of rows.
+
+procedure shortscan (in, out, nscan, minreplace, readaxis)
+
+pointer in # Input image
+pointer out # Output image
+int nscan # Number of lines scanned before readout
+real minreplace # Minimum output value
+int readaxis # Readout axis
+
+bool replace
+real nscanr, sum, mean, asumr()
+int i, j, k, l, len1, len2, nc, nl, nscani, c1, c2, cs, l1, l2, ls
+pointer sp, str, bufs, datain, dataout, data, imgl2r(), impl2r()
+long clktime()
+errchk malloc, calloc
+
+begin
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ # The default data section is the entire image.
+ len1 = IM_LEN(in,1)
+ len2 = IM_LEN(in,2)
+ c1 = 1
+ c2 = len1
+ cs = 1
+ l1 = 1
+ l2 = len2
+ ls = 1
+ call hdmgstr (in, "datasec", Memc[str], SZ_LINE)
+ call ccd_section (Memc[str], c1, c2, cs, l1, l2, ls)
+ if ((c1<1)||(c2>len1)||(l1<1)||(l2>len2)||(cs!=1)||(ls!=1))
+ call error (0, "Error in DATASEC parameter")
+ nc = c2 - c1 + 1
+ nl = l2 - l1 + 1
+
+ # Copy initial lines.
+ do i = 1, l1 - 1
+ call amovr (Memr[imgl2r(in,i)], Memr[impl2r(out,i)], len1)
+
+ replace = !IS_INDEF(minreplace)
+ mean = 0.
+ switch (readaxis) {
+ case 1:
+ nscani = max (1, min (nscan, nl) + 1)
+ nscanr = nscani
+ call imseti (in, IM_NBUFS, nscani)
+ call malloc (bufs, nscani, TY_INT)
+ call calloc (data, nc, TY_REAL)
+ j = 1
+ k = 1
+ l = 1
+
+ # Ramp up
+ while (j <= nscani) {
+ i = j + l1 - 1
+ datain = imgl2r (in, i)
+ if (nc < len1)
+ call amovr (Memr[datain], Memr[impl2r(out,i)], len1)
+ datain = datain + c1 - 1
+ Memi[bufs+mod(j,nscani)] = datain
+ call aaddr (Memr[data], Memr[datain], Memr[data], nc)
+ j = j + 1
+ }
+ dataout = impl2r (out, l+l1-1) + c1 - 1
+ call adivkr (Memr[data], nscanr, Memr[dataout], nc)
+ if (replace)
+ call amaxkr (Memr[dataout], minreplace, Memr[dataout], nc)
+ mean = mean + asumr (Memr[dataout], nc)
+ l = l + 1
+
+ # Moving average
+ while (j <= nl) {
+ datain = Memi[bufs+mod(k,nscani)]
+ call asubr (Memr[data], Memr[datain], Memr[data], nc)
+ i = j + l1 - 1
+ datain = imgl2r (in, i)
+ if (nc < len1)
+ call amovr (Memr[datain], Memr[impl2r(out,i)], len1)
+ datain = datain + c1 - 1
+ Memi[bufs+mod(j,nscani)] = datain
+ call aaddr (Memr[data], Memr[datain], Memr[data], nc)
+ dataout = impl2r (out, l+l1-1) + c1 - 1
+ call adivkr (Memr[data], nscanr, Memr[dataout], nc)
+ if (replace)
+ call amaxkr (Memr[dataout], minreplace, Memr[dataout], nc)
+ mean = mean + asumr (Memr[dataout], nc)
+
+ j = j + 1
+ k = k + 1
+ l = l + 1
+ }
+
+ # Ramp down.
+ while (l <= nl) {
+ datain = Memi[bufs+mod(k,nscani)]
+ call asubr (Memr[data], Memr[datain], Memr[data], nc)
+ dataout = impl2r (out, l+l1-1) + c1 - 1
+ call adivkr (Memr[data], nscanr, Memr[dataout], nc)
+ if (replace)
+ call amaxkr (Memr[dataout], minreplace, Memr[dataout], nc)
+ mean = mean + asumr (Memr[dataout], nc)
+
+ k = k + 1
+ l = l + 1
+ }
+
+ call mfree (bufs, TY_INT)
+ call mfree (data, TY_REAL)
+
+ case 2:
+ nscani = max (1, min (nscan, nc) + 1)
+ nscanr = nscani
+ do i = 1, nl {
+ datain = imgl2r (in, i + l1 - 1)
+ datain = datain + c1 - 1
+ data = impl2r (out, i + l1 - 1)
+ call amovr (Memr[datain], Memr[data], len1)
+ datain = datain + c1 - 1
+ data = data + c1 - 1
+ sum = 0
+ j = 0
+ k = 0
+ l = 0
+
+ # Ramp up
+ while (j < nscani) {
+ sum = sum + Memr[datain+j]
+ j = j + 1
+ }
+ if (replace)
+ Memr[data] = max (minreplace, sum / nscani)
+ else
+ Memr[data] = sum / nscani
+ mean = mean + Memr[data]
+ l = l + 1
+
+ # Moving average
+ while (j < nl) {
+ sum = sum + Memr[datain+j] - Memr[datain+k]
+ if (replace)
+ Memr[data+l] = max (minreplace, sum / nscani)
+ else
+ Memr[data+l] = sum / nscani
+ mean = mean + Memr[data+l]
+ j = j + 1
+ k = k + 1
+ l = l + 1
+ }
+
+ # Ramp down
+ while (l < nl) {
+ sum = sum - Memr[datain+k]
+ if (replace)
+ Memr[data+l] = max (minreplace, sum / nscani)
+ else
+ Memr[data+l] = sum / nscani
+ mean = mean + Memr[data+l]
+ k = k + 1
+ l = l + 1
+ }
+ }
+ }
+
+ # Copy final lines.
+ do i = l2+1, len2
+ call amovr (Memr[imgl2r(in,i)], Memr[impl2r(out,i)], len1)
+
+ mean = mean / nc / nl
+ call hdmputr (out, "ccdmean", mean)
+ call hdmputi (out, "ccdmeant", int (clktime (long (0))))
+
+ call sfree (sp)
+end
+
+
+# LONGSCAN -- Make a longscan mode readout flat field correction by averaging
+# across the readout axis.
+
+procedure longscan (in, out, readaxis)
+
+pointer in # Input image
+pointer out # Output image
+int readaxis # Readout axis
+
+int i, nc, nl, c1, c2, cs, l1, l2, ls
+int in_c1, in_c2, in_l1, in_l2, ccd_c1, ccd_c2, ccd_l1, ccd_l2
+real mean, asumr()
+long clktime()
+pointer sp, str, data, imgl2r(), impl2r(), imps2r()
+
+begin
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ # The default data section is the entire image.
+ nc = IM_LEN(in,1)
+ nl = IM_LEN(in,2)
+ c1 = 1
+ c2 = nc
+ cs = 1
+ l1 = 1
+ l2 = nl
+ ls = 1
+ call hdmgstr (in, "datasec", Memc[str], SZ_LINE)
+ call ccd_section (Memc[str], c1, c2, cs, l1, l2, ls)
+ if ((c1<1)||(c2>nc)||(l1<1)||(l2>nl)||(cs!=1)||(ls!=1))
+ call error (0, "Error in DATASEC parameter")
+ in_c1 = c1
+ in_c2 = c2
+ in_l1 = l1
+ in_l2 = l2
+
+ # The default ccd section is the data section.
+ call hdmgstr (in, "ccdsec", Memc[str], SZ_LINE)
+ call ccd_section (Memc[str], c1, c2, cs, l1, l2, ls)
+ if ((cs != 1) || (ls != 1))
+ call error (0, "Error in CCDSEC parameter")
+ ccd_c1 = c1
+ ccd_c2 = c2
+ ccd_l1 = l1
+ ccd_l2 = l2
+ if ((in_c2-in_c1 != ccd_c2-ccd_c1) || (in_l2-in_l1 != ccd_l2-ccd_l1))
+ call error (0, "Size of DATASEC and CCDSEC do not agree")
+
+ switch (readaxis) {
+ case 1:
+ IM_LEN(out,2) = 1
+ data = impl2r (out, 1)
+ call aclrr (Memr[data], nc)
+ nc = in_c2 - in_c1 + 1
+ nl = in_l2 - in_l1 + 1
+ data = data + in_c1 - 1
+ do i = in_l1, in_l2
+ call aaddr (Memr[imgl2r(in,i)+in_c1-1], Memr[data],
+ Memr[data], nc)
+ call adivkr (Memr[data], real (nl), Memr[data], nc)
+ call sprintf (Memc[str], SZ_LINE, "[%d:%d,1:1]")
+ call pargi (in_c1)
+ call pargi (in_c2)
+ call hdmpstr (out, "datasec", Memc[str])
+ call sprintf (Memc[str], SZ_LINE, "[%d:%d,*]")
+ call pargi (ccd_c1)
+ call pargi (ccd_c2)
+ call hdmpstr (out, "ccdsec", Memc[str])
+ mean = asumr (Memr[data], nc) / nl
+ case 2:
+ IM_LEN(out,1) = 1
+ data = imps2r (out, 1, 1, 1, nl)
+ call aclrr (Memr[data], nl)
+ nc = in_c2 - in_c1 + 1
+ nl = in_l2 - in_l1 + 1
+ do i = in_l1, in_l2
+ Memr[data+i-1] = asumr (Memr[imgl2r(in,i)+in_c1-1], nc) / nc
+ call sprintf (Memc[str], SZ_LINE, "[1:1,%d:%d]")
+ call pargi (in_l1)
+ call pargi (in_l2)
+ call hdmpstr (out, "datasec", Memc[str])
+ call sprintf (Memc[str], SZ_LINE, "[*,%d:%d]")
+ call pargi (ccd_l1)
+ call pargi (ccd_l2)
+ call hdmpstr (out, "ccdsec", Memc[str])
+ mean = asumr (Memr[data], nl) / nc
+ }
+
+ call hdmputr (out, "ccdmean", mean)
+ call hdmputi (out, "ccdmeant", int (clktime (long (0))))
+
+ call sfree (sp)
+end
diff --git a/noao/imred/quadred/src/ccdproc/setdark.x b/noao/imred/quadred/src/ccdproc/setdark.x
new file mode 100644
index 00000000..bf3c7354
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/setdark.x
@@ -0,0 +1,155 @@
+include <imhdr.h>
+include "ccdred.h"
+include "ccdtypes.h"
+
+
+# SET_DARK -- Set parameters for dark count correction.
+#
+# 1. Return immediately if the dark count correction is not requested or
+# if the image has been previously corrected.
+# 2. Get the dark count correction image and return an error if not found.
+# 3. If the dark count image has not been processed call PROC.
+# 4. Compute the dark count integration time scale factor.
+# 5. Set the processing flags.
+# 6. Log the operation (to user, logfile, and output image header).
+
+procedure set_dark (ccd)
+
+pointer ccd # CCD structure
+
+int nscan, nc, nl, c1, c2, cs, l1, l2, ls, data_c1, ccd_c1, data_l1, ccd_l1
+real darktime1, darktime2
+pointer sp, image, str, im
+
+bool clgetb(), ccdflag(), ccdcheck()
+int ccdnscan(), ccdtypei()
+real hdmgetr()
+pointer ccd_cache()
+errchk cal_image, ccd_cache, ccdproc, hdmgetr
+
+begin
+ # Check if the user wants this operation or it has already been done.
+ if (!clgetb ("darkcor") || ccdflag (IN_IM(ccd), "darkcor"))
+ return
+
+ call smark (sp)
+ call salloc (image, SZ_FNAME, TY_CHAR)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ # Get the dark count correction image name.
+ if (clgetb ("scancor"))
+ nscan = ccdnscan (IN_IM(ccd), ccdtypei(IN_IM(ccd)))
+ else
+ nscan = 1
+ call cal_image (IN_IM(ccd), DARK, nscan, Memc[image], SZ_FNAME)
+
+ # If no processing is desired print dark count image and return.
+ if (clgetb ("noproc")) {
+ call eprintf (" [TO BE DONE] Dark count correction image is %s.\n")
+ call pargstr (Memc[image])
+ call sfree (sp)
+ return
+ }
+
+ # Map the image and return on an error.
+ # Process the dark count image if necessary.
+ # If nscan > 1 then the dark may not yet exist so create it
+ # from the unscanned dark.
+
+ iferr (im = ccd_cache (Memc[image], DARK)) {
+ call cal_image (IN_IM(ccd), DARK, 1, Memc[str], SZ_LINE)
+ im = ccd_cache (Memc[str], DARK)
+ if (ccdcheck (im, DARK)) {
+ call ccd_flush (im)
+ call ccdproc (Memc[str], DARK)
+ }
+ call scancor (Memc[str], Memc[image], nscan, INDEF)
+ im = ccd_cache (Memc[image], DARK)
+ }
+
+ if (ccdcheck (im, DARK)) {
+ call ccd_flush (im)
+ call ccdproc (Memc[image], DARK)
+ im = ccd_cache (Memc[image], DARK)
+ }
+
+ # Set the processing parameters in the CCD structure.
+ nc = IM_LEN(im,1)
+ nl = IM_LEN(im,2)
+ c1 = 1
+ c2 = nc
+ l1 = 1
+ l2 = nl
+ cs = 1
+ ls = 1
+ call hdmgstr (im, "datasec", Memc[str], SZ_FNAME)
+ call ccd_section (Memc[str], c1, c2, cs, l1, l2, ls)
+ if ((c1<1)||(c2>nc)||(l1<1)||(l2>nl)||(cs!=1)||(ls!=1)) {
+ call sprintf (Memc[str], SZ_LINE,
+ "Data section error: image=%s[%d,%d], datasec=[%d:%d,%d:%d]")
+ call pargstr (Memc[image])
+ call pargi (nc)
+ call pargi (nl)
+ call pargi (c1)
+ call pargi (c2)
+ call pargi (l1)
+ call pargi (l2)
+ call error (0, Memc[str])
+ }
+ data_c1 = c1
+ data_l1 = l1
+ call hdmgstr (im, "ccdsec", Memc[str], SZ_FNAME)
+ call ccd_section (Memc[str], c1, c2, cs, l1, l2, ls)
+ if (nc == 1) {
+ c1 = CCD_C1(ccd)
+ c2 = CCD_C2(ccd)
+ }
+ if (nl == 1) {
+ l1 = CCD_L1(ccd)
+ l2 = CCD_L2(ccd)
+ }
+ ccd_c1 = c1
+ ccd_l1 = l1
+ if ((c1 > CCD_C1(ccd)) || (c2 < CCD_C2(ccd)) ||
+ (l1 > CCD_L1(ccd)) || (l2 < CCD_L2(ccd))) {
+ call sprintf (Memc[str], SZ_LINE,
+ "CCD section error: input=[%d:%d,%d:%d], %s=[%d:%d,%d:%d]")
+ call pargi (CCD_C1(ccd))
+ call pargi (CCD_C2(ccd))
+ call pargi (CCD_L1(ccd))
+ call pargi (CCD_L2(ccd))
+ call pargstr (Memc[image])
+ call pargi (c1)
+ call pargi (c2)
+ call pargi (l1)
+ call pargi (l2)
+ call error (0, Memc[str])
+ }
+
+ DARK_IM(ccd) = im
+ DARK_C1(ccd) = CCD_C1(ccd) - ccd_c1 + data_c1
+ DARK_C2(ccd) = CCD_C2(ccd) - ccd_c1 + data_c1
+ DARK_L1(ccd) = CCD_L1(ccd) - ccd_l1 + data_l1
+ DARK_L2(ccd) = CCD_L2(ccd) - ccd_l1 + data_l1
+
+ # Get the dark count integration times. Return an error if not found.
+ iferr (darktime1 = hdmgetr (IN_IM(ccd), "darktime"))
+ darktime1 = hdmgetr (IN_IM(ccd), "exptime")
+ iferr (darktime2 = hdmgetr (im, "darktime"))
+ darktime2 = hdmgetr (im, "exptime")
+
+ DARKSCALE(ccd) = darktime1 / darktime2
+ CORS(ccd, DARKCOR) = D
+ COR(ccd) = YES
+
+ # Record the operation in the output image and write a log record.
+ call sprintf (Memc[str], SZ_LINE,
+ "Dark count correction image is %s with scale=%g")
+ call pargstr (Memc[image])
+ call pargr (DARKSCALE(ccd))
+ call timelog (Memc[str], SZ_LINE)
+ call ccdlog (IN_IM(ccd), Memc[str])
+ call hdmpstr (OUT_IM(ccd), "darkcor", Memc[str])
+
+ call sfree (sp)
+end
diff --git a/noao/imred/quadred/src/ccdproc/setfixpix.x b/noao/imred/quadred/src/ccdproc/setfixpix.x
new file mode 100644
index 00000000..05866bed
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/setfixpix.x
@@ -0,0 +1,181 @@
+include <imhdr.h>
+include "ccdred.h"
+
+# SET_FIXPIX -- Setup for fixing bad pixels.
+#
+# 1. Return immediately if the bad pixel correction is not requested or
+# if the image has been previously corrected.
+# 2. Determine the bad pixel correction file. This may be specified
+# directly or indirectly through the image header or symbol table.
+# Return warning if not found.
+# 3. Read through the file collecting the bad pixel regions into a
+# bad column array (regions to be interpolated across columns) and
+# a bad line array (regions to be interpolated across lines).
+# 4. Set the processing flag.
+# 5. Log the operation (to user, logfile, and output image header).
+
+procedure set_fixpix (ccd)
+
+pointer ccd # CCD structure
+
+int fd, nc, nl, c1, c2, l1, l2, dc, dl, nbadcols, nbadlines
+pointer sp, image, str, badcols, badlines
+
+int open(), fscan(), nscan(), strmatch()
+bool clgetb(), streq(), ccdflag()
+errchk open
+
+begin
+ # Check if the user wants this operation or it has been done.
+ if (!clgetb ("fixpix") || ccdflag (IN_IM(ccd), "fixpix"))
+ return
+
+ call smark (sp)
+ call salloc (image, SZ_FNAME, TY_CHAR)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ # Get the bad pixel file. If the name is "image" then get the file
+ # name from the image header or symbol table.
+
+ call clgstr ("fixfile", Memc[image], SZ_FNAME)
+ if (streq (Memc[image], "image"))
+ call hdmgstr (IN_IM(ccd), "fixfile", Memc[image], SZ_FNAME)
+
+ # If no processing is desired print message and return.
+ if (clgetb ("noproc")) {
+ call eprintf (" [TO BE DONE] Bad pixel file is %s\n")
+ call pargstr (Memc[image])
+ call sfree (sp)
+ return
+ }
+
+ # Open the file and read the bad pixel regions. Use dynamic memory.
+ # Set the bad pixel coordinates. By default the bad pixel coordinates
+ # refer to the image directly but if the word "untrimmed" appears
+ # in a comment then the coordinates refer to the CCD coordinates.
+
+ fd = open (Memc[image], READ_ONLY, TEXT_FILE)
+ dc = 0
+ dl = 0
+ nc = IM_LEN(IN_IM(ccd),1)
+ nl = IM_LEN(IN_IM(ccd),2)
+ nbadcols = 0
+ nbadlines = 0
+ while (fscan (fd) != EOF) {
+ call gargwrd (Memc[str], SZ_LINE)
+ if (Memc[str] == '#') {
+ call gargstr (Memc[str], SZ_LINE)
+ if (strmatch (Memc[str], "{untrimmed}") != 0) {
+ dc = IN_C1(ccd) - CCD_C1(ccd)
+ dl = IN_L1(ccd) - CCD_L1(ccd)
+ }
+ next
+ }
+
+ call reset_scan()
+ call gargi (c1)
+ call gargi (c2)
+ call gargi (l1)
+ call gargi (l2)
+
+ # Ignore badly specified lines.
+ if (nscan() != 4) {
+ if (nscan() == 2) {
+ l1 = c2
+ c2 = c1
+ l2 = l1
+ } else
+ next
+ }
+
+ # Do the coordinate conversion.
+ c1 = max (IN_C1(ccd), c1 + dc)
+ c2 = min (IN_C2(ccd), c2 + dc)
+ l1 = max (IN_L1(ccd), l1 + dl)
+ l2 = min (IN_L2(ccd), l2 + dl)
+
+ # Ignore an inproperly specified region.
+ if ((c1 > c2) || (l1 > l2))
+ next
+
+ # Interpolate across the shortest direction.
+ if ((l2 - l1) < (c2 - c1)) {
+ nbadlines = nbadlines + 1
+ if (nbadlines == 1)
+ call calloc (badlines, 2*nl*nbadlines, TY_SHORT)
+ else {
+ call realloc (badlines, 2*nl*nbadlines, TY_SHORT)
+ call aclrs (Mems[badlines+2*nl*(nbadlines-1)], 2*nl)
+ }
+ call set_badcols (c1, c2, l1, l2, Mems[badlines],
+ nl, nbadlines)
+
+ } else {
+ nbadcols = nbadcols + 1
+ if (nbadcols == 1)
+ call calloc (badcols, 2*nl*nbadcols, TY_SHORT)
+ else {
+ call realloc (badcols, 2*nl*nbadcols, TY_SHORT)
+ call aclrs (Mems[badcols+2*nl*(nbadcols-1)], 2*nl)
+ }
+ call set_badcols (c1, c2, l1, l2, Mems[badcols],
+ nl, nbadcols)
+ }
+ }
+ call close (fd)
+
+ # Set structure parameters and the correction flags.
+ if (nbadcols != 0) {
+ NBADCOLS(ccd) = nbadcols
+ BADCOLS(ccd) = badcols
+ CORS(ccd, FIXPIX) = YES
+ COR(ccd) = YES
+ }
+ if (nbadlines != 0) {
+ NBADLINES(ccd) = nbadlines
+ BADLINES(ccd) = badlines
+ CORS(ccd, FIXPIX) = YES
+ COR(ccd) = YES
+ }
+
+ # Log the operation.
+ call sprintf (Memc[str], SZ_LINE, "Bad pixel file is %s")
+ call pargstr (Memc[image])
+ call timelog (Memc[str], SZ_LINE)
+ call ccdlog (IN_IM(ccd), Memc[str])
+ call hdmpstr (OUT_IM(ccd), "fixpix", Memc[str])
+
+ call sfree (sp)
+end
+
+
+# SET_BADCOLS -- Enter bad columns in a bad column array.
+# This procedure is used both for the line and column interpolation arrays.
+# The bad column array contains the starting and ending bad columns for
+# each line. This allows quick look up when processing the image at the
+# expense of memory. A column index of zero indicates no further bad columns
+# in the line.
+
+procedure set_badcols (c1, c2, l1, l2, array, nl, nbadcols)
+
+int c1, c2, l1, l2 # Bad column
+short array[2,nl,nbadcols] # Bad column array
+int nl # Number of image lines
+int nbadcols # Number of bad column areas
+
+int i, j
+
+begin
+ # For each line in the bad columns set the columns
+ # in the first unused entry in the array.
+
+ do i = l1, l2 {
+ do j = 1, nbadcols {
+ if (array[1,i,j] == 0) {
+ array[1,i,j] = c1
+ array[2,i,j] = c2
+ break
+ }
+ }
+ }
+end
diff --git a/noao/imred/quadred/src/ccdproc/setflat.x b/noao/imred/quadred/src/ccdproc/setflat.x
new file mode 100644
index 00000000..87713404
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/setflat.x
@@ -0,0 +1,146 @@
+include <imhdr.h>
+include "ccdred.h"
+include "ccdtypes.h"
+
+# SET_FLAT -- Set parameters for flat field correction.
+#
+# 1. Return immediately if the flat field correction is not requested or
+# if the image has been previously corrected.
+# 2. Get the flat field image and return on an error.
+# 3. If the flat field image has not been processed call PROC.
+# 4. Set the processing flags and record the operation in the output
+# image and write a log record.
+
+procedure set_flat (ccd)
+
+pointer ccd # CCD structure
+
+int nc, nl, c1, c2, cs, l1, l2, ls, data_c1, ccd_c1, data_l1, ccd_l1
+pointer sp, str, image, im, ccd_cache()
+bool clgetb(), ccdflag(), ccdcheck()
+int nscan, ccdnscan(), ccdtypei()
+real hdmgetr()
+errchk cal_image, ccd_cache, ccdproc, hdmgetr
+
+begin
+ # Check if the user wants this operation or if it has been done.
+ if (!clgetb ("flatcor") || ccdflag (IN_IM(ccd), "flatcor"))
+ return
+
+ call smark (sp)
+ call salloc (image, SZ_FNAME, TY_CHAR)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ # Get the flat field correction image.
+ if (clgetb ("scancor"))
+ nscan = ccdnscan (IN_IM(ccd), ccdtypei(IN_IM(ccd)))
+ else
+ nscan = 1
+ call cal_image (IN_IM(ccd), FLAT, nscan, Memc[image], SZ_FNAME)
+
+ # If no processing is desired print flat field image name and return.
+ if (clgetb ("noproc")) {
+ call eprintf (" [TO BE DONE] Flat correction image is %s.\n")
+ call pargstr (Memc[image])
+ call sfree (sp)
+ return
+ }
+
+ # Map the image and return on an error.
+ # Process the flat field image if necessary.
+ # If nscan > 1 then the flat field may not yet exist so create it
+ # from the unscanned flat field.
+
+ iferr (im = ccd_cache (Memc[image], FLAT)) {
+ call cal_image (IN_IM(ccd), FLAT, 1, Memc[str], SZ_LINE)
+ im = ccd_cache (Memc[str], FLAT)
+ if (ccdcheck (im, FLAT)) {
+ call ccd_flush (im)
+ call ccdproc (Memc[str], FLAT)
+ }
+ call scancor (Memc[str], Memc[image], nscan, MINREPLACE(ccd))
+ im = ccd_cache (Memc[image], FLAT)
+ }
+
+ if (ccdcheck (im, FLAT)) {
+ call ccd_flush (im)
+ call ccdproc (Memc[image], FLAT)
+ im = ccd_cache (Memc[image], FLAT)
+ }
+
+ # Set the processing parameters in the CCD structure.
+ nc = IM_LEN(im,1)
+ nl = IM_LEN(im,2)
+ c1 = 1
+ c2 = nc
+ l1 = 1
+ l2 = nl
+ cs = 1
+ ls = 1
+ call hdmgstr (im, "datasec", Memc[str], SZ_FNAME)
+ call ccd_section (Memc[str], c1, c2, cs, l1, l2, ls)
+ if ((c1<1)||(c2>nc)||(l1<1)||(l2>nl)||(cs!=1)||(ls!=1)) {
+ call sprintf (Memc[str], SZ_LINE,
+ "Data section error: image=%s[%d,%d], datasec=[%d:%d,%d:%d]")
+ call pargstr (Memc[image])
+ call pargi (nc)
+ call pargi (nl)
+ call pargi (c1)
+ call pargi (c2)
+ call pargi (l1)
+ call pargi (l2)
+ call error (0, Memc[str])
+ }
+ data_c1 = c1
+ data_l1 = l1
+ call hdmgstr (im, "ccdsec", Memc[str], SZ_FNAME)
+ call ccd_section (Memc[str], c1, c2, cs, l1, l2, ls)
+ if (nc == 1) {
+ c1 = CCD_C1(ccd)
+ c2 = CCD_C2(ccd)
+ }
+ if (nl == 1) {
+ l1 = CCD_L1(ccd)
+ l2 = CCD_L2(ccd)
+ }
+ ccd_c1 = c1
+ ccd_l1 = l1
+ if ((c1 > CCD_C1(ccd)) || (c2 < CCD_C2(ccd)) ||
+ (l1 > CCD_L1(ccd)) || (l2 < CCD_L2(ccd))) {
+ call sprintf (Memc[str], SZ_LINE,
+ "CCD section error: input=[%d:%d,%d:%d], %s=[%d:%d,%d:%d]")
+ call pargi (CCD_C1(ccd))
+ call pargi (CCD_C2(ccd))
+ call pargi (CCD_L1(ccd))
+ call pargi (CCD_L2(ccd))
+ call pargstr (Memc[image])
+ call pargi (c1)
+ call pargi (c2)
+ call pargi (l1)
+ call pargi (l2)
+ call error (0, Memc[str])
+ }
+
+ FLAT_IM(ccd) = im
+ FLAT_C1(ccd) = CCD_C1(ccd) - ccd_c1 + data_c1
+ FLAT_C2(ccd) = CCD_C2(ccd) - ccd_c1 + data_c1
+ FLAT_L1(ccd) = CCD_L1(ccd) - ccd_l1 + data_l1
+ FLAT_L2(ccd) = CCD_L2(ccd) - ccd_l1 + data_l1
+
+ # If no mean value use 1 as the scale factor.
+ iferr (FLATSCALE(ccd) = hdmgetr (im, "ccdmean"))
+ FLATSCALE(ccd) = 1.
+ CORS(ccd, FLATCOR) = F
+ COR(ccd) = YES
+
+ # Log the operation.
+ call sprintf (Memc[str], SZ_LINE,
+ "Flat field image is %s with scale=%g")
+ call pargstr (Memc[image])
+ call pargr (FLATSCALE(ccd))
+ call timelog (Memc[str], SZ_LINE)
+ call ccdlog (IN_IM(ccd), Memc[str])
+ call hdmpstr (OUT_IM(ccd), "flatcor", Memc[str])
+
+ call sfree (sp)
+end
diff --git a/noao/imred/quadred/src/ccdproc/setfringe.x b/noao/imred/quadred/src/ccdproc/setfringe.x
new file mode 100644
index 00000000..7055f35f
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/setfringe.x
@@ -0,0 +1,123 @@
+include <imhdr.h>
+include "ccdred.h"
+include "ccdtypes.h"
+
+# SET_FRINGE -- Set parameters for fringe correction.
+#
+# 1. Return immediately if the fringe correction is not requested or
+# if the image has been previously corrected.
+# 2. Get the fringe image and return error if the mkfringe flag is missing.
+# 3. Set the processing flags and record the operation in the output
+# image and write a log record.
+
+procedure set_fringe (ccd)
+
+pointer ccd # CCD structure
+
+int nc, nl, c1, c2, cs, l1, l2, ls, data_c1, ccd_c1, data_l1, ccd_l1
+real exptime1, exptime2, fringescale
+pointer sp, str, image, im
+
+bool clgetb(), ccdflag()
+real hdmgetr()
+pointer ccd_cache()
+errchk cal_image, ccd_cache, ccdproc, hdmgetr
+
+begin
+ # Check if the user wants this operation or if it has been done.
+ if (!clgetb ("fringecor") || ccdflag (IN_IM(ccd), "fringcor"))
+ return
+
+ call smark (sp)
+ call salloc (image, SZ_FNAME, TY_CHAR)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ # Get the fringe correction image.
+ call cal_image (IN_IM(ccd), FRINGE, 1, Memc[image], SZ_FNAME)
+
+ # If no processing is desired print fringe image name and return.
+ if (clgetb ("noproc")) {
+ call eprintf (
+ " [TO BE DONE] Fringe correction image is %s.\n")
+ call pargstr (Memc[image])
+ call sfree (sp)
+ return
+ }
+
+ # Return an error if the fringe flag is missing.
+ im = ccd_cache (Memc[image], FRINGE)
+ if (!ccdflag (im, "mkfringe"))
+ call error (0, "MKFRINGE flag missing from fringe image.")
+
+ # Set the processing parameters in the CCD structure.
+ nc = IM_LEN(im,1)
+ nl = IM_LEN(im,2)
+ c1 = 1
+ c2 = nc
+ l1 = 1
+ l2 = nl
+ cs = 1
+ ls = 1
+ call hdmgstr (im, "datasec", Memc[str], SZ_FNAME)
+ call ccd_section (Memc[str], c1, c2, cs, l1, l2, ls)
+ if ((c1<1)||(c2>nc)||(l1<1)||(l2>nl)||(cs!=1)||(ls!=1)) {
+ call sprintf (Memc[str], SZ_LINE,
+ "Data section error: image=%s[%d,%d], datasec=[%d:%d,%d:%d]")
+ call pargstr (Memc[image])
+ call pargi (nc)
+ call pargi (nl)
+ call pargi (c1)
+ call pargi (c2)
+ call pargi (l1)
+ call pargi (l2)
+ call error (0, Memc[str])
+ }
+ data_c1 = c1
+ data_l1 = l1
+ call hdmgstr (im, "ccdsec", Memc[str], SZ_FNAME)
+ call ccd_section (Memc[str], c1, c2, cs, l1, l2, ls)
+ ccd_c1 = c1
+ ccd_l1 = l1
+ if ((c1 > CCD_C1(ccd)) || (c2 < CCD_C2(ccd)) ||
+ (l1 > CCD_L1(ccd)) || (l2 < CCD_L2(ccd))) {
+ call sprintf (Memc[str], SZ_LINE,
+ "CCD section error: input=[%d:%d,%d:%d], %s=[%d:%d,%d:%d]")
+ call pargi (CCD_C1(ccd))
+ call pargi (CCD_C2(ccd))
+ call pargi (CCD_L1(ccd))
+ call pargi (CCD_L2(ccd))
+ call pargstr (Memc[image])
+ call pargi (c1)
+ call pargi (c2)
+ call pargi (l1)
+ call pargi (l2)
+ call error (0, Memc[str])
+ }
+
+ FRINGE_IM(ccd) = im
+ FRINGE_C1(ccd) = CCD_C1(ccd) - ccd_c1 + data_c1
+ FRINGE_C2(ccd) = CCD_C2(ccd) - ccd_c1 + data_c1
+ FRINGE_L1(ccd) = CCD_L1(ccd) - ccd_l1 + data_l1
+ FRINGE_L2(ccd) = CCD_L2(ccd) - ccd_l1 + data_l1
+
+ # Get the scaling factors. If no fringe scale factor assume 1.
+ exptime1 = hdmgetr (IN_IM(ccd), "exptime")
+ exptime2 = hdmgetr (im, "exptime")
+ iferr (fringescale = hdmgetr (im, "fringscl"))
+ fringescale = 1.
+
+ FRINGESCALE(ccd) = exptime1 / exptime2 * fringescale
+ CORS(ccd, FRINGECOR) = Q
+ COR(ccd) = YES
+
+ # Log the operation.
+ call sprintf (Memc[str], SZ_LINE,
+ "Fringe image is %s with scale=%g")
+ call pargstr (Memc[image])
+ call pargr (FRINGESCALE(ccd))
+ call timelog (Memc[str], SZ_LINE)
+ call ccdlog (IN_IM(ccd), Memc[str])
+ call hdmpstr (OUT_IM(ccd), "fringcor", Memc[str])
+
+ call sfree (sp)
+end
diff --git a/noao/imred/quadred/src/ccdproc/setheader.x b/noao/imred/quadred/src/ccdproc/setheader.x
new file mode 100644
index 00000000..5687612d
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/setheader.x
@@ -0,0 +1,76 @@
+include <imhdr.h>
+include "ccdred.h"
+
+# SET_HEADER -- Set the output image header.
+
+procedure set_header (ccd)
+
+pointer ccd # CCD structure
+
+int nc, nl
+pointer sp, str, out
+long clktime()
+
+begin
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ out = OUT_IM(ccd)
+ nc = IM_LEN(out,1)
+ nl = IM_LEN(out,2)
+
+ # Set the data section if it is not the whole image.
+ if ((OUT_C1(ccd) != 1) || (OUT_C2(ccd) != nc) ||
+ (OUT_L1(ccd) != 1) || (OUT_L2(ccd) != nl)) {
+ call sprintf (Memc[str], SZ_LINE, "[%d:%d,%d:%d]")
+ call pargi (OUT_C1(ccd))
+ call pargi (OUT_C2(ccd))
+ call pargi (OUT_L1(ccd))
+ call pargi (OUT_L2(ccd))
+ call hdmpstr (out, "datasec", Memc[str])
+ } else {
+ iferr (call hdmdelf (out, "datasec"))
+ ;
+ }
+
+ # Set the CCD section.
+ call sprintf (Memc[str], SZ_LINE, "[%d:%d,%d:%d]")
+ call pargi (CCD_C1(ccd))
+ call pargi (CCD_C2(ccd))
+ call pargi (CCD_L1(ccd))
+ call pargi (CCD_L2(ccd))
+ call hdmpstr (out, "ccdsec", Memc[str])
+
+ # If trimming update the trim and bias section parameters.
+ if (CORS(ccd, TRIM) == YES) {
+ iferr (call hdmdelf (out, "trimsec"))
+ ;
+ iferr (call hdmdelf (out, "biassec"))
+ ;
+ BIAS_C1(ccd) = max (1, BIAS_C1(ccd) - TRIM_C1(ccd) + 1)
+ BIAS_C2(ccd) = min (nc, BIAS_C2(ccd) - TRIM_C1(ccd) + 1)
+ BIAS_L1(ccd) = max (1, BIAS_L1(ccd) - TRIM_L1(ccd) + 1)
+ BIAS_L2(ccd) = min (nl, BIAS_L2(ccd) - TRIM_L1(ccd) + 1)
+ if ((BIAS_C1(ccd)<=BIAS_C2(ccd)) && (BIAS_L1(ccd)<=BIAS_L2(ccd))) {
+ call sprintf (Memc[str], SZ_LINE, "[%d:%d,%d:%d]")
+ call pargi (BIAS_C1(ccd))
+ call pargi (BIAS_C2(ccd))
+ call pargi (BIAS_L1(ccd))
+ call pargi (BIAS_L2(ccd))
+ call hdmpstr (out, "biassec", Memc[str])
+ }
+ }
+
+ # Set mean value if desired.
+ if (CORS(ccd, FINDMEAN) == YES) {
+ call hdmputr (out, "ccdmean", MEAN(ccd))
+ call hdmputi (out, "ccdmeant", int (clktime (long (0))))
+ }
+
+ # Mark image as processed.
+ call sprintf (Memc[str], SZ_LINE, "CCD processing done")
+ call timelog (Memc[str], SZ_LINE)
+ call hdmpstr (out, "ccdproc", Memc[str])
+
+ call sfree (sp)
+end
diff --git a/noao/imred/quadred/src/ccdproc/setillum.x b/noao/imred/quadred/src/ccdproc/setillum.x
new file mode 100644
index 00000000..d1677301
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/setillum.x
@@ -0,0 +1,132 @@
+include <imhdr.h>
+include "ccdred.h"
+include "ccdtypes.h"
+
+# SET_ILLUM -- Set parameters for illumination correction.
+#
+# 1. Return immediately if the illumination correction is not requested or
+# if the image has been previously corrected.
+# 2. Get the illumination image and return error if mkillum flag missing.
+# 3. Set the processing flags and record the operation in the output
+# image and write a log record.
+
+procedure set_illum (ccd)
+
+pointer ccd # CCD structure
+
+int nc, nl, c1, c2, cs, l1, l2, ls, data_c1, ccd_c1, data_l1, ccd_l1
+long time
+pointer sp, str, image, im
+
+bool clgetb(), ccdflag()
+long hdmgeti()
+real hdmgetr()
+pointer ccd_cache()
+errchk cal_image, ccd_cache, ccdproc, hdmgetr, hdmgeti
+
+begin
+ # Check if the user wants this operation or if it has been done.
+ if (!clgetb ("illumcor") || ccdflag (IN_IM(ccd), "illumcor"))
+ return
+
+ call smark (sp)
+ call salloc (image, SZ_FNAME, TY_CHAR)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ # Get the illumcor correction image.
+ call cal_image (IN_IM(ccd), ILLUM, 1, Memc[image], SZ_FNAME)
+
+ # If no processing is desired print illumination image name and return.
+ if (clgetb ("noproc")) {
+ call eprintf (
+ " [TO BE DONE] Illumination correction image is %s.\n")
+ call pargstr (Memc[image])
+ call sfree (sp)
+ return
+ }
+
+ # Return a warning if the illumination flag is missing.
+ im = ccd_cache (Memc[image], ILLUM)
+ if (!ccdflag (im, "mkillum")) {
+ call ccd_flush (im)
+ call error (0, "MKILLUM flag missing from illumination image")
+ }
+
+ # If no mean value for the scale factor compute it.
+ iferr (ILLUMSCALE(ccd) = hdmgetr (im, "ccdmean"))
+ ILLUMSCALE(ccd) = INDEF
+ iferr (time = hdmgeti (im, "ccdmeant"))
+ time = IM_MTIME(im)
+ if (IS_INDEF(ILLUMSCALE(ccd)) || time < IM_MTIME(im)) {
+ call ccd_flush (im)
+ call ccdmean (Memc[image])
+ im = ccd_cache (Memc[image], ILLUM)
+ }
+ iferr (ILLUMSCALE(ccd) = hdmgetr (im, "ccdmean"))
+ ILLUMSCALE(ccd) = 1.
+
+ # Set the processing parameters in the CCD structure.
+ nc = IM_LEN(im,1)
+ nl = IM_LEN(im,2)
+ c1 = 1
+ c2 = nc
+ l1 = 1
+ l2 = nl
+ cs = 1
+ ls = 1
+ call hdmgstr (im, "datasec", Memc[str], SZ_FNAME)
+ call ccd_section (Memc[str], c1, c2, cs, l1, l2, ls)
+ if ((c1<1)||(c2>nc)||(l1<1)||(l2>nl)||(cs!=1)||(ls!=1)) {
+ call sprintf (Memc[str], SZ_LINE,
+ "Data section error: image=%s[%d,%d], datasec=[%d:%d,%d:%d]")
+ call pargstr (Memc[image])
+ call pargi (nc)
+ call pargi (nl)
+ call pargi (c1)
+ call pargi (c2)
+ call pargi (l1)
+ call pargi (l2)
+ call error (0, Memc[str])
+ }
+ data_c1 = c1
+ data_l1 = l1
+ call hdmgstr (im, "ccdsec", Memc[str], SZ_FNAME)
+ call ccd_section (Memc[str], c1, c2, cs, l1, l2, ls)
+ ccd_c1 = c1
+ ccd_l1 = l1
+ if ((c1 > CCD_C1(ccd)) || (c2 < CCD_C2(ccd)) ||
+ (l1 > CCD_L1(ccd)) || (l2 < CCD_L2(ccd))) {
+ call sprintf (Memc[str], SZ_LINE,
+ "CCD section error: input=[%d:%d,%d:%d], %s=[%d:%d,%d:%d]")
+ call pargi (CCD_C1(ccd))
+ call pargi (CCD_C2(ccd))
+ call pargi (CCD_L1(ccd))
+ call pargi (CCD_L2(ccd))
+ call pargstr (Memc[image])
+ call pargi (c1)
+ call pargi (c2)
+ call pargi (l1)
+ call pargi (l2)
+ call error (0, Memc[str])
+ }
+
+ ILLUM_IM(ccd) = im
+ ILLUM_C1(ccd) = CCD_C1(ccd) - ccd_c1 + data_c1
+ ILLUM_C2(ccd) = CCD_C2(ccd) - ccd_c1 + data_c1
+ ILLUM_L1(ccd) = CCD_L1(ccd) - ccd_l1 + data_l1
+ ILLUM_L2(ccd) = CCD_L2(ccd) - ccd_l1 + data_l1
+
+ CORS(ccd, ILLUMCOR) = I
+ COR(ccd) = YES
+
+ # Log the operation.
+ call sprintf (Memc[str], SZ_LINE,
+ "Illumination image is %s with scale=%g")
+ call pargstr (Memc[image])
+ call pargr (ILLUMSCALE(ccd))
+ call timelog (Memc[str], SZ_LINE)
+ call ccdlog (IN_IM(ccd), Memc[str])
+ call hdmpstr (OUT_IM(ccd), "illumcor", Memc[str])
+
+ call sfree (sp)
+end
diff --git a/noao/imred/quadred/src/ccdproc/setinput.x b/noao/imred/quadred/src/ccdproc/setinput.x
new file mode 100644
index 00000000..3d3170db
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/setinput.x
@@ -0,0 +1,48 @@
+include <error.h>
+include "ccdtypes.h"
+
+# SET_INPUT -- Set the input image and image type.
+#
+# 1. Open the input image. Return warning and NULL pointer for an error.
+# 2. Get the requested CCD image type.
+# a. If no type is requested then accept the image.
+# b. If a type is requested then match against the image type.
+# Unmap the image if no match.
+# 3. If the image is acceptable then get the CCD type code.
+
+procedure set_input (image, im, ccdtype)
+
+char image[ARB] # Input image name
+pointer im # IMIO pointer (returned)
+int ccdtype # CCD image type
+
+bool strne()
+int ccdtypei()
+pointer sp, str1, str2, immap()
+
+begin
+ # Open the image. Return a warning and NULL pointer for an error.
+ iferr (im = immap (image, READ_ONLY, 0)) {
+ call erract (EA_WARN)
+ im = NULL
+ return
+ }
+
+ call smark (sp)
+ call salloc (str1, SZ_LINE, TY_CHAR)
+ call salloc (str2, SZ_LINE, TY_CHAR)
+
+ # Get the requested CCD type.
+ call clgstr ("ccdtype", Memc[str1], SZ_LINE)
+ call xt_stripwhite (Memc[str1])
+ if (Memc[str1] != EOS) {
+ call ccdtypes (im, Memc[str2], SZ_LINE)
+ if (strne (Memc[str1], Memc[str2]))
+ call imunmap (im)
+ }
+
+ if (im != NULL)
+ ccdtype = ccdtypei (im)
+
+ call sfree (sp)
+end
diff --git a/noao/imred/quadred/src/ccdproc/setinteract.x b/noao/imred/quadred/src/ccdproc/setinteract.x
new file mode 100644
index 00000000..05bc0f71
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/setinteract.x
@@ -0,0 +1,31 @@
+include <pkg/xtanswer.h>
+
+# SET_INTERACTIVE -- Set the interactive flag. Query the user if necessary.
+#
+# This procedure initializes the interactive flag if there is no query.
+# If there is a query it is issued by XT_ANSWER. The four valued
+# interactive flag is returned.
+
+procedure set_interactive (query, interactive)
+
+char query[ARB] # Query prompt
+int interactive # Fit overscan interactively? (returned)
+
+int interact # Saves last value of interactive flag
+bool clgetb()
+
+begin
+ # If the query is null then initialize from the CL otherwise
+ # query the user. This response is four valued to allow the user
+ # to turn off the query when processing multiple images.
+
+ if (query[1] == EOS) {
+ if (clgetb ("interactive"))
+ interact = YES
+ else
+ interact = ALWAYSNO
+ } else
+ call xt_answer (query, interact)
+
+ interactive = interact
+end
diff --git a/noao/imred/quadred/src/ccdproc/setoutput.x b/noao/imred/quadred/src/ccdproc/setoutput.x
new file mode 100644
index 00000000..0c4e608f
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/setoutput.x
@@ -0,0 +1,51 @@
+include <imhdr.h>
+include <imset.h>
+
+# SET_OUTPUT -- Setup the output image.
+# The output image is a NEW_COPY of the input image.
+# The user may select a pixel datatype with higher precision though not
+# lower.
+
+procedure set_output (in, out, output)
+
+pointer in # Input IMIO pointer to copy
+pointer out # Output IMIO pointer
+char output[SZ_FNAME] # Output image name
+
+int i, clscan(), nscan()
+char type[1]
+pointer immap()
+errchk immap
+
+begin
+ out = immap (output, NEW_COPY, in)
+ IM_PIXTYPE(out) = TY_REAL
+ if (clscan ("pixeltype") != EOF) {
+ call gargwrd (type, 1)
+ if (nscan() == 1) {
+ i = IM_PIXTYPE(in)
+ IM_PIXTYPE(out) = i
+ switch (type[1]) {
+ case 's':
+ ;
+ case 'u':
+ if (i == TY_SHORT)
+ IM_PIXTYPE(out) = TY_USHORT
+ case 'i':
+ if (i == TY_SHORT || i == TY_USHORT)
+ IM_PIXTYPE(out) = TY_INT
+ case 'l':
+ if (i == TY_SHORT || i == TY_USHORT || i == TY_INT)
+ IM_PIXTYPE(out) = TY_LONG
+ case 'r':
+ if (i != TY_DOUBLE)
+ IM_PIXTYPE(out) = TY_REAL
+ case 'd':
+ IM_PIXTYPE(out) = TY_DOUBLE
+ default:
+ call imunmap (out)
+ call error (0, "Unknown pixel type")
+ }
+ }
+ }
+end
diff --git a/noao/imred/quadred/src/ccdproc/setoverscan.x b/noao/imred/quadred/src/ccdproc/setoverscan.x
new file mode 100644
index 00000000..2fef378a
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/setoverscan.x
@@ -0,0 +1,344 @@
+include <imhdr.h>
+include <imset.h>
+include <pkg/gtools.h>
+include <pkg/xtanswer.h>
+include "ccdred.h"
+
+
+# SET_OVERSCAN -- Set the overscan vector.
+#
+# 1. Return immediately if the overscan correction is not requested or
+# if the image has been previously corrected.
+# 2. Determine the overscan columns or lines. This may be specifed
+# directly or indirectly through the image header or symbol table.
+# 3. Average the overscan columns or lines.
+# 4. Fit a function with the ICFIT routines to smooth the overscan vector.
+# 5. Set the processing flag.
+# 6. Log the operation (to user, logfile, and output image header).
+
+procedure set_overscan (ccd)
+
+pointer ccd # CCD structure pointer
+
+int i, j, nsec, navg, npts, first, last
+int nc, nl, c1, c2, l1, l2
+pointer sp, str, errstr, buf, overscan, x, y, z
+
+real asumr()
+bool clgetb(), ccdflag()
+pointer imgl2r()
+errchk imgl2r, fit_overscan
+
+begin
+ # Check if the user wants this operation or if it has been done.
+ if (!clgetb ("overscan") || ccdflag (IN_IM(ccd), "overscan"))
+ return
+
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+ call salloc (errstr, SZ_LINE, TY_CHAR)
+ call imstats (IN_IM(ccd), IM_IMAGENAME, Memc[str], SZ_LINE)
+
+ # Check bias section.
+ nc = IM_LEN(IN_IM(ccd),1)
+ nl = IM_LEN(IN_IM(ccd),2)
+
+ c1 = BIAS_C1(ccd)
+ c2 = BIAS_C2(ccd)
+ l1 = BIAS_L1(ccd)
+ l2 = BIAS_L2(ccd)
+ navg = c2 - c1 + 1
+ npts = CCD_L2(ccd) - CCD_L1(ccd) + 1
+
+ nsec = max (1, IN_NSEC(ccd))
+ do i = 1, nsec {
+ if (BIAS_SEC(ccd) != NULL) {
+ c1 = BIAS_SC1(ccd,i)
+ c2 = BIAS_SC2(ccd,i)
+ l1 = BIAS_SL1(ccd,i)
+ l2 = BIAS_SL2(ccd,i)
+ }
+ if ((c1 < 1) || (c2 > nc) || (l1 < 1) || (l2 > nl)) {
+ call sprintf (Memc[errstr], SZ_LINE,
+ "Error in bias section: image=%s[%d,%d], biassec=[%d:%d,%d:%d]")
+ call pargstr (Memc[str])
+ call pargi (nc)
+ call pargi (nl)
+ call pargi (c1)
+ call pargi (c2)
+ call pargi (l1)
+ call pargi (l2)
+ call error (0, Memc[errstr])
+ }
+ if ((c1 == 1) && (c2 == nc) && (l1 == 1) && (l2 == nl)) {
+ call error (0,
+ "Bias section not specified or given as full image")
+ }
+
+ # If no processing is desired then print overscan strip and return.
+ if (clgetb ("noproc")) {
+ call eprintf (
+ " [TO BE DONE] Overscan section is [%d:%d,%d:%d].\n")
+ call pargi (c1)
+ call pargi (c2)
+ call pargi (l1)
+ call pargi (l2)
+ call sfree (sp)
+ return
+ }
+ }
+
+ # Determine the overscan section parameters. The readout axis
+ # determines the type of overscan. The step sizes are ignored.
+ # The limits in the long dimension are replaced by the trim limits.
+
+ if (READAXIS(ccd) == 1) {
+ call salloc (buf, nsec*nl, TY_REAL)
+ z = buf
+ do i = 1, nl {
+ y = imgl2r (IN_IM(ccd), i)
+ do j = 1, nsec {
+ if (BIAS_SEC(ccd) != NULL) {
+ l1 = BIAS_SL1(ccd,j)
+ l2 = BIAS_SL2(ccd,j)
+ if (i < l1 || i > l2)
+ next
+ c1 = BIAS_SC1(ccd,j)
+ c2 = BIAS_SC2(ccd,j)
+ navg = c2 - c1 + 1
+ z = buf + (j - 1) * nl
+ }
+ Memr[z+i-1] = asumr (Memr[y+c1-1], navg)
+ }
+ }
+
+ # Trim the overscan vector and set the pixel coordinate.
+ call salloc (x, nl, TY_REAL)
+ call malloc (overscan, nsec*nl, TY_REAL)
+ y = overscan
+ do i = 1, nsec {
+ if (BIAS_SEC(ccd) != NULL) {
+ c1 = BIAS_SC1(ccd,i)
+ c2 = BIAS_SC2(ccd,i)
+ l1 = BIAS_SL1(ccd,i)
+ l2 = BIAS_SL2(ccd,i)
+ navg = c2 - c1 + 1
+ npts = l2 - l1 + 1
+ y = overscan + (i - 1) * nl
+ z = buf + (i - 1) * nl
+ }
+ if (navg > 1)
+ call adivkr (Memr[z+l1-1], real (navg), Memr[z+l1-1],
+ npts)
+ call trim_overscan (Memr[z], npts, l1, Memr[x], Memr[y])
+ call fit_overscan (Memc[str], c1, c2, l1, l2, Memr[x],
+ Memr[y], npts)
+ }
+
+ } else {
+ first = l1
+ last = l2
+ navg = last - first + 1
+ npts = nc
+ call salloc (buf, npts, TY_REAL)
+ call aclrr (Memr[buf], npts)
+ do i = first, last
+ call aaddr (Memr[imgl2r(IN_IM(ccd),i)], Memr[buf], Memr[buf],
+ npts)
+ if (navg > 1)
+ call adivkr (Memr[buf], real (navg), Memr[buf], npts)
+
+ # Trim the overscan vector and set the pixel coordinate.
+ npts = CCD_C2(ccd) - CCD_C1(ccd) + 1
+ call malloc (overscan, npts, TY_REAL)
+ call salloc (x, npts, TY_REAL)
+ call trim_overscan (Memr[buf], npts, IN_C1(ccd), Memr[x],
+ Memr[overscan])
+
+ call fit_overscan (Memc[str], c1, c2, l1, l2, Memr[x],
+ Memr[overscan], npts)
+ }
+
+ # Set the CCD structure overscan parameters.
+ CORS(ccd, OVERSCAN) = O
+ COR(ccd) = YES
+ OVERSCAN_VEC(ccd) = overscan
+
+ # Log the operation.
+ call strcpy ("overscan", Memc[errstr], SZ_LINE)
+ y = overscan
+ do i = 1, nsec {
+ if (BIAS_SEC(ccd) != NULL) {
+ c1 = BIAS_SC1(ccd,i)
+ c2 = BIAS_SC2(ccd,i)
+ l1 = BIAS_SL1(ccd,i)
+ l2 = BIAS_SL2(ccd,i)
+ y = overscan + (i - 1) * nl
+ npts = c2 - c1 + 1
+ if (i > 1) {
+ call sprintf (Memc[errstr], SZ_LINE, "ovrscn%d")
+ call pargi (i)
+ }
+ }
+ call sprintf (Memc[str], SZ_LINE,
+ "Overscan section is [%d:%d,%d:%d] with mean=%g")
+ call pargi (c1)
+ call pargi (c2)
+ call pargi (l1)
+ call pargi (l2)
+ call pargr (asumr (Memr[y], npts) / npts)
+ call timelog (Memc[str], SZ_LINE)
+ call ccdlog (IN_IM(ccd), Memc[str])
+ call hdmpstr (OUT_IM(ccd), Memc[errstr], Memc[str])
+ }
+
+ call sfree (sp)
+end
+
+
+# FIT_OVERSCAN -- Fit a function to smooth the overscan vector.
+# The fitting uses the ICFIT procedures which may be interactive.
+# Changes to these parameters are "learned". The user is queried with a four
+# valued logical query (XT_ANSWER routine) which may be turned off when
+# multiple images are processed.
+
+procedure fit_overscan (image, c1, c2, l1, l2, x, overscan, npts)
+
+char image[ARB] # Image name for query and title
+int c1, c2, l1, l2 # Overscan strip
+real x[npts] # Pixel coordinates of overscan
+real overscan[npts] # Input overscan and output fitted overscan
+int npts # Number of data points
+
+int interactive, fd
+pointer sp, str, w, ic, cv, gp, gt
+
+int clgeti(), ic_geti(), open()
+real clgetr(), ic_getr()
+pointer gopen(), gt_init()
+errchk gopen, open
+
+begin
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+ call salloc (w, npts, TY_REAL)
+ call amovkr (1., Memr[w], npts)
+
+ # Open the ICFIT procedures, get the fitting parameters, and
+ # set the fitting limits.
+
+ call ic_open (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_putr (ic, "xmin", min (x[1], x[npts]))
+ call ic_putr (ic, "xmax", max (x[1], x[npts]))
+ call ic_pstr (ic, "xlabel", "Pixel")
+ call ic_pstr (ic, "ylabel", "Overscan")
+
+ # If the fitting is done interactively set the GTOOLS and GIO
+ # pointers. Also "learn" the fitting parameters since they may
+ # be changed when fitting interactively.
+
+ call sprintf (Memc[str], SZ_LINE,
+ "Fit overscan vector for %s[%d:%d,%d:%d] interactively")
+ call pargstr (image)
+ call pargi (c1)
+ call pargi (c2)
+ call pargi (l1)
+ call pargi (l2)
+ call set_interactive (Memc[str], interactive)
+ if ((interactive == YES) || (interactive == ALWAYSYES)) {
+ gt = gt_init ()
+ call sprintf (Memc[str], SZ_LINE,
+ "Overscan vector for %s from section [%d:%d,%d:%d]\n")
+ call pargstr (image)
+ call pargi (c1)
+ call pargi (c2)
+ call pargi (l1)
+ call pargi (l2)
+ call gt_sets (gt, GTTITLE, Memc[str])
+ call gt_sets (gt, GTTYPE, "line")
+ call gt_setr (gt, GTXMIN, x[1])
+ call gt_setr (gt, GTXMAX, x[npts])
+ call clgstr ("graphics", Memc[str], SZ_FNAME)
+ gp = gopen (Memc[str], NEW_FILE, STDGRAPH)
+
+ call icg_fit (ic, gp, "cursor", gt, cv, x, overscan, Memr[w], npts)
+
+ call ic_gstr (ic, "function", Memc[str], SZ_LINE)
+ call clpstr ("function", Memc[str])
+ call clputi ("order", ic_geti (ic, "order"))
+ call ic_gstr (ic, "sample", Memc[str], SZ_LINE)
+ call clpstr ("sample", Memc[str])
+ call clputi ("naverage", ic_geti (ic, "naverage"))
+ call clputi ("niterate", ic_geti (ic, "niterate"))
+ call clputr ("low_reject", ic_getr (ic, "low"))
+ call clputr ("high_reject", ic_getr (ic, "high"))
+ call clputr ("grow", ic_getr (ic, "grow"))
+
+ call gclose (gp)
+ call gt_free (gt)
+ } else
+ call ic_fit (ic, cv, x, overscan, Memr[w], npts, YES, YES, YES, YES)
+
+ # Make a log of the fit in the plot file if given.
+ call clgstr ("plotfile", Memc[str], SZ_LINE)
+ call xt_stripwhite (Memc[str])
+ if (Memc[str] != EOS) {
+ fd = open (Memc[str], APPEND, BINARY_FILE)
+ gp = gopen ("stdvdm", NEW_FILE, fd)
+ gt = gt_init ()
+ call sprintf (Memc[str], SZ_LINE,
+ "Overscan vector for %s from section [%d:%d,%d:%d]\n")
+ call pargstr (image)
+ call pargi (c1)
+ call pargi (c2)
+ call pargi (l1)
+ call pargi (l2)
+ call gt_sets (gt, GTTITLE, Memc[str])
+ call gt_sets (gt, GTTYPE, "line")
+ call gt_setr (gt, GTXMIN, 1.)
+ call gt_setr (gt, GTXMAX, real (npts))
+ call icg_graphr (ic, gp, gt, cv, x, overscan, Memr[w], npts)
+ call gclose (gp)
+ call close (fd)
+ call gt_free (gt)
+ }
+
+ # Replace the raw overscan vector with the smooth fit.
+ call cvvector (cv, x, overscan, npts)
+
+ # Finish up.
+ call ic_closer (ic)
+ call cvfree (cv)
+ call sfree (sp)
+end
+
+
+# TRIM_OVERSCAN -- Trim the overscan vector.
+
+procedure trim_overscan (data, npts, start, x, overscan)
+
+real data[ARB] # Full overscan vector
+int npts # Length of trimmed vector
+int start # Trim start
+real x[npts] # Trimmed pixel coordinates (returned)
+real overscan[npts] # Trimmed overscan vector (returned)
+
+int i, j
+
+begin
+ do i = 1, npts {
+ j = start + i - 1
+ x[i] = j
+ overscan[i] = data[j]
+ }
+end
diff --git a/noao/imred/quadred/src/ccdproc/setproc.x b/noao/imred/quadred/src/ccdproc/setproc.x
new file mode 100644
index 00000000..595acd76
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/setproc.x
@@ -0,0 +1,80 @@
+include <imhdr.h>
+include "ccdred.h"
+
+# SET_PROC -- Set the processing parameter structure pointer.
+
+procedure set_proc (in, out, ccd)
+
+pointer in # Input IMIO pointer
+pointer out # Output IMIO pointer
+pointer ccd # CCD structure (returned)
+
+int clgwrd(), clscan(), nscan()
+real clgetr()
+pointer sp, str
+
+begin
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ # Allocate the ccd structure.
+ call calloc (ccd, LEN_CCD, TY_STRUCT)
+
+ IN_IM(ccd) = in
+ OUT_IM(ccd) = out
+ COR(ccd) = NO
+ CORS(ccd, FIXPIX) = NO
+ CORS(ccd, OVERSCAN) = NO
+ CORS(ccd, TRIM) = NO
+ READAXIS(ccd) = clgwrd ("readaxis",Memc[str],SZ_LINE,"|line|columns|")
+ MINREPLACE(ccd) = clgetr ("minreplace")
+
+ CALCTYPE(ccd) = TY_REAL
+ if (clscan ("pixeltype") != EOF) {
+ call gargwrd (Memc[str], SZ_LINE)
+ call gargwrd (Memc[str], SZ_LINE)
+ if (nscan() == 2) {
+ if (Memc[str] == 'r')
+ CALCTYPE(ccd) = TY_REAL
+ else if (Memc[str] == 's')
+ CALCTYPE(ccd) = TY_SHORT
+ else
+ call error (1, "Invalid calculation datatype")
+ }
+ }
+
+ call sfree (sp)
+end
+
+
+# FREE_PROC -- Free the processing structure pointer.
+
+procedure free_proc (ccd)
+
+pointer ccd # CCD structure
+
+begin
+ # Unmap calibration images.
+ if (ZERO_IM(ccd) != NULL)
+ call ccd_unmap (ZERO_IM(ccd))
+ if (DARK_IM(ccd) != NULL)
+ call ccd_unmap (DARK_IM(ccd))
+ if (FLAT_IM(ccd) != NULL)
+ call ccd_unmap (FLAT_IM(ccd))
+ if (ILLUM_IM(ccd) != NULL)
+ call ccd_unmap (ILLUM_IM(ccd))
+ if (FRINGE_IM(ccd) != NULL)
+ call ccd_unmap (FRINGE_IM(ccd))
+
+ # Free memory
+ if (BADCOLS(ccd) != NULL)
+ call mfree (BADCOLS(ccd), TY_SHORT)
+ if (BADLINES(ccd) != NULL)
+ call mfree (BADLINES(ccd), TY_SHORT)
+ if (OVERSCAN_VEC(ccd) != NULL)
+ call mfree (OVERSCAN_VEC(ccd), TY_REAL)
+ call mfree (IN_SEC(ccd), TY_INT)
+ call mfree (OUT_SEC(ccd), TY_INT)
+ call mfree (BIAS_SEC(ccd), TY_INT)
+ call mfree (ccd, TY_STRUCT)
+end
diff --git a/noao/imred/quadred/src/ccdproc/setsections.x b/noao/imred/quadred/src/ccdproc/setsections.x
new file mode 100644
index 00000000..b83a9d13
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/setsections.x
@@ -0,0 +1,327 @@
+include <imhdr.h>
+include "ccdred.h"
+
+# SET_SECTIONS -- Set the data section, ccd section, trim section and
+# bias section.
+
+procedure set_sections (ccd)
+
+pointer ccd # CCD structure (returned)
+
+pointer sp, str
+int nc, nl, c1, c2, cs, l1, l2, ls
+bool streq()
+
+begin
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ nc = IM_LEN(IN_IM(ccd),1)
+ nl = IM_LEN(IN_IM(ccd),2)
+
+ # The default data section is the entire image.
+ c1 = 1
+ c2 = nc
+ cs = 1
+ l1 = 1
+ l2 = nl
+ ls = 1
+ call hdmgstr (IN_IM(ccd), "datasec", Memc[str], SZ_LINE)
+ call ccd_section (Memc[str], c1, c2, cs, l1, l2, ls)
+ if ((c1<1)||(c2>nc)||(l1<1)||(l2>nl)||(cs!=1)||(ls!=1))
+ call error (0, "Error in DATASEC parameter")
+ IN_C1(ccd) = c1
+ IN_C2(ccd) = c2
+ IN_L1(ccd) = l1
+ IN_L2(ccd) = l2
+
+ # The default trim section is the data section.
+ # Defer limit checking until actually used.
+ c1 = IN_C1(ccd)
+ c2 = IN_C2(ccd)
+ l1 = IN_L1(ccd)
+ l2 = IN_L2(ccd)
+ call clgstr ("trimsec", Memc[str], SZ_LINE)
+ if (streq (Memc[str], "image"))
+ call hdmgstr (IN_IM(ccd), "trimsec", Memc[str], SZ_LINE)
+ call ccd_section (Memc[str], c1, c2, cs, l1, l2, ls)
+ if ((cs!=1)||(ls!=1))
+ call error (0, "Error in TRIMSEC parameter")
+ TRIM_C1(ccd) = c1
+ TRIM_C2(ccd) = c2
+ TRIM_L1(ccd) = l1
+ TRIM_L2(ccd) = l2
+
+ # The default bias section is the whole image.
+ # Defer limit checking until actually used.
+ c1 = 1
+ c2 = nc
+ l1 = 1
+ l2 = nl
+ call clgstr ("biassec", Memc[str], SZ_LINE)
+ if (streq (Memc[str], "image"))
+ call hdmgstr (IN_IM(ccd), "biassec", Memc[str], SZ_LINE)
+ call ccd_section (Memc[str], c1, c2, cs, l1, l2, ls)
+ if ((cs!=1)||(ls!=1))
+ call error (0, "Error in BIASSEC parameter")
+ BIAS_C1(ccd) = c1
+ BIAS_C2(ccd) = c2
+ BIAS_L1(ccd) = l1
+ BIAS_L2(ccd) = l2
+
+ # The default ccd section is the size of the data section.
+ c1 = 1
+ c2 = IN_C2(ccd) - IN_C1(ccd) + 1
+ l1 = 1
+ l2 = IN_L2(ccd) - IN_L1(ccd) + 1
+ call hdmgstr (IN_IM(ccd), "ccdsec", Memc[str], SZ_LINE)
+ call ccd_section (Memc[str], c1, c2, cs, l1, l2, ls)
+ if ((cs != 1) || (ls != 1))
+ call error (0, "Error in CCDSEC parameter")
+ CCD_C1(ccd) = c1
+ CCD_C2(ccd) = c2
+ CCD_L1(ccd) = l1
+ CCD_L2(ccd) = l2
+ if ((IN_C2(ccd)-IN_C1(ccd) != CCD_C2(ccd)-CCD_C1(ccd)) ||
+ (IN_L2(ccd)-IN_L1(ccd) != CCD_L2(ccd)-CCD_L1(ccd)))
+ call error (0, "Size of DATASEC and CCDSEC do not agree")
+
+ # The default output data section is the input data section.
+ OUT_C1(ccd) = IN_C1(ccd)
+ OUT_C2(ccd) = IN_C2(ccd)
+ OUT_L1(ccd) = IN_L1(ccd)
+ OUT_L2(ccd) = IN_L2(ccd)
+
+ # Set ARCON style sections.
+ call set_arcon (ccd)
+
+ call sfree (sp)
+end
+
+
+# SET_ARCON -- Set the data section, ccd section, trim section and
+# bias section.
+
+procedure set_arcon (ccd)
+
+pointer ccd # CCD structure (returned)
+
+pointer sp, amplist, amp, key, str
+int i, ip, nc, nl, c1, c2, cs, l1, l2, ls, ctowrd()
+int xt1, xt2, yt1, yt2
+bool trim, clgetb()
+
+begin
+ call smark (sp)
+ call salloc (amplist, SZ_LINE, TY_CHAR)
+ call salloc (amp, SZ_LINE, TY_CHAR)
+ call salloc (key, SZ_LINE, TY_CHAR)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ trim = clgetb ("trim")
+
+ # Get AMPLIST and determine the number of amplifiers.
+ # If there is no AMPLIST or missing BSEC keywords return.
+ call hdmgstr (IN_IM(ccd), "amplist", Memc[amplist], SZ_LINE)
+ if (Memc[amplist] == EOS) {
+ call sfree (sp)
+ return
+ }
+
+ ip = 1
+ for (i=0; ctowrd(Memc[amplist],ip,Memc[amp],SZ_LINE)!=0; i=i+1) {
+ call sprintf (Memc[key], SZ_LINE, "bsec%s")
+ call pargstr (Memc[amp])
+ call hdmgstr (IN_IM(ccd), Memc[key], Memc[str], SZ_LINE)
+ if (Memc[str] == EOS) {
+ call sfree (sp)
+ return
+ }
+ }
+ if (i == 0) {
+ call sfree (sp)
+ return
+ }
+
+ IN_NSEC(ccd) = i
+ call malloc (IN_SEC(ccd), 4*i, TY_INT)
+ call malloc (OUT_SEC(ccd), 4*i, TY_INT)
+ call malloc (BIAS_SEC(ccd), 4*i, TY_INT)
+
+ nc = IM_LEN(IN_IM(ccd),1)
+ nl = IM_LEN(IN_IM(ccd),2)
+
+ ip = 1
+ for (i=1; ctowrd(Memc[amplist],ip,Memc[amp],SZ_LINE)!=0; i=i+1) {
+
+ # Use amp section if no trim and data section if trim.
+ c1 = 1; c2 = nc; cs = 1; l1 = 1; l2 = nl; ls = 1
+ if (trim)
+ call sprintf (Memc[key], SZ_LINE, "dsec%s")
+ else
+ call sprintf (Memc[key], SZ_LINE, "asec%s")
+ call pargstr (Memc[amp])
+ call hdmgstr (IN_IM(ccd), Memc[key], Memc[str], SZ_LINE)
+ if (Memc[str] == EOS) {
+ call sprintf (Memc[str], SZ_LINE, "Keyword %s not found")
+ call pargstr (Memc[key])
+ call error (0, Memc[str])
+ }
+ call ccd_section (Memc[str], c1, c2, cs, l1, l2, ls)
+ if ((c1<1)||(c2>nc)||(l1<1)||(l2>nl)) {
+ call sprintf (Memc[str], SZ_LINE, "Error in %s parameter")
+ call pargstr (Memc[key])
+ call error (0, Memc[str])
+ }
+ IN_SC1(ccd,i) = c1
+ IN_SC2(ccd,i) = c2
+ IN_SL1(ccd,i) = l1
+ IN_SL2(ccd,i) = l2
+
+ # If trimming match dsec with csec and then use tsec.
+ if (trim) {
+ c1 = IN_SC1(ccd,i); c2 = IN_SC2(ccd,i); cs = 1
+ l1 = IN_SL1(ccd,i); l2 = IN_SL2(ccd,i); ls = 1
+ call sprintf (Memc[key], SZ_LINE, "tsec%s")
+ call pargstr (Memc[amp])
+ call hdmgstr (IN_IM(ccd), Memc[key], Memc[str], SZ_LINE)
+ if (Memc[str] != EOS)
+ call ccd_section (Memc[str], c1, c2, cs, l1, l2, ls)
+ if ((c1<IN_SC1(ccd,i))||(c2>IN_SC2(ccd,i))||
+ (l1<IN_SL1(ccd,i))||(l2>IN_SL2(ccd,i))) {
+ call sprintf (Memc[str], SZ_LINE, "Error in %s parameter")
+ call pargstr (Memc[key])
+ call error (0, Memc[str])
+ }
+ xt1 = max (0, c1 - IN_SC1(ccd,i))
+ xt2 = min (0, c2 - IN_SC2(ccd,i))
+ yt1 = max (0, l1 - IN_SL1(ccd,i))
+ yt2 = min (0, l2 - IN_SL2(ccd,i))
+
+ call sprintf (Memc[key], SZ_LINE, "csec%s")
+ call pargstr (Memc[amp])
+ call hdmgstr (IN_IM(ccd), Memc[key], Memc[str], SZ_LINE)
+ if (Memc[str] == EOS) {
+ call sprintf (Memc[str], SZ_LINE, "Keyword %s not found")
+ call pargstr (Memc[key])
+ call error (0, Memc[str])
+ }
+ call ccd_section (Memc[str], c1, c2, cs, l1, l2, ls)
+ if ((c2-c1) != (IN_SC2(ccd,i)-IN_SC1(ccd,i)) ||
+ (l2-l1) != (IN_SL2(ccd,i)-IN_SL1(ccd,i)))
+ call error (1, "DSEC and CSEC are different sizes")
+
+ IN_SC1(ccd,i) = IN_SC1(ccd,i) + xt1
+ IN_SC2(ccd,i) = IN_SC2(ccd,i) + xt2
+ IN_SL1(ccd,i) = IN_SL1(ccd,i) + yt1
+ IN_SL2(ccd,i) = IN_SL2(ccd,i) + yt2
+ OUT_SC1(ccd,i) = c1 + xt1
+ OUT_SC2(ccd,i) = c2 + xt2
+ OUT_SL1(ccd,i) = l1 + yt1
+ OUT_SL2(ccd,i) = l2 + yt2
+
+ } else {
+ OUT_SC1(ccd,i) = c1
+ OUT_SC2(ccd,i) = c2
+ OUT_SL1(ccd,i) = l1
+ OUT_SL2(ccd,i) = l2
+ }
+
+ # The default bias section is the whole image.
+ # Defer limit checking until actually used.
+ c1 = 1
+ c2 = nc
+ l1 = 1
+ l2 = nl
+ call sprintf (Memc[key], SZ_LINE, "bsec%s")
+ call pargstr (Memc[amp])
+ call hdmgstr (IN_IM(ccd), Memc[key], Memc[str], SZ_LINE)
+ if (Memc[str] == EOS) {
+ call sprintf (Memc[str], SZ_LINE, "Keyword %s not found")
+ call pargstr (Memc[key])
+ call error (0, Memc[str])
+ }
+ call ccd_section (Memc[str], c1, c2, cs, l1, l2, ls)
+ if ((cs!=1)||(ls!=1))
+ call error (0, "Error in BSEC parameter")
+ BIAS_SC1(ccd,i) = c1
+ BIAS_SC2(ccd,i) = c2
+ BIAS_SL1(ccd,i) = l1
+ BIAS_SL2(ccd,i) = l2
+
+ if (trim) {
+ #iferr (call hdmdelf (OUT_IM(ccd), "amplist"))
+ # ;
+ #call sprintf (Memc[key], SZ_LINE, "asec%s")
+ # call pargstr (Memc[amp])
+ #iferr (call hdmdelf (OUT_IM(ccd), Memc[key]))
+ # ;
+ call sprintf (Memc[key], SZ_LINE, "bsec%s")
+ call pargstr (Memc[amp])
+ iferr (call hdmdelf (OUT_IM(ccd), Memc[key]))
+ ;
+ call sprintf (Memc[key], SZ_LINE, "csec%s")
+ call pargstr (Memc[amp])
+ iferr (call hdmdelf (OUT_IM(ccd), Memc[key]))
+ ;
+ call sprintf (Memc[key], SZ_LINE, "dsec%s")
+ call pargstr (Memc[amp])
+ iferr (call hdmdelf (OUT_IM(ccd), Memc[key]))
+ ;
+ call sprintf (Memc[key], SZ_LINE, "tsec%s")
+ call pargstr (Memc[amp])
+ iferr (call hdmdelf (OUT_IM(ccd), Memc[key]))
+ ;
+ }
+ }
+
+ # Set global sections.
+ IN_C1(ccd) = IN_SC1(ccd,1)
+ IN_C2(ccd) = IN_SC2(ccd,1)
+ IN_L1(ccd) = IN_SL1(ccd,1)
+ IN_L2(ccd) = IN_SL2(ccd,1)
+ CCD_C1(ccd) = OUT_SC1(ccd,1)
+ CCD_C2(ccd) = OUT_SC2(ccd,1)
+ CCD_L1(ccd) = OUT_SL1(ccd,1)
+ CCD_L2(ccd) = OUT_SL2(ccd,1)
+ do i = 2, IN_NSEC(ccd) {
+ IN_C1(ccd) = min (IN_SC1(ccd,i), IN_C1(ccd))
+ IN_C2(ccd) = max (IN_SC2(ccd,i), IN_C2(ccd))
+ IN_L1(ccd) = min (IN_SL1(ccd,i), IN_L1(ccd))
+ IN_L2(ccd) = max (IN_SL2(ccd,i), IN_L2(ccd))
+ CCD_C1(ccd) = min (OUT_SC1(ccd,i), CCD_C1(ccd))
+ CCD_C2(ccd) = max (OUT_SC2(ccd,i), CCD_C2(ccd))
+ CCD_L1(ccd) = min (OUT_SL1(ccd,i), CCD_L1(ccd))
+ CCD_L2(ccd) = max (OUT_SL2(ccd,i), CCD_L2(ccd))
+ }
+ if (trim) {
+ OUT_C1(ccd) = CCD_C1(ccd) - CCD_C1(ccd) + 1
+ OUT_C2(ccd) = CCD_C2(ccd) - CCD_C1(ccd) + 1
+ OUT_L1(ccd) = CCD_L1(ccd) - CCD_L1(ccd) + 1
+ OUT_L2(ccd) = CCD_L2(ccd) - CCD_L1(ccd) + 1
+ ip = 1
+ for (i=1; ctowrd(Memc[amplist],ip,Memc[amp],SZ_LINE)!=0; i=i+1) {
+ OUT_SC1(ccd,i) = OUT_SC1(ccd,i) - CCD_C1(ccd) + 1
+ OUT_SC2(ccd,i) = OUT_SC2(ccd,i) - CCD_C1(ccd) + 1
+ OUT_SL1(ccd,i) = OUT_SL1(ccd,i) - CCD_L1(ccd) + 1
+ OUT_SL2(ccd,i) = OUT_SL2(ccd,i) - CCD_L1(ccd) + 1
+ call sprintf (Memc[key], SZ_LINE, "asec%s")
+ call pargstr (Memc[amp])
+ call sprintf (Memc[str], SZ_LINE, "[%d:%d,%d:%d]")
+ call pargi (OUT_SC1(ccd,i))
+ call pargi (OUT_SC2(ccd,i))
+ call pargi (OUT_SL1(ccd,i))
+ call pargi (OUT_SL2(ccd,i))
+ call hdmpstr (OUT_IM(ccd), Memc[key], Memc[str])
+ }
+ IM_LEN(OUT_IM(ccd),1) = OUT_C2(ccd)
+ IM_LEN(OUT_IM(ccd),2) = OUT_L2(ccd)
+ } else {
+ OUT_C1(ccd) = IN_C1(ccd)
+ OUT_C2(ccd) = IN_C2(ccd)
+ OUT_L1(ccd) = IN_L1(ccd)
+ OUT_L2(ccd) = IN_L2(ccd)
+ }
+
+ call sfree (sp)
+end
diff --git a/noao/imred/quadred/src/ccdproc/settrim.x b/noao/imred/quadred/src/ccdproc/settrim.x
new file mode 100644
index 00000000..1aef62c3
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/settrim.x
@@ -0,0 +1,115 @@
+include <imhdr.h>
+include <imset.h>
+include "ccdred.h"
+
+# SET_TRIM -- Set the trim parameters.
+#
+# 1. Return immediately if the trim correction is not requested or
+# if the image has been previously corrected.
+# 2. Determine the trim section. This may be specifed directly or
+# indirectly through the image header or symbol table.
+# 3. Parse the trim section and apply it to the output image.
+# 4. If the image is trimmed then log the operation and reset the output
+# image size.
+
+procedure set_trim (ccd)
+
+pointer ccd # CCD structure
+
+int xt1, xt2, yt1, yt2
+int nc, nl, c1, c2, l1, l2
+pointer sp, str, image
+bool clgetb(), ccdflag()
+define log_ 10
+
+begin
+ # Check if the user wants this operation or it has been done.
+ if (!clgetb ("trim") || ccdflag (IN_IM(ccd), "trim"))
+ return
+
+ call smark (sp)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ if (IN_SEC(ccd) != NULL)
+ goto log_
+
+ # Check trim section.
+ nc = IM_LEN(IN_IM(ccd),1)
+ nl = IM_LEN(IN_IM(ccd),2)
+ c1 = TRIM_C1(ccd)
+ c2 = TRIM_C2(ccd)
+ l1 = TRIM_L1(ccd)
+ l2 = TRIM_L2(ccd)
+ if ((c1 < 1) || (c2 > nc) || (l1 < 1) || (l2 > nl)) {
+ call salloc (image, SZ_LINE, TY_CHAR)
+ call imstats (IN_IM(ccd), IM_IMAGENAME, Memc[image], SZ_FNAME)
+ call sprintf (Memc[str], SZ_LINE,
+ "Error in trim section: image=%s[%d,%d], trimsec=[%d:%d,%d:%d]")
+ call pargstr (Memc[image])
+ call pargi (nc)
+ call pargi (nl)
+ call pargi (c1)
+ call pargi (c2)
+ call pargi (l1)
+ call pargi (l2)
+ call error (0, Memc[str])
+ }
+
+ # If no processing is desired print trim section and return.
+ if (clgetb ("noproc")) {
+ call eprintf (" [TO BE DONE] Trim section is [%d:%d,%d:%d].\n")
+ call pargi (c1)
+ call pargi (c2)
+ call pargi (l1)
+ call pargi (l2)
+ call sfree (sp)
+ return
+ }
+
+ xt1 = max (0, c1 - IN_C1(ccd))
+ xt2 = min (0, c2 - IN_C2(ccd))
+ yt1 = max (0, l1 - IN_L1(ccd))
+ yt2 = min (0, l2 - IN_L2(ccd))
+
+ CCD_C1(ccd) = CCD_C1(ccd) + xt1
+ CCD_C2(ccd) = CCD_C2(ccd) + xt2
+ CCD_L1(ccd) = CCD_L1(ccd) + yt1
+ CCD_L2(ccd) = CCD_L2(ccd) + yt2
+ IN_C1(ccd) = IN_C1(ccd) + xt1
+ IN_C2(ccd) = IN_C2(ccd) + xt2
+ IN_L1(ccd) = IN_L1(ccd) + yt1
+ IN_L2(ccd) = IN_L2(ccd) + yt2
+ OUT_C1(ccd) = IN_C1(ccd) - c1 + 1
+ OUT_C2(ccd) = IN_C2(ccd) - c1 + 1
+ OUT_L1(ccd) = IN_L1(ccd) - l1 + 1
+ OUT_L2(ccd) = IN_L2(ccd) - l1 + 1
+ IM_LEN(OUT_IM(ccd),1) = c2 - c1 + 1
+ IM_LEN(OUT_IM(ccd),2) = l2 - l1 + 1
+
+log_
+ if (IN_SEC(ccd) == NULL) {
+ CORS(ccd, TRIM) = YES
+ COR(ccd) = YES
+
+ call sprintf (Memc[str], SZ_LINE,
+ "Trim data section is [%d:%d,%d:%d]")
+ call pargi (c1)
+ call pargi (c2)
+ call pargi (l1)
+ call pargi (l2)
+ call timelog (Memc[str], SZ_LINE)
+ call ccdlog (IN_IM(ccd), Memc[str])
+ call hdmpstr (OUT_IM(ccd), "trim", Memc[str])
+ } else {
+ CORS(ccd, TRIM) = NO
+ COR(ccd) = YES
+
+ call sprintf (Memc[str], SZ_LINE,
+ "Trim multiple overscan sections")
+ call timelog (Memc[str], SZ_LINE)
+ call ccdlog (IN_IM(ccd), Memc[str])
+ call hdmpstr (OUT_IM(ccd), "trim", Memc[str])
+ }
+
+ call sfree (sp)
+end
diff --git a/noao/imred/quadred/src/ccdproc/setzero.x b/noao/imred/quadred/src/ccdproc/setzero.x
new file mode 100644
index 00000000..610aeee7
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/setzero.x
@@ -0,0 +1,141 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <imhdr.h>
+include "ccdred.h"
+include "ccdtypes.h"
+
+# SET_ZERO -- Set parameters for zero level correction.
+# 1. Return immediately if the zero level correction is not requested or
+# if the image has been previously corrected.
+# 2. Get the zero level correction image. Return an error if not found.
+# 3. If the zero level image has not been processed call ZEROPROC.
+# 4. Set the processing flag.
+# 5. Log the operation (to user, logfile, and output image header).
+
+procedure set_zero (ccd)
+
+pointer ccd # CCD structure
+
+int nscan, nc, nl, c1, c2, cs, l1, l2, ls, data_c1, ccd_c1, data_l1, ccd_l1
+pointer sp, str, image, im, ccd_cache()
+bool clgetb(), ccdflag(), ccdcheck()
+int ccdtypei(), ccdnscan()
+errchk cal_image, ccd_cache, ccdproc
+
+begin
+ # Check if the user wants this operation or it has been done.
+ if (!clgetb ("zerocor") || ccdflag (IN_IM(ccd), "zerocor"))
+ return
+
+ call smark (sp)
+ call salloc (image, SZ_FNAME, TY_CHAR)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ # Get the zero level correction image.
+ if (clgetb ("scancor"))
+ nscan = ccdnscan (IN_IM(ccd), ccdtypei(IN_IM(ccd)))
+ else
+ nscan = 1
+ call cal_image (IN_IM(ccd), ZERO, nscan, Memc[image], SZ_FNAME)
+
+ # If no processing is desired print zero correction image and return.
+ if (clgetb ("noproc")) {
+ call eprintf (" [TO BE DONE] Zero level correction image is %s.\n")
+ call pargstr (Memc[image])
+ call sfree (sp)
+ return
+ }
+
+ # Map the image and return on an error.
+ # Process the zero image if necessary.
+ # If nscan > 1 then the zero may not yet exist so create it
+ # from the unscanned zero.
+
+ iferr (im = ccd_cache (Memc[image], ZERO)) {
+ call cal_image (IN_IM(ccd), ZERO, 1, Memc[str], SZ_LINE)
+ im = ccd_cache (Memc[str], ZERO)
+ if (ccdcheck (im, ZERO)) {
+ call ccd_flush (im)
+ call ccdproc (Memc[str], ZERO)
+ }
+ call scancor (Memc[str], Memc[image], nscan, INDEF)
+ im = ccd_cache (Memc[image], ZERO)
+ }
+
+ if (ccdcheck (im, ZERO)) {
+ call ccd_flush (im)
+ call ccdproc (Memc[image], ZERO)
+ im = ccd_cache (Memc[image], ZERO)
+ }
+
+ # Set the processing parameters in the CCD structure.
+ nc = IM_LEN(im,1)
+ nl = IM_LEN(im,2)
+ c1 = 1
+ c2 = nc
+ l1 = 1
+ l2 = nl
+ cs = 1
+ ls = 1
+ call hdmgstr (im, "datasec", Memc[str], SZ_FNAME)
+ call ccd_section (Memc[str], c1, c2, cs, l1, l2, ls)
+ if ((c1<1)||(c2>nc)||(l1<1)||(l2>nl)||(cs!=1)||(ls!=1)) {
+ call sprintf (Memc[str], SZ_LINE,
+ "Data section error: image=%s[%d,%d], datasec=[%d:%d,%d:%d]")
+ call pargstr (Memc[image])
+ call pargi (nc)
+ call pargi (nl)
+ call pargi (c1)
+ call pargi (c2)
+ call pargi (l1)
+ call pargi (l2)
+ call error (0, Memc[str])
+ }
+ data_c1 = c1
+ data_l1 = l1
+ call hdmgstr (im, "ccdsec", Memc[str], SZ_FNAME)
+ call ccd_section (Memc[str], c1, c2, cs, l1, l2, ls)
+ if (nc == 1) {
+ c1 = CCD_C1(ccd)
+ c2 = CCD_C2(ccd)
+ }
+ if (nl == 1) {
+ l1 = CCD_L1(ccd)
+ l2 = CCD_L2(ccd)
+ }
+ ccd_c1 = c1
+ ccd_l1 = l1
+ if ((c1 > CCD_C1(ccd)) || (c2 < CCD_C2(ccd)) ||
+ (l1 > CCD_L1(ccd)) || (l2 < CCD_L2(ccd))) {
+ call sprintf (Memc[str], SZ_LINE,
+ "CCD section error: input=[%d:%d,%d:%d], %s=[%d:%d,%d:%d]")
+ call pargi (CCD_C1(ccd))
+ call pargi (CCD_C2(ccd))
+ call pargi (CCD_L1(ccd))
+ call pargi (CCD_L2(ccd))
+ call pargstr (Memc[image])
+ call pargi (c1)
+ call pargi (c2)
+ call pargi (l1)
+ call pargi (l2)
+ call error (0, Memc[str])
+ }
+
+ ZERO_IM(ccd) = im
+ ZERO_C1(ccd) = CCD_C1(ccd) - ccd_c1 + data_c1
+ ZERO_C2(ccd) = CCD_C2(ccd) - ccd_c1 + data_c1
+ ZERO_L1(ccd) = CCD_L1(ccd) - ccd_l1 + data_l1
+ ZERO_L2(ccd) = CCD_L2(ccd) - ccd_l1 + data_l1
+
+ CORS(ccd, ZEROCOR) = Z
+ COR(ccd) = YES
+
+ # Log the operation.
+ call sprintf (Memc[str], SZ_LINE, "Zero level correction image is %s")
+ call pargstr (Memc[image])
+ call timelog (Memc[str], SZ_LINE)
+ call ccdlog (IN_IM(ccd), Memc[str])
+ call hdmpstr (OUT_IM(ccd), "zerocor", Memc[str])
+
+ call sfree (sp)
+end
diff --git a/noao/imred/quadred/src/ccdproc/t_ccdproc.x b/noao/imred/quadred/src/ccdproc/t_ccdproc.x
new file mode 100644
index 00000000..8d256046
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/t_ccdproc.x
@@ -0,0 +1,155 @@
+include <imhdr.h>
+include <error.h>
+include "ccdred.h"
+include "ccdtypes.h"
+
+define CACHEUNIT 1000000. # Units of max_cache parameter
+
+# T_CCDPROC -- Process CCD images
+#
+# This is the main procedure for processing CCD images. The images are
+# corrected for bad pixels, overscan levels, zero levels, dark counts,
+# flat field response, illumination errors, and fringe response. They
+# may also be trimmed. The input is a list of images to be processed.
+# Each image must match any image type requested. The checking of
+# whether to apply each correction, getting the required parameters, and
+# logging the operations is left to separate procedures, one for each
+# correction. The actual processing is done by a specialized procedure
+# designed to be very efficient. These procedures may also process
+# calibration images if necessary. There are two data type paths; one
+# for short pixel types and one for all other pixel types (usually
+# real).
+
+procedure t_ccdproc ()
+
+int list # List of CCD images to process
+int ccdtype # CCD image type
+int interactive # Fit overscan interactively?
+int max_cache # Maximum image cache size
+
+bool clgetb()
+real clgetr()
+int imtopenp(), imtgetim(), imtlen()
+pointer sp, input, output, str, in, out, ccd
+errchk set_input, set_output, ccddelete, cal_open
+errchk set_fixpix, set_zero, set_dark, set_flat, set_illum, set_fringe
+
+begin
+ call smark (sp)
+ call salloc (input, SZ_FNAME, TY_CHAR)
+ call salloc (output, SZ_FNAME, TY_CHAR)
+ call salloc (str, SZ_LINE, TY_CHAR)
+
+ # Get the list and instrument translation file. Open the translation
+ # file. Initialize the interactive flag and the calibration images.
+
+ list = imtopenp ("images")
+ call clgstr ("instrument", Memc[input], SZ_FNAME)
+ call hdmopen (Memc[input])
+ call set_interactive ("", interactive)
+ call cal_open (list)
+ if (imtlen (list) < 3)
+ max_cache = 0.
+ else
+ max_cache = CACHEUNIT * clgetr ("max_cache")
+ call ccd_open (max_cache)
+
+ # Process each image.
+ while (imtgetim (list, Memc[input], SZ_FNAME) != EOF) {
+ if (clgetb ("noproc")) {
+ call printf ("%s:\n")
+ call pargstr (Memc[input])
+ }
+ call set_input (Memc[input], in, ccdtype)
+ if (in == NULL)
+ next
+
+ # Use a temporary image for output which will replace the input
+ # image after processing.
+
+ call mktemp ("tmp", Memc[output], SZ_FNAME)
+ call set_output (in, out, Memc[output])
+
+ # Set processing parameters applicable to all images.
+ call set_proc (in, out, ccd)
+ call set_sections (ccd)
+ call set_trim (ccd)
+ call set_fixpix (ccd)
+ call set_overscan (ccd)
+
+ # Set processing parameters for the standard CCD image types.
+ switch (ccdtype) {
+ case ZERO:
+ case DARK:
+ call set_zero (ccd)
+ case FLAT:
+ call set_zero (ccd)
+ call set_dark (ccd)
+ CORS(ccd, FINDMEAN) = YES
+ CORS(ccd, MINREP) = YES
+ case ILLUM:
+ call set_zero (ccd)
+ call set_dark (ccd)
+ call set_flat (ccd)
+ case OBJECT, COMP:
+ call set_zero (ccd)
+ call set_dark (ccd)
+ call set_flat (ccd)
+ iferr {
+ call set_illum (ccd)
+ call set_fringe (ccd)
+ } then
+ call erract (EA_WARN)
+ default:
+ call set_zero (ccd)
+ call set_dark (ccd)
+ call set_flat (ccd)
+ iferr {
+ call set_illum (ccd)
+ call set_fringe (ccd)
+ } then
+ call erract (EA_WARN)
+ CORS(ccd, FINDMEAN) = YES
+ }
+
+ # Do the processing if the COR flag is set.
+
+ if (COR(ccd) == YES) {
+ call doproc (ccd)
+ call set_header (ccd)
+
+ # Replace the input image by the corrected image.
+ call imunmap (in)
+ call imunmap (out)
+ iferr (call ccddelete (Memc[input])) {
+ call imdelete (Memc[output])
+ call error (1,
+ "Can't delete or make backup of original image")
+ }
+ call imrename (Memc[output], Memc[input])
+ } else {
+ # Delete the temporary output image leaving the input unchanged.
+ call imunmap (in)
+ iferr (call imunmap (out))
+ ;
+ iferr (call imdelete (Memc[output]))
+ ;
+ }
+ call free_proc (ccd)
+
+ # Do special processing on certain image types.
+ switch (ccdtype) {
+ case ZERO:
+ call readcor (Memc[input])
+ case FLAT:
+ call ccdmean (Memc[input])
+ }
+ }
+
+ # Finish up.
+ call hdmclose ()
+ call imtclose (list)
+ call cal_close ()
+ call ccd_close ()
+ call sfree (sp)
+end
diff --git a/noao/imred/quadred/src/ccdproc/timelog.x b/noao/imred/quadred/src/ccdproc/timelog.x
new file mode 100644
index 00000000..7a8d969f
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/timelog.x
@@ -0,0 +1,29 @@
+include <time.h>
+
+
+# TIMELOG -- Prepend a time stamp to the given string.
+#
+# For the purpose of a history logging prepend a short time stamp to the
+# given string. Note that the input string is modified.
+
+procedure timelog (str, max_char)
+
+char str[max_char] # String to be time stamped
+int max_char # Maximum characters in string
+
+pointer sp, time, temp
+long clktime()
+
+begin
+ call smark (sp)
+ call salloc (time, SZ_DATE, TY_CHAR)
+ call salloc (temp, max_char, TY_CHAR)
+
+ call cnvdate (clktime(0), Memc[time], SZ_DATE)
+ call sprintf (Memc[temp], max_char, "%s %s")
+ call pargstr (Memc[time])
+ call pargstr (str)
+ call strcpy (Memc[temp], str, max_char)
+
+ call sfree (sp)
+end
diff --git a/noao/imred/quadred/src/ccdproc/x_quadred.x b/noao/imred/quadred/src/ccdproc/x_quadred.x
new file mode 100644
index 00000000..a603d0d5
--- /dev/null
+++ b/noao/imred/quadred/src/ccdproc/x_quadred.x
@@ -0,0 +1 @@
+task ccdproc = t_ccdproc