aboutsummaryrefslogtreecommitdiff
path: root/noao/imred/dtoi
diff options
context:
space:
mode:
authorJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
committerJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
commit40e5a5811c6ffce9b0974e93cdd927cbcf60c157 (patch)
tree4464880c571602d54f6ae114729bf62a89518057 /noao/imred/dtoi
downloadiraf-osx-40e5a5811c6ffce9b0974e93cdd927cbcf60c157.tar.gz
Repatch (from linux) of OSX IRAF
Diffstat (limited to 'noao/imred/dtoi')
-rw-r--r--noao/imred/dtoi/README1
-rw-r--r--noao/imred/dtoi/Revisions144
-rw-r--r--noao/imred/dtoi/database.x611
-rw-r--r--noao/imred/dtoi/dematch.par8
-rw-r--r--noao/imred/dtoi/dematch.x160
-rw-r--r--noao/imred/dtoi/doc/dematch.hlp51
-rw-r--r--noao/imred/dtoi/doc/dtoi.ms576
-rw-r--r--noao/imred/dtoi/doc/dtoi.toc34
-rw-r--r--noao/imred/dtoi/doc/hdfit.hlp79
-rw-r--r--noao/imred/dtoi/doc/hdshift.hlp50
-rw-r--r--noao/imred/dtoi/doc/hdtoi.hlp88
-rw-r--r--noao/imred/dtoi/doc/selftest.hlp81
-rw-r--r--noao/imred/dtoi/doc/splotlist.hlp81
-rw-r--r--noao/imred/dtoi/dtoi.cl16
-rw-r--r--noao/imred/dtoi/dtoi.hd11
-rw-r--r--noao/imred/dtoi/dtoi.men6
-rw-r--r--noao/imred/dtoi/dtoi.par2
-rw-r--r--noao/imred/dtoi/hd_aravr.x50
-rw-r--r--noao/imred/dtoi/hdfit.par9
-rw-r--r--noao/imred/dtoi/hdfit.x364
-rw-r--r--noao/imred/dtoi/hdicfit/hdic.com6
-rw-r--r--noao/imred/dtoi/hdicfit/hdicadd.x47
-rw-r--r--noao/imred/dtoi/hdicfit/hdicclean.x94
-rw-r--r--noao/imred/dtoi/hdicfit/hdicdeviant.x116
-rw-r--r--noao/imred/dtoi/hdicfit/hdicdosetup.x104
-rw-r--r--noao/imred/dtoi/hdicfit/hdicebars.x217
-rw-r--r--noao/imred/dtoi/hdicfit/hdicerrors.x143
-rw-r--r--noao/imred/dtoi/hdicfit/hdicfit.h65
-rw-r--r--noao/imred/dtoi/hdicfit/hdicfit.x80
-rw-r--r--noao/imred/dtoi/hdicfit/hdicgaxes.x101
-rw-r--r--noao/imred/dtoi/hdicfit/hdicgcolon.x284
-rw-r--r--noao/imred/dtoi/hdicfit/hdicgdelete.x81
-rw-r--r--noao/imred/dtoi/hdicfit/hdicgfit.x402
-rw-r--r--noao/imred/dtoi/hdicfit/hdicggraph.x329
-rw-r--r--noao/imred/dtoi/hdicfit/hdicgnearest.x72
-rw-r--r--noao/imred/dtoi/hdicfit/hdicgparams.x94
-rw-r--r--noao/imred/dtoi/hdicfit/hdicgredraw.x22
-rw-r--r--noao/imred/dtoi/hdicfit/hdicgsample.x84
-rw-r--r--noao/imred/dtoi/hdicfit/hdicguaxes.x38
-rw-r--r--noao/imred/dtoi/hdicfit/hdicgundel.x87
-rw-r--r--noao/imred/dtoi/hdicfit/hdicguser.x17
-rw-r--r--noao/imred/dtoi/hdicfit/hdicgvec.x74
-rw-r--r--noao/imred/dtoi/hdicfit/hdicinit.x60
-rw-r--r--noao/imred/dtoi/hdicfit/hdicparams.x323
-rw-r--r--noao/imred/dtoi/hdicfit/hdicreject.x39
-rw-r--r--noao/imred/dtoi/hdicfit/hdicshow.x52
-rw-r--r--noao/imred/dtoi/hdicfit/hdicsort.x38
-rw-r--r--noao/imred/dtoi/hdicfit/hdictrans.x155
-rw-r--r--noao/imred/dtoi/hdicfit/hdicvshow.x155
-rw-r--r--noao/imred/dtoi/hdicfit/mkpkg37
-rw-r--r--noao/imred/dtoi/hdicfit/userfcn.x37
-rw-r--r--noao/imred/dtoi/hdshift.par2
-rw-r--r--noao/imred/dtoi/hdshift.x184
-rw-r--r--noao/imred/dtoi/hdtoi.par11
-rw-r--r--noao/imred/dtoi/hdtoi.x407
-rw-r--r--noao/imred/dtoi/minmax.x73
-rw-r--r--noao/imred/dtoi/mkpkg40
-rw-r--r--noao/imred/dtoi/selftest.par8
-rw-r--r--noao/imred/dtoi/selftest.x290
-rw-r--r--noao/imred/dtoi/spotlist.par8
-rw-r--r--noao/imred/dtoi/spotlist.x395
-rw-r--r--noao/imred/dtoi/x_dtoi.x6
62 files changed, 7299 insertions, 0 deletions
diff --git a/noao/imred/dtoi/README b/noao/imred/dtoi/README
new file mode 100644
index 00000000..e293c6c8
--- /dev/null
+++ b/noao/imred/dtoi/README
@@ -0,0 +1 @@
+DTOI -- Density to intensity transformation package.
diff --git a/noao/imred/dtoi/Revisions b/noao/imred/dtoi/Revisions
new file mode 100644
index 00000000..e6e955ff
--- /dev/null
+++ b/noao/imred/dtoi/Revisions
@@ -0,0 +1,144 @@
+.help revisions Jun88 noao.imred.dtoi
+.nf
+
+imred$dtoi/selftest.x
+ The 'lut' was declared as TY_INT instead of TY_REAL (5/4/13)
+
+imred$dtoi/spolist.x
+ A TY_INT pointer was being used with Memr[] (4/20/13)
+
+=======
+V2.16
+=======
+
+imred$dtoi/hdtoi.x
+ The hd_fogcalc() procedure was being called with too few arguments
+ (7/12/09, MJF)
+
+=======
+V2.14.1
+=======
+
+imred$dtoi/hdicfit/mkpkg
+ Added missing dependencies. (12/13/01, MJF)
+
+imred$dtoi/mkpkg
+ Added missing dependencies. (10/11/99, Valdes)
+
+=======
+V2.11.2
+=======
+
+imred$dtoi/doc/hdfit.hlp
+imred$dtoi/doc/hdshift.hlp
+imred$dtoi/doc/hdtoi.hlp
+imred$dtoi/doc/spotlist.hlp
+ Fixed minor formating problems. (4/22/99, Valdes)
+
+imred$dtoi/hdicggraph.x
+imred$dtoi/hdicebars.x
+ Replace direct access to GTOOLS structure with GTOOLS interface.
+ (12/18/98, Valdes)
+
+=======
+V2.11.1
+=======
+
+imred$dtoi/spotlist.x 7 Sept, 1989 SRo
+ In Suzanne's absence, removed the divide by nfog fog images in
+ hd_fogcalc() after a bug report by Steve Majewski that when multiple
+ fog images are used, the resultant fog values are too low by 1/nfog.
+ The total_pix accumulator is already a total for all images. Should
+ be verified by Suzanne on her return.
+
+imred$dtoi/hdicfit/hdicgdelte.x 17 April, 1989 ShJ
+ Procedure icg_dl1 was declared as an integer procedure, although
+ it does not return a function values and was not being called
+ as a function.
+
+imred$dtoi/hdicfit/hdicgcolon.x 27 March, 1989 ShJ
+ Changed only a comment line, to point out that the :ebars command
+ switches the meaning of the error bars between representing
+ standard deviations or weights.
+
+imred$dtoi/spotlist.x 11 May, 1988 ShJ
+ Added parameter "option", which selects a mean or median calculation
+ of spot densities and the fog value. Previously, only a mean
+ calculation was available. The choice of "option" is written to
+ the database.
+
+imred$dtoi/hd_aravr.x 11 May, 1988 ShJ
+ This is a new file, modified from the vops version only in that it
+ puts an upper limit on the number of iterations allowed in the
+ procedure of 10. This should avoid the problem reported by
+ Steve Majewski of nearly saturated pixels "hanging"; they actually
+ were oscillating endlessly in the mean rejection calculation.
+
+imred$dtoi/hdtoi.x 11 May, 1988 ShJ
+ Added parameter "option", which selects a mean or median calulcation
+ of the fog value, in those cases where the user supplies a fog
+ image, rather than a fog value. Previously, only a mean calculation
+ was available. This newly calculated value of fog is now also
+ written to the database.
+
+imred$dtoi/hdtoi.x 5 April, 1988 ShJ
+ Modified the way in which hdtoi scales intensities to the "ceiling"
+ parameter. A maximum intensity is calculated, using cveval to
+ evaluate the transformed value of the maximum density above fog.
+ The fog value subtracted is hdtoi.fog, which may or may not
+ equal the value of fog written by spotlist into the database.
+ Previously, the program was incorrectly subtracting the spotlist
+ fog value from the maximum density when calculating the maximum
+ intensity and so the scale factor to represent saturated intensities
+ as "ceiling".
+
+imred$dtoi/hdicgundel.x 25 March, 1988 ShJ
+ Procedures icg_u1d and icg_undeleted in this source file were
+ declared as functions but not returning a value. They were not
+ being called as functions, and are now not declared as functions.
+
+imred$dtoi/database.x 14 March, 1988 ShJ
+ Added procedure to put a double precision value: ddb_putd().
+
+imred$dtoi/spotlist.x 14 March, 1988 ShJ
+ Added code for additional input parameter: "maxad", the maximum
+ allowed input value, i.e., the AD units in a saturated pixel. From
+ this value and the "scale" parameter, spotlist calculates the
+ maximum permissable density, and writes this to the database as a
+ double precision value.
+
+imred$dtoi/hdfit.x 14 March, 1988 ShJ
+ Parameter "maxden" was removed, as this value is now calculated
+ precisely by spotlist and can be read from the database.
+
+imred$dtoi/spotlist.par
+imred$dtoi/hdfit.par
+imred$dtoi/doc/spotlist.hlp
+imred$dtoi/doc/hdfit.hlp 14 March, 1988 ShJ
+ Modified help pages and parameter files for spotlist and hdfit to
+ support the above changes to the user interface.
+
+imred$dtoi/hdtoi.x 11 March, 1988 ShJ
+ Bug fixed in hd_aptrans(). The equations for the k75 and k50
+ transformations were incorrect, having a '*' where a '+' should
+ have been. Also, the strncmp procedure was only checking the first
+ character to distinguish between transformation types, in which
+ case k75 and k50 would not be resolved.
+
+imred$dtoi/hdfit.x 10 March, 1988 ShJ
+ Repaired an error in incrementing an offset into the output
+ arrays in hd_rdloge. This error was seen only when more than
+ two databases contributed input values to be fit. This was
+ a trivial arithmetic error that had been overlooked due to
+ insufficient testing. This bug would produce a memory error
+ as values were written into unallocated locations.
+
+imred$dtoi/hdicfit/hdic.com 9 March, 1988 ShJ
+ Reordered the values in the common block, as the largest double
+ precision value was following the integers. The SUN-4 compiler
+ gave warning of this, then padded the double value. Also at this
+ time file hdicgundelete.x was renamed to hdicgundel.x to avoid
+ problems associated with filenames longer than 14 characters. The
+ hdicfit library was completely rebuilt at this time, to insure the
+ new object module would be retrieved.
+.endhelp
diff --git a/noao/imred/dtoi/database.x b/noao/imred/dtoi/database.x
new file mode 100644
index 00000000..cb501472
--- /dev/null
+++ b/noao/imred/dtoi/database.x
@@ -0,0 +1,611 @@
+include <time.h>
+include <ctype.h>
+include <ctotok.h>
+include <finfo.h>
+
+# DATABASE.X -- This file contains source for the database utilities used by
+# the DTOI package. They are based on Frank Valdes's dtext utilities.
+
+# Definition for dbtext structure.
+
+define DT_LEN 5
+
+define DT Memi[$1] # FIO channel
+define DT_NRECS Memi[$1+1] # Number of records
+define DT_OFFSETS Memi[$1+2] # Pointer to record offsets
+define DT_NAMES Memi[$1+3] # Pointer to name indices
+define DT_MAP Memi[$1+4] # Pointer to record names
+
+define DT_OFFSET Meml[DT_OFFSETS($1)+$2-1]
+define DT_NAMEI Memi[DT_NAMES($1)+$2-1]
+define DT_NAME Memc[DT_MAP($1)+DT_NAMEI($1,$2)]
+
+define DT_ALLOC 20 # Allocation block size
+
+
+# DDB_MAP -- Map the database.
+
+pointer procedure ddb_map (database, mode)
+
+char database[ARB] # Database file
+int mode # FIO mode
+
+int i, nrec
+int dt_alloc1, dt_alloc2
+pointer db, str
+
+int open(), fscan(), strlen()
+bool streq()
+long note()
+errchk delete, open
+
+begin
+ call calloc (db, DT_LEN, TY_STRUCT)
+
+ if (mode == NEW_FILE)
+ iferr (call delete (database))
+ ;
+
+ DT(db) = open (database, mode, TEXT_FILE)
+
+ if (mode != READ_ONLY)
+ return (db)
+
+ dt_alloc1 = DT_ALLOC
+ dt_alloc2 = DT_ALLOC * SZ_LINE
+ call malloc (DT_OFFSETS(db), dt_alloc1, TY_LONG)
+ call malloc (DT_NAMES(db), dt_alloc1, TY_INT)
+ call malloc (DT_MAP(db), dt_alloc2, TY_CHAR)
+ call malloc (str, SZ_LINE, TY_CHAR)
+
+ nrec = 1
+ DT_NRECS(db) = 0
+ DT_NAMEI(db, nrec) = 0
+
+ while (fscan (DT(db)) != EOF) {
+ call gargwrd (DT_NAME(db, nrec), SZ_LINE)
+
+ if (streq (DT_NAME(db, nrec), "begin")) {
+ call gargstr (Memc[str], SZ_LINE)
+ for (i=str; IS_WHITE(Memc[i]); i=i+1)
+ ;
+ call strcpy (Memc[i], DT_NAME(db, nrec), SZ_LINE)
+
+ for (i = 1; i < nrec; i = i + 1)
+ if (streq (DT_NAME(db, i), DT_NAME(db, nrec)))
+ break
+
+ if (i < nrec)
+ DT_OFFSET(db, i) = note (DT(db))
+ else {
+ DT_NRECS(db) = nrec
+ DT_OFFSET(db, nrec) = note (DT(db))
+ DT_NAMEI(db, nrec+1) = DT_NAMEI(db, nrec) +
+ strlen (DT_NAME(db, nrec)) + 1
+ nrec = nrec + 1
+ }
+
+ if (nrec == dt_alloc1) {
+ dt_alloc1 = dt_alloc1 + DT_ALLOC
+ call realloc (DT_OFFSETS(db), dt_alloc1, TY_LONG)
+ call realloc (DT_NAMES(db), dt_alloc1, TY_INT)
+ }
+
+ if (DT_NAMEI(db, nrec) + SZ_LINE >= dt_alloc2) {
+ dt_alloc2 = dt_alloc2 + DT_ALLOC * SZ_LINE
+ call realloc (DT_MAP(db), dt_alloc2, TY_CHAR)
+ }
+ }
+ }
+
+ call realloc (DT_MAP(db), DT_NAMEI(db, nrec), TY_CHAR)
+ call realloc (DT_OFFSETS(db), DT_NRECS(db), TY_LONG)
+ call realloc (DT_NAMES(db), DT_NRECS(db), TY_INT)
+
+ return (db)
+end
+
+
+# DDB_UNMAP -- Unmap the database.
+
+procedure ddb_unmap (db)
+
+pointer db # Database file descriptor
+
+begin
+ call close (DT(db))
+ call mfree (DT_MAP(db), TY_CHAR)
+ call mfree (DT_OFFSETS(db), TY_LONG)
+ call mfree (DT_NAMES(db), TY_INT)
+ call mfree (db, TY_STRUCT)
+end
+
+
+# DDB_PREC -- Write a record to the database.
+
+procedure ddb_prec (db, record)
+
+pointer db # Pointer to database
+char record[ARB] # Name of record to enter
+
+pointer sp, entry
+
+begin
+ call smark (sp)
+ call salloc (entry, SZ_LINE, TY_CHAR)
+
+ call sprintf (Memc[entry], SZ_LINE, "begin\t%s\n")
+ call pargstr (record)
+
+ call fprintf (DT(db), Memc[entry])
+
+ call sfree (sp)
+end
+
+
+# DDB_PUTR -- Write a real valued field into the current record.
+
+procedure ddb_putr (db, field, value)
+
+pointer db # Pointer to database
+char field[ARB] # Format string
+real value # Real value to output
+
+pointer sp, entry
+
+begin
+ call smark (sp)
+ call salloc (entry, SZ_LINE, TY_CHAR)
+
+ call sprintf (Memc[entry], SZ_LINE, "\t%s\t%g\n")
+ call pargstr (field)
+ call pargr (value)
+
+ call fprintf (DT(db), Memc[entry])
+
+ call sfree (sp)
+end
+
+# DDB_PUTD -- Write a double valued field into the current record.
+
+procedure ddb_putd (db, field, value)
+
+pointer db # Pointer to database
+char field[ARB] # Format string
+double value # Real value to output
+
+pointer sp, entry
+
+begin
+ call smark (sp)
+ call salloc (entry, SZ_LINE, TY_CHAR)
+
+ call sprintf (Memc[entry], SZ_LINE, "\t%s\t%g\n")
+ call pargstr (field)
+ call pargd (value)
+
+ call fprintf (DT(db), Memc[entry])
+
+ call sfree (sp)
+end
+
+
+# DDB_PUTI -- Write an integer valued field into the current record.
+
+procedure ddb_puti (db, field, value)
+
+pointer db # Pointer to database
+char field[ARB] # Format string
+int value # Integer value to output
+
+pointer sp, entry
+
+begin
+ call smark (sp)
+ call salloc (entry, SZ_LINE, TY_CHAR)
+
+ call sprintf (Memc[entry], SZ_LINE, "\t%s\t%d\n")
+ call pargstr (field)
+ call pargi (value)
+
+ call fprintf (DT(db), Memc[entry])
+
+ call sfree (sp)
+end
+
+
+# DDB_PSTR -- Write a string valued field into the current record.
+
+procedure ddb_pstr (db, field, value)
+
+pointer db # Pointer to database
+char field[ARB] # Format string
+char value[ARB] # String field
+
+pointer sp, entry
+
+begin
+ call smark (sp)
+ call salloc (entry, SZ_LINE, TY_CHAR)
+
+ call sprintf (Memc[entry], SZ_LINE, "\t%s\t%s\n")
+ call pargstr (field)
+ call pargstr (value)
+
+ call fprintf (DT(db), Memc[entry])
+
+ call sfree (sp)
+end
+
+
+# DDB_PAR -- Put an array of real values into a field in the current record.
+
+procedure ddb_par (db, field, array, nvals)
+
+pointer db # Pointer to database structure
+char field[ARB] # Name of field to be added
+real array[nvals] # Array of real values
+int nvals # Number of values in array
+
+pointer sp, entry
+int i
+
+begin
+ call smark (sp)
+ call salloc (entry, SZ_LINE, TY_CHAR)
+
+ call sprintf (Memc[entry], SZ_LINE, "\t%s\t%d\n")
+ call pargstr (field)
+ call pargi (nvals)
+
+ call fprintf (DT(db), Memc[entry])
+
+ do i = 1, nvals {
+ call sprintf (Memc[entry], SZ_LINE, "\t\t%g\n")
+ call pargr (array[i])
+
+ call fprintf (DT(db), Memc[entry])
+ }
+
+ call sfree (sp)
+end
+
+
+# DDB_PAD -- Put an array of double values into a field in the current record.
+
+procedure ddb_pad (db, field, array, nvals)
+
+pointer db # Pointer to database structure
+char field[ARB] # Name of field to be added
+double array[nvals] # Array of double values
+int nvals # Number of values in array
+
+pointer sp, entry
+int i
+
+begin
+ call smark (sp)
+ call salloc (entry, SZ_LINE, TY_CHAR)
+
+ call sprintf (Memc[entry], SZ_LINE, "\t%s\t%d\n")
+ call pargstr (field)
+ call pargi (nvals)
+
+ call fprintf (DT(db), Memc[entry])
+
+ do i = 1, nvals {
+ call sprintf (Memc[entry], SZ_LINE, "\t\t%g\n")
+ call pargd (array[i])
+
+ call fprintf (DT(db), Memc[entry])
+ }
+
+ call sfree (sp)
+end
+
+
+# DDB_PAI -- Put an array of integer values into a field in the current
+# record.
+
+procedure ddb_pai (db, field, array, nvals)
+
+pointer db # Pointer to database structure
+char field[ARB] # Name of field to be added
+int array[nvals] # Array of integer values
+int nvals # Number of values in array
+
+pointer sp, entry
+int i
+
+begin
+ call smark (sp)
+ call salloc (entry, SZ_LINE, TY_CHAR)
+
+ call sprintf (Memc[entry], SZ_LINE, "\t%s\t%d\n")
+ call pargstr (field)
+ call pargi (nvals)
+
+ call fprintf (DT(db), Memc[entry])
+
+ do i = 1, nvals {
+ call sprintf (Memc[entry], SZ_LINE, "\t\t%d\n")
+ call pargi (array[i])
+
+ call fprintf (DT(db), Memc[entry])
+ }
+
+ call sfree (sp)
+end
+
+
+# DDB_LOCATE -- Locate a database record.
+
+int procedure ddb_locate (db, name)
+
+pointer db # DTTEXT pointer
+char name[ARB] # Record name
+
+int i
+
+bool streq()
+pointer sp, err_string
+
+begin
+ do i = 1, DT_NRECS(db) {
+ if (streq (name, DT_NAME(db, i)))
+ return (i)
+ }
+
+ # The record was not found
+
+ call smark (sp)
+ call salloc (err_string, SZ_LINE, TY_CHAR)
+
+ call sprintf (Memc[err_string], SZ_LINE,
+ "DDB_LOCATE: Database record '%s' not found")
+ call pargstr (name)
+
+ call error (21, Memc[err_string])
+ call sfree (sp)
+end
+
+
+# DDB_GSTR -- Get a string field
+
+procedure ddb_gstr (db, record, field, str, maxchar)
+
+pointer db # Database file descriptor
+int record # Database index
+char field[ARB] # Database field
+char str[maxchar] # String value
+int maxchar # Maximum characters for string
+
+char name[SZ_LINE]
+
+pointer sp, esp
+int i, fscan()
+bool streq()
+
+begin
+ if ((record < 1) || (record > DT_NRECS(db)))
+ call error (22, "Database record request out of bounds")
+
+ call seek (DT(db), DT_OFFSET(db, record))
+
+ while (fscan (DT(db)) != EOF) {
+ call gargwrd (name, SZ_LINE)
+
+ if (streq (name, "begin"))
+ break
+ else if (streq (name, field)) {
+ call gargstr (str, maxchar)
+ for (i=1; IS_WHITE(str[i]); i=i+1)
+ ;
+ if (i>1)
+ call strcpy (str[i], str, maxchar)
+ return
+ }
+ }
+
+ call smark (sp)
+ call salloc (esp, SZ_LINE, TY_CHAR)
+
+ call sprintf (Memc[esp], SZ_LINE,
+ "DDB_GSTR: Database field '%s' not found")
+ call pargstr (field)
+
+ call error (23, Memc[esp])
+ call sfree (sp)
+end
+
+
+# DDB_GETI -- Get an integer field.
+
+int procedure ddb_geti (db, record, field)
+
+pointer db # DTTEXT pointer
+int record # Database index
+char field[ARB] # Database field
+
+real rval
+bool fp_equalr()
+real ddb_getr()
+
+errchk ddb_getr
+
+begin
+ rval = ddb_getr (db, record, field)
+
+ if (fp_equalr (rval, INDEFR))
+ return (INDEFI)
+ else
+ return (int (rval))
+end
+
+
+# DDB_GETR -- Get an real field
+
+real procedure ddb_getr (db, record, field)
+
+pointer db # DTTEXT pointer
+int record # Database index
+char field[ARB] # Database field
+
+pointer sp, esp
+real rval
+char name[SZ_LINE]
+
+int fscan(), nscan()
+bool streq()
+
+begin
+ if ((record < 1) || (record > DT_NRECS(db)))
+ call error (24, "Database record request out of bounds")
+
+ call seek (DT(db), DT_OFFSET(db, record))
+
+ while (fscan (DT(db)) != EOF) {
+ call gargwrd (name, SZ_LINE)
+
+ if (streq (name, "begin"))
+ break
+ else if (streq (name, field)) {
+ call gargr (rval)
+ if (nscan() == 2)
+ return (rval)
+ else
+ call error (25, "Error in database field value")
+ }
+ }
+
+ call smark (sp)
+ call salloc (esp, SZ_LINE, TY_CHAR)
+
+ call sprintf (Memc[esp], SZ_LINE,
+ "DDB_GET: Database field '%s' not found")
+ call pargstr (field)
+
+ call error (26, Memc[esp])
+ call sfree (sp)
+end
+
+
+# DDB_GAR -- Get a real array field
+
+procedure ddb_gar (db, record, field, array, len_array, npts)
+
+pointer db # DTTEXT pointer
+int record # Database index
+char field[ARB] # Database field
+real array[len_array] # Array values
+int len_array # Length of array
+int npts # Number of values in the field
+
+int i
+double tmp
+pointer sp, dubble
+bool fp_equald()
+
+begin
+ call smark (sp)
+ call salloc (dubble, npts, TY_DOUBLE)
+
+ call ddb_gad (db, record, field, Memd[dubble], len_array, npts)
+ do i = 1, npts {
+ tmp = Memd[dubble+i-1]
+ if (fp_equald (tmp, INDEFD))
+ array[i] = INDEFR
+ else
+ array[i] = real (tmp)
+ }
+
+ call sfree (sp)
+end
+
+
+# DDB_GAD -- Get a double array field
+
+procedure ddb_gad (db, record, field, array, len_array, npts)
+
+pointer db # DTTEXT pointer
+int record # Database index
+char field[ARB] # Database field
+double array[len_array] # Array values
+int len_array # Length of array
+int npts # Number of points in the array
+
+pointer sp, esp
+char name[SZ_LINE]
+int i
+
+int fscan(), nscan()
+bool streq()
+
+begin
+ if ((record < 1) || (record > DT_NRECS(db)))
+ call error (27, "Database record request out of bounds")
+
+ call seek (DT(db), DT_OFFSET(db, record))
+
+ while (fscan (DT(db)) != EOF) {
+ call gargwrd (name, SZ_LINE)
+
+ if (streq (name, "begin"))
+ break
+ else if (streq (name, field)) {
+ call gargi (npts)
+ if (nscan() != 2)
+ call error (28, "Error in database field value")
+
+ npts = min (npts, len_array)
+ for (i = 1; i <= npts; i = i + 1) {
+ if (fscan (DT(db)) == EOF)
+ call error (29, "Error in database field value")
+
+ call gargd (array[i])
+ if (nscan() != 1)
+ call error (30, "Error in database field value")
+ }
+ return
+ }
+ }
+
+ call smark (sp)
+ call salloc (esp, SZ_LINE, TY_CHAR)
+
+ call sprintf (Memc[esp], SZ_LINE,
+ "DDB_GA: Database field '%s' not found")
+ call pargstr (field)
+
+ call error (31, Memc[esp])
+ call sfree (sp)
+end
+
+
+# DDB_PTIME -- Put a time string with a comment
+
+procedure ddb_ptime (db)
+
+pointer db # DTTEXT pointer
+
+char timestr[SZ_TIME]
+long time, clktime()
+
+begin
+ time = clktime (0)
+ call cnvtime (time, timestr, SZ_TIME)
+ call fprintf (DT(db), "# %s\n")
+ call pargstr (timestr)
+end
+
+
+# DDB_SCAN -- Scan a line from the database.
+
+int procedure ddb_scan (db)
+
+pointer db # DDB pointer
+int fscan()
+
+begin
+ return (fscan (DT(db)))
+end
diff --git a/noao/imred/dtoi/dematch.par b/noao/imred/dtoi/dematch.par
new file mode 100644
index 00000000..cd7a5cfc
--- /dev/null
+++ b/noao/imred/dtoi/dematch.par
@@ -0,0 +1,8 @@
+# Cl parameters are:
+database,f,a,,,,Database of density information
+wedge,f,a,"",,,Wedge number used for calibration
+filter,f,a,"",,,Filter used for calibration
+emulsion,f,a,"",,,Emulsion used for calibration
+wedgefile,f,h,"noao$lib/hdwedge.dat",,,File containing exposure information
+nskip,i,h,0,,,Number of faint spots skipped
+verbose,b,h,yes,,,Print exposure record from wedgefile
diff --git a/noao/imred/dtoi/dematch.x b/noao/imred/dtoi/dematch.x
new file mode 100644
index 00000000..ff47e90f
--- /dev/null
+++ b/noao/imred/dtoi/dematch.x
@@ -0,0 +1,160 @@
+include <error.h>
+
+# T_DEMATCH -- matches densities listed in the input database to
+# log exposure values retrieved from a system maintained or user
+# provided file. The output matches are added to the input database.
+
+procedure t_dematch ()
+
+pointer filter, emulsion, wedge_db, density_db, db, exp, den, sp
+pointer wedge, expo
+int nskip, rec, nvalues
+
+pointer ddb_map()
+bool clgetb()
+int ddb_locate(), ddb_geti(), clgeti()
+
+begin
+ call smark (sp)
+ call salloc (filter, SZ_FNAME, TY_CHAR)
+ call salloc (emulsion, SZ_FNAME, TY_CHAR)
+ call salloc (wedge_db, SZ_FNAME, TY_CHAR)
+ call salloc (density_db, SZ_FNAME, TY_CHAR)
+ call salloc (wedge, SZ_FNAME, TY_CHAR)
+
+ # Get parameters
+ call clgstr ("database", Memc[density_db], SZ_FNAME)
+ call clgstr ("wedge", Memc[wedge], SZ_FNAME)
+ call clgstr ("filter", Memc[filter], SZ_FNAME)
+ call clgstr ("emulsion", Memc[emulsion], SZ_FNAME)
+ call clgstr ("wedgefile", Memc[wedge_db], SZ_FNAME)
+ nskip = clgeti ("nskip")
+
+ # Retrieve exposure information; one wedge per run
+ call hd_rwedge (Memc[wedge_db], exp, Memc[wedge], Memc[filter],
+ Memc[emulsion], clgetb("verbose"))
+
+ db = ddb_map (Memc[density_db], READ_ONLY)
+ iferr {
+ rec = ddb_locate (db, "density")
+ nvalues = ddb_geti (db, rec, "den_val")
+ } then
+ call error (0, "Error locating density record in database")
+
+ call salloc (den, nvalues, TY_REAL)
+ iferr (call ddb_gar (db, rec, "den_val", Memr[den], nvalues, nvalues))
+ call error (0, "Error reading density information")
+
+ # Close db file before reopening for append.
+ call ddb_unmap (db)
+
+ # Add fields for wedge, filter and plate as "calibrate" record
+ db = ddb_map (Memc[density_db], APPEND)
+ call ddb_prec (db, "calibrate")
+ call ddb_pstr (db, "wedge", Memc[wedge])
+ call ddb_pstr (db, "filter", Memc[filter])
+ call ddb_pstr (db, "emulsion", Memc[emulsion])
+
+ # Exposures are returned in increasing order. Make sure the
+ # exposures are output in the same order as density values.
+
+ call salloc (expo, nvalues, TY_REAL)
+ call amovr (Memr[exp+nskip], Memr[expo], nvalues)
+
+ if (Memr[den] > Memr[den+nvalues-1])
+ call hd_reorderr (Memr[expo], nvalues)
+
+ # Now add exposure values to database
+ call ddb_ptime (db)
+ call ddb_prec (db, "exposure")
+ call ddb_par (db, "log_exp", Memr[expo], nvalues)
+
+ call ddb_unmap (db)
+
+ call mfree (exp, TY_REAL)
+ call sfree (sp)
+end
+
+
+# HD_RWEDGE -- Read wedge information from database file for a given
+# wedge, filter, emulsion combination. A pointer to the extracted
+# exposure values is returned as an argument.
+
+procedure hd_rwedge (db_file, exp, wedge, filter, emulsion, verbose)
+
+char db_file[SZ_FNAME] # Name of database with exposure information
+pointer exp # Pointer to array of exposure values - output
+char wedge[SZ_FNAME] # Wedge number
+char filter[SZ_FNAME] # Filter used
+char emulsion[SZ_FNAME] # Emulsion used
+bool verbose # Print record of exposure information?
+
+pointer db
+char wfe[SZ_FNAME]
+int rec, nvalues, stat, i
+
+pointer ddb_map()
+int ddb_locate(), ddb_geti(), ddb_scan()
+errchk ddb_map, ddb_scan
+
+begin
+ # Convert strings to upper case for matching in database
+ call strupr (wedge)
+ call strupr (filter)
+ call strupr (emulsion)
+
+ db = ddb_map (db_file, READ_ONLY)
+ iferr (rec = ddb_locate (db, wedge))
+ call erract (EA_FATAL)
+
+ # Construct field name of filter/emulsion combination in question
+ call sprintf (wfe, SZ_FNAME, "%s/%s")
+ call pargstr (emulsion)
+ call pargstr (filter)
+
+ # Retrieve exposure values from database file
+ iferr (nvalues = ddb_geti (db, rec, wfe))
+ call erract (EA_FATAL)
+
+ call malloc (exp, nvalues, TY_REAL)
+ stat = ddb_scan (db)
+
+ do i = 1, nvalues {
+ call gargr (Memr[exp+i-1])
+
+ # Calibration values are stored 8 values per line
+ if (mod (i, 8) == 0) {
+ if (nvalues > i)
+ stat = ddb_scan (db)
+ }
+ }
+
+ if (verbose) {
+ call printf ("\nCalibration log exposure values for %s/%s: \n")
+ call pargstr (wedge)
+ call pargstr (wfe)
+
+ do i = 1, nvalues {
+ call printf ("%8g ")
+ call pargr (Memr[exp+i-1])
+ if (mod (i, 8) == 0)
+ call printf ("\n")
+ }
+
+ # Need a newline if the last line didn't have 8 entries.
+ if (mod (nvalues, 8) != 0)
+ call printf ("\n")
+
+ call flush (STDOUT)
+ }
+
+ # Exposures are returned sorted in increasing order. That is,
+ # the exposure for the lightest spot is element one, and the
+ # darkest spot's exposure value is the last array element.
+
+ if (Memr[exp] > Memr[exp+nvalues-1])
+ # Out of order - flip elements
+ call hd_reorderr (Memr[exp], nvalues)
+
+ call ddb_unmap (db)
+end
diff --git a/noao/imred/dtoi/doc/dematch.hlp b/noao/imred/dtoi/doc/dematch.hlp
new file mode 100644
index 00000000..7dffad26
--- /dev/null
+++ b/noao/imred/dtoi/doc/dematch.hlp
@@ -0,0 +1,51 @@
+.help dematch Feb87 imred.dtoi
+.ih
+NAME
+dematch -- match density to log exposure values
+.ih
+USAGE
+dematch database
+.ih
+PARAMETERS
+.ls database
+Database containing density list, probably from \fIspotlist\fR.
+.le
+.ls wedge = "", filter = "", emulsion = ""
+Information used to retrieve log exposure values from \fBwedgefile\fR.
+.le
+.ls wedgefile = "noao$lib/hdwedge.dat"
+Name of file containing wedge intensity information.
+.le
+.ls nskip = 0
+Number of faint spots skipped, used as an offset into the list of
+log exposure values.
+.le
+.ls verbose = yes
+Print the log exposure information to STDOUT as well as to \fBdatabase\fR.
+.le
+.ih
+DESCRIPTION
+Task \fIdematch\fR matches density values to log exposure values. A database
+of density values is input, as well as information needed to
+retrieve log exposure values from a reference file. The two sources of
+information are matched, and the matching log exposure values are added
+as a record in the database.
+
+Parameter \fBnskip\fR tells how many faint spots were not
+included in the density \fBdatabase\fR. This information is
+used to align the density, exposure values. It doesn't matter if the
+densities are listed in a monotonically increasing or decreasing
+order, as long as no spots were omitted between the first and last
+measured.
+.ih
+EXAMPLES
+Match densities in db1 to log exposure values for wedge#117
+with a IIIAJ emulsion and a GG385 filter.
+.nf
+
+ cl> dematch db1 wedge=117 filt=gg385 emulsion=IIIAJ
+.fi
+.ih
+SEE ALSO
+spotlist, hdfit, hdtoi
+.endhelp
diff --git a/noao/imred/dtoi/doc/dtoi.ms b/noao/imred/dtoi/doc/dtoi.ms
new file mode 100644
index 00000000..4f999259
--- /dev/null
+++ b/noao/imred/dtoi/doc/dtoi.ms
@@ -0,0 +1,576 @@
+.RP
+.TL
+An Overview of the IRAF DTOI Package
+.AU
+Suzanne Hammond Jacoby
+.AI
+IRAF Group - Central Computer Services
+.K2 "" "" "*"
+February 1987
+.br
+Revised July 1988
+
+.AB
+This document describes the DTOI package, which contains tasks
+for determining and applying a density to intensity transformation to
+photographic data. The transformation is determined from a set
+of calibration spots with known relative intensities. A curve is
+interactively fit to the densities and intensities of the calibration
+spots. The transformation is then applied and a new output image written.
+.AE
+
+.NH
+Introduction
+.PP
+The DTOI package contains tasks for computing and applying a density
+to intensity transformation to photographic data. These tasks perform the
+standard steps in linearizing data: calculating HD data points from
+calibration spots, fitting a curve to these points and applying the HD
+curve to the data. It is also possible to combine related HD curves.
+Communication between the tasks is via text files which the user can
+inspect or modify. It is intended
+to be easy for users to introduce data from outside the DTOI package
+into the processing.
+.PP
+There are currently six tasks in the package. They are:
+
+.ce
+The \fBDTOI\fR Package
+.TS
+center;
+n.
+spotlist \&- Calculate densities and weights of calibration spots.
+dematch \&- Match densities to log exposure values.
+hdfit \&- Fit characteristic curve to density, exposure data.
+hdtoi \&- Apply HD transformation to image data.
+hdshift \&- Align related characteristic curves.
+selftest \&- Test transformation algorithm.
+.TE
+.PP
+The DTOI package does not currently support the self calibration of images,
+but the addition of this capability is planned. This would involve
+determining the HD curve from the data itself, by assuming the point spread
+function scales linearly with intensity.
+.PP
+Upon entering the package, your calibration spots and images to be
+transformed should be on the disk in IRAF image format.
+
+.NH
+Determining the HD Curve Data
+.PP
+To determine the HD curve, you need two sets of data: the
+measured photographic densities of a set of calibration spots and
+the log exposure values corresponding to these measurements. The
+log exposure values must be known a priori. Tasks \fIspotlist\fR and
+\fIdematch\fR are used to assemble these two data sets.
+.NH 2
+SPOTLIST
+.PP
+The first step is to calculate the density of
+the calibration spots, each of which is a separate IRAF image or image
+section. The spot density is either the median of the spot pixels or
+the mean of the pixels when pixels more then a user specified number of
+standard deviations away from the mean have been rejected. The numbers
+in the spot image must be scaled to density; parameter \fBspotlist.scale\fR
+is used such that density = input_value * scale. Task \fIspotlist\fR also
+calculates the standard deviation of each spot and reports
+the number of good pixels, i.e., the number of pixels not rejected
+when determining the mean density.
+The final product of this task is a record in the data base containing a
+density for each spot. The scale factor used is also written to the data
+base; it will be read later in task \fIhdtoi\fR.
+.NH 2
+DEMATCH
+.PP
+Log exposure values must be matched to the measured density values. These
+log exposure values must be known a priori and will be read from a file.
+Task \fIdematch\fR retrieves the proper exposure information by
+matching the wedge number, emulsion type and filter used. Once a match
+has been made, the proper log exposure values are written to a record
+in the database.
+.PP
+A database of log exposure values for the NOAO standard wedges is maintained
+in a system file; the wedge/emulsion/filter combinations available are listed
+in last section of this document. This file can be replaced with one specific
+to any institution; the file name is supplied to task \fIdematch\fR as a
+parameter. In this way the wedge file can be personalized to any application
+and not be lost when the system is updated.
+
+.NH
+Fitting the Curve
+.PP
+The HD curve, or characteristic curve, is a plot of density versus log
+exposure. This curve is determined from the data points generated by
+tasks \fIspotlist\fR and \fIdematch\fR. The objective is to fit
+a curve to these points, such that Log exposure = F(Density). The
+technique available in this package allows the independent variable of the
+fit to be a transformation of the density (log opacitance, for example).
+The log exposure and density values are
+read from the database. If multiple entries for a particular record are
+present in the database, the last one is used.
+.NH 2
+HDFIT
+.PP
+Task \fIhdfit\fR fits a characteristic curve to density and log exposure
+values in preparation for transforming an image from density to intensity.
+Five functional forms of the curve are available:
+.nf
+
+ Power Series
+ Linear Spline
+ Cubic Spline
+ Legendre Polynomials
+ Chebyshev Polynomials
+
+.fi
+.LP
+It is possible to apply a transformation to the
+independent variable (density above fog) prior to the fit. The traditional
+choice is to fit log exposure
+as a function of the log opacitance, rather than density directly. This is
+sometimes referred to as the Baker, or Seidel, function. Transforming
+the density has the effect of stretching the low density data points, which
+tend to be relatively oversampled.
+In the DTOI package, four independendent variables are currently available:
+.nf
+
+ Density
+ Log Opacitance
+ K50 - (Kaiser* Transform with alpha = 0.50)
+ K75 - (Kaiser* Transform with alpha = 0.75)
+
+.fi
+.FS
+* Margoshes and Rasberry, Spectrochimica Acta, Vol 24B, p497, (1969)
+.FE
+Any combination of transformation type and fitting function can be used and
+changed interactively. Two combinations of interest are discussed here.
+
+The default fit is a power series fit where the independent variable is
+Log Opacitance. That is:
+.LP
+.EQ
+
+ "Log Exposure = " sum from k=0 to {ncoeff - 1} {A sub k Y sup k}
+
+.EN
+.sp 1
+.EQ
+ "where Y = Log Opacitance = "Log sub 10 (10 sup Density - 1)
+.EN
+.LP
+A fit that is expected to best model a IIIA-J emulsion is a power series
+fit to a K75 transform of the density. That is,
+.LP
+.EQ
+
+ "Log Exposure = "sum from k=0 to {ncoeff - 1} {A sub k Y sup k}
+
+.EN
+.sp 1
+.EQ
+"where Y = K75 transform = Density + 0.75 " Log sub 10 (1 - 10 sup -Density )
+.EN
+.LP
+Over the expected small dynamic range in variables of the fit, legendre
+and chebyshev functions offer no advantages over a simple power series
+functional form. The cubic and linear spline fits may follow the data very
+closely, but with typically sparse data sets this is not desirable. It
+is expected that power series fit will serve satisfactorily in all cases.
+
+.NH 3
+Interactive Curve Fitting
+.PP
+Task \fIhdfit\fR can be run interactively or not. In interactive mode,
+points in the sample can be edited, added or deleted. Weighting values
+can be changed as well as the fog value, the type of transformation
+and the fitting function chosen. To obtain the best fit possible, interactive
+fitting is recommended. A complete list of the available commands
+is printed here; this list is also available interactively with the
+keystroke '\fL?\fR'.
+.TS
+center;
+c s s w(3.0i)
+c l s.
+
+ DTOI INTERACTIVE CURVE FITTING OPTIONS
+
+\fL?\fR Print options
+\fLa\fR Add the point at the cursor position to the sample
+\fLc\fR Print the coordinates and fit of point nearest the cursor
+\fLd\fR Delete data point nearest the cursor
+\fLf\fR Fit the data and redraw or overplot
+\fLg\fR T{
+Redefine graph keys. Any of the following data types may be along
+either axis:
+T}
+.T&
+l l l.
+ \fLx\fR Independent variable \fLy\fR Dependent variable
+ \fLf\fR Fitted value \fLr\fR Residual (y - f)
+ \fLd\fR Ratio (y / f) \fLn\fR Nonlinear part of y
+ \fLu\fR Density above fog
+
+Graph keys:
+.T&
+c l s.
+
+\fLh\fR h = (x,y) transformed density vs. log exposure
+\fLi\fR i = (y,x) log exposure vs. transformed density
+\fLj\fR j = (x,r) transformed density vs. residuals
+\fLk\fR k = (x,d) transformed density vs. the y(data)/y(fit) ratio
+\fLl\fR l = (y,u) log exposure vs. density above fog (HD Curve)
+
+\fLo\fR Overplot the next graph
+\fLq\fR T{
+Terminate the interactive curve fitting, updating the database file.
+T}
+\fLr\fR Redraw graph
+\fLu\fR Undelete the deleted point nearest the cursor
+\fLw\fR Set the graph window. For help type 'w' followed by '?'.
+\fLx\fR Change the x value of the point nearest the cursor
+\fLy\fR Change the y value of the point nearest the cursor
+\fLz\fR Change the weight of the point nearest the cursor
+
+.T&
+l s s w(3.0i).
+T{
+The parameters are listed or set with the following commands which may be
+abbreviated. To list the value of a parameter type the command alone.
+T}
+
+.T&
+l l s.
+
+\fL:show \fR[\fIfile\fR] Show the values of all the parameters
+\fL:vshow \fR[\fIfile\fR] Show the values of all the parameters verbosely
+\fL:errors \fR[\fIfile\fR] Print the errors of the fit (default STDOUT)
+\fL:reset \fR T{
+Return to original conditions of x, y, wts and npts.
+T}
+\fL:ebars \fR[\fIerrors/weights\fR] T{
+The size of marker type '[hv]ebars' can show either standard deviations or
+relative weights.
+T}
+\fL:function \fR[\fIvalue\fR] T{
+Fitting function (power, chebyshev, legendre, spline3, or spline1)
+T}
+\fL:transform \fR[\fIvalue\fR] Set the transform type (none, logo, k50, k75)
+\fL:fog \fR[\fIvalue\fR] Change the fog level (or ":fog reset")
+\fL:order \fR[\fIvalue\fR] Fitting function order
+\fL:quit \fR Terminate HDFIT without updating database
+\fL:/mark \fRstring T{
+Mark type (point, box, plus, cross, diamond, hline, vline, hebar, vebar, circle)
+T}
+
+.T&
+l s s.
+T{
+Additional commands are available for setting graph formats and manipulating
+the graphics. Use the following commands for help.
+T}
+
+.T&
+l l s.
+\fL:/help\fR Print help for graph formatting option
+\fL:.help\fR Print cursor mode help
+
+.TE
+.PP
+The value of fog can be changed interactively if you have
+reason to override the value written in the database by \fIspotlist\fR.
+You can reset the fog to its original value with the command ":fog reset".
+A common problem with defining the HD curve is that some of
+the calibration spot densities fall below fog. This is caused by either
+the low signal to noise at low densities or by making a poor choice of
+where to scan the fog level. These points are rejected from the fit
+when a transformation of the density is being made, as the transform cannot
+be evaluated for negative density. If the fog value or transformation
+type is interactively changed so this problem no longer exists,
+the spot densities are restored in the sample.
+
+The parameters of the final fit are written to a database which then
+contains the information
+necessary to reinitialize the curfit package for applying the transformation
+in \fIhdtoi\fR.
+
+.NH
+Applying the Transform
+.PP
+.NH 2
+HDTOI
+.PP
+Once the HD curve has been defined, it is applied to a density image
+in task \fIhdtoi\fR.
+Here the transformation is applied, as described by the fit parameters
+stored in the database. If more than one record of fit parameters is
+present, the last one is used. This means task \fIhdfit\fR can be
+repeated until an acceptable solution is found; the last solution will
+be used by \fIhdtoi\fR. On output, a new output image is written; the
+input image is left intact.
+.PP
+The transformation is accomplished by using a look-up table. All possible
+input values, from the minimum to maximum values found in the image, are
+converted to density using the scale value read from the database, and then
+to intensity using the fit parameters determined by \fIhdfit\fR. The input
+value is then the index into the intensity table:
+intensity = look_up_table (input_value).
+.PP
+A scaling factor can be applied to the final intensities, as typically
+they will be < 1.0. (The maximum log exposure in the NOAO wedge database
+is 0.0) By default, a saturated density pixel will be assigned the "ceiling"
+intensity of 30000 and the other pixels are scaled accordingly.
+The user is responsible for choosing a ceiling value
+that will avoid having significant digits truncated.
+The precision
+of the transform is unaffected by scaling the
+final intensities, although caution must be used if the output image
+pixel type is an integer.
+.PP
+The value of fog to be used is entered by the user, and can be either
+a number or a list of file names from which to calculate the fog value.
+The fog value is subtracted from the input image before the transformation
+takes place.
+Again, consider density values below fog. Two choices are available for
+these densities: the calculated intensity can be equal to the constant
+value 0.0 or equal -1.0 times the intensity determined for absolute (density).
+
+.NH
+Aligning Related HD curves
+.PP
+Calibration data sets from several plates can be combined once a shift
+particular to each set has been removed. "Different spot exposures
+define a series of HD curves which are parallel but mutually separated
+by arbitrary shifts in log exposure, produced by differing lamp intensities
+or exposure times. Generally, Kodak spectroscopic plates can be
+averaged if [1] they come from the same emulsion batch and box, [2]
+they receive identical hypersensitizing, [3] they are exposed similarly and
+[4] they receive the same development." *
+.FS
+* "Averaging Photographic Characteristic Curves", John Kormendy, from
+"ESO Workshop on Two Dimensional Photometry", Edited by P. Crane and
+K.Kjar, p 69, (1980), an ESO Publication.
+.FE
+.NH 2
+HDSHIFT
+.PP
+Procedure \fIhdshift\fR calculates and subtracts a zero point shift to
+bring several related HD curves into alignment. The individual shifts
+are calculated by elimination of the first coefficient (Bevington, eqn 9-3):
+.EQ
+
+a0 = y bar - a sub 1 X bar - a sub 2 X bar sup 2 - ~ ...~ - a sub n X bar sup n
+
+.EN
+Here, the averages over y and X refer to individual calibration set averages;
+the coefficients a1, ... an were previously calculated using data from all
+calibration sets with task \fIhdfit\fR, and stored in the database. The
+a0 term is calculated individually for each database; this term represents
+the zero point shift in log exposure and will be different for each database.
+
+On output, the log exposure values in each database have been
+shifted to the zero point shift of the first database in the list. The
+log exposure records are now aligned and it would be appropriate
+to run \fIhdfit\fR on the modified database list.
+.NH
+Testing the Transformation Algorithm
+.PP
+A test task is included to see if any numerical errors were introduced
+during the density to intensity transformation. It also evaluates
+truncation errors produced when an output image with integer pixels,
+rather than reals, is written.
+.NH 2
+SELFTEST
+.PP
+An intensity vector is generated from a density vector in two different
+ways. The first method uses the density vector and known coefficients
+to compute the intensity. The second method uses the curfit package
+to generate a look up table of intensities as done in task \fIhdtoi\fR. The
+residual of the two vectors is plotted; ideally the difference between
+the 'known' and 'calculated' intensity is zero.
+.PP
+Task \fIselftest\fR also plots intensity as a function of density for
+both integer and real output pixels. The user should investigate the
+plot with the cursor zoom and expand capabilities to determine if
+truncation errors are significant.
+.NH
+The Wedgefile Database
+.PP
+Task \fIdematch\fR reads a database and retrieves log exposure information
+for certain combinations of wedge number, photographic emulsion and filter.
+Those combinations included in the NOAO database are listed in the next
+section, although any calibration data can be included if the values are
+known. To modify the database, it is recommended that
+you generate a new file rather than add records to the existing file. This
+way, the modifications will not be lost when a new version of the IRAF
+system is released.
+
+In the database, the information for each wedge makes up a separate record;
+each record starts with the word \fBbegin\fR. Each record has a title field
+and can have multiple emulsion/filter fields. The number of log exposure
+values must be given, followed by the values written 8 per line. The order
+of the exposure data can be either monotonically increasing or decreasing.
+Here is an example:
+.DS
+begin 115
+ title MAYALL 4-M PF BEFORE 15APR74 (CHROME) [MP1-MP968]
+ IIIAJ/UG2 16
+ 0.000 -0.160 -0.419 -0.671 -0.872 -1.153 -1.471 -1.765
+ -2.106 -2.342 -2.614 -2.876 -3.183 -3.555 -3.911 -4.058
+ IIAO/UG2 16
+ 0.000 -0.160 -0.418 -0.670 -0.871 -1.152 -1.468 -1.761
+ -2.102 -2.338 -2.609 -2.870 -3.176 -3.547 -3.901 -4.047
+
+.DE
+.NH 2
+Contents of the NOAO Wedgefile
+.LP
+The following table lists the wedge/emulsion/filter combinations available in
+the NOAO wedgefile database.
+.TS
+center;
+l l s s s
+l l l l l.
+
+\fBWedge 24 CTIO SCHMIDT WESTON TUBE SENSITOMETER. \fR
+ MONO/MONO
+
+.T&
+l l s s s
+l l l l l.
+\fBWedge 48 PALOMAR 48-INCH SCHMIDT STEP WEDGE. \fR
+ MONO/MONO
+
+.T&
+l l s s s
+l l l l l.
+\fBWedge 84 OLD 84-INCH SPOT SENSITOMETER (1967) \fR
+ MONO/MONO
+
+.TE
+.TS
+l l s s s
+l l l l l.
+\fBWedge 101 SPOT BOX 4, KEPT IN SCHOENING-S LAB. \fR
+ IIIAJ/UG2 IIAO/UG2 IIIAJ/*5113 IIAO/*5113
+ IIAO/GG385 IIIAJ/CLEAR IIIAJ/GG385 IIAD/GG495
+ 127/GG495 098/RG610 127/RG610 IVN/RG695
+ MONO/4363 MONO/4760 MONO/5200 MONO/5876
+ MONO/6470
+
+.T&
+l l s s s
+l l l l l.
+\fBWedge 115 MAYALL 4-M PF BEFORE 15APR74 (CHROME) [MP1-MP968] \fR
+ IIIAJ/UG2 IIAO/UG2 IIIAJ/*5113 IIAO/*5113
+ IIAO/GG385 IIIAJ/CLEAR IIIAJ/GG385 IIAD/GG495
+ 127/GG495 098/RG610 127/RG610 IVN/RG695
+ MONO/4363 MONO/4770 MONO/5200 MONO/5876
+ MONO/6470
+
+.T&
+l l s s s
+l l l l l.
+\fBWedge 117 CTIO 4-METER P.F. \fR
+ IIIAJ/UG2 IIAO/UG2 IIIAJ/*5113 IIAO/*5113
+ IIAO/GG385 IIIAJ/CLEAR IIIAJ/GG385 IIAD/GG495
+ 127/GG495 098/RG610 127/RG610 IVN/RG695
+ MONO/4363 MONO/4770 MONO/5200 MONO/5876
+ MONO/6470
+
+.T&
+l l s s s
+l l l l l.
+\fBWedge 118 CTIO 4-METER CASSEGRAIN \fR
+ IIIAJ/UG2 IIAO/UG2 IIIAJ/*5113 IIAO/*5113
+ IIAO/GG385 IIIAJ/CLEAR IIIAJ/GG385 IIAD/GG495
+ 127/GG495 098/RG610 127/RG610 IVN/RG695
+ MONO/4363 MONO/4760 MONO/5200 MONO/5876
+ MONO/6470 MONO/6900
+
+.T&
+l l s s s
+l l l l l.
+\fBWedge 119 SPOT BOX 5, KEPT AT MAYALL 4-METER. \fR
+ IIIAJ/UG2 IIAO/UG2 IIIAJ/*5113 IIAO/*5113
+ IIAO/GG385 IIIAJ/CLEAR IIIAJ/GG385 IIAD/GG495
+ 127/GG495 098/RG610 127/RG610 IVN/RG695
+ MONO/4363 MONO/4760 MONO/5200 MONO/5876
+ MONO/6470
+
+.T&
+l l s s s
+l l l l l.
+\fBWedge 120 SPOT BOX 6, KEPT AT 2.1-METER. \fR
+ IIIAJ/UG2 IIAO/UG2 IIIAJ/*5113 IIAO/*5113
+ IIAO/GG385 IIIAJ/CLEAR IIIAJ/GG385 IIAD/GG495
+ 127/GG495 098/RG610 127/RG610 IVN/RG695
+ MONO/4363 MONO/4760 MONO/5200 MONO/5876
+ MONO/6470
+
+.T&
+l l s s s
+l l l l l.
+\fBWedge 121 SPOT BOX 8, KEPT IN SCHOENING'S LAB. \fR
+ IIIAJ/UG2 IIAO/UG2 IIIAJ/*5113 IIAO/*5113
+ IIAO/GG385 IIIAJ/CLEAR IIIAJ/GG385 IIAD/GG495
+ 127/GG495 098/RG610 127/RG610 IVN/RG695
+ MONO/4363 MONO/4760 MONO/5200 MONO/5876
+ MONO/6470
+
+.T&
+l l s s s
+l l l l l.
+\fBWedge 122 SPOT BOX 7, AVAILABLE AT KPNO NIGHT ASST'S OFFICE \fR
+ IIIAJ/UG2 IIAO/UG2 IIIAJ/*5113 IIAO/*5113
+ IIAO/GG385 IIIAJ/CLEAR IIIAJ/GG385 IIAD/GG495
+ 127/GG495 098/RG610 127/RG610 IVN/RG695
+ MONO/4363 MONO/4760 MONO/5200 MONO/5876
+ MONO/6470C
+.TE
+.TS
+l l s s s
+l l l l l.
+\fBWedge 123 MAYALL 4-M P.F. 15APR74 TO 21MAY74 [MP969-MP1051] \fR
+ IIIAJ/UG2 IIAO/UG2 IIIAJ/*5113 IIAO/*5113
+ IIAO/GG385 IIIAJ/CLEAR IIIAJ/GG385 IIAD/GG495
+ 127/GG495 098/RG610 127/RG610 IVN/RG695
+ MONO/4363 MONO/4770 MONO/5200 MONO/5876
+ MONO/6470
+
+.T&
+l l s s s
+l l l l l.
+\fBWedge 129 MAYALL 4-METER P.F. AFTER 21MAY74 [MP1052--> ] \fR
+ IIIAJ/UG2 IIAO/UG2 IIIAJ/*5113 IIAO/*5113
+ IIAO/GG385 IIIAJ/CLEAR IIIAJ/GG385 IIAD/GG495
+ 127/GG495 098/RG610 127/RG610 IVN/RG695
+ MONO/4363 MONO/4760 MONO/5200 MONO/5876
+ MONO/6470
+
+.T&
+l l s s s
+l l l l l.
+\fBWedge 130 MAYALL 4-METER CASS CAMERA. \fR
+ IIIAJ/UG2 IIAO/UG2 IIIAJ/*5113 IIAO/*5113
+ IIAO/GG385 IIIAJ/CLEAR IIIAJ/GG385 IIAD/GG495
+ 127/GG495 098/RG610 127/RG610 IVN/RG695
+ MONO/4363 MONO/4760 MONO/5200 MONO/5876
+ MONO/6470
+
+.T&
+l l s s s
+l l l l l.
+\fBWedge 138 TRAVELLING BOX AFTER 06JAN78. \fR
+ IIIAJ/UG2 IIAO/UG2 IIIAJ/*5113 IIAO/*5113
+ IIAO/GG385 IIIAJ/CLEAR IIIAJ/GG385 IIAD/GG495
+ 127/GG495 098/RG610 127/RG610 IVN/RG695
+ MONO/4363 MONO/4770 MONO/5200 MONO/5876
+ MONO/6470
+
+.T&
+l l s s s
+l l l l l.
+\fBWedge 201 TEN UCLA SPOTS (H. FORD, 10JAN78) \fR
+ MONO/MONO
+.TE
diff --git a/noao/imred/dtoi/doc/dtoi.toc b/noao/imred/dtoi/doc/dtoi.toc
new file mode 100644
index 00000000..cd794321
--- /dev/null
+++ b/noao/imred/dtoi/doc/dtoi.toc
@@ -0,0 +1,34 @@
+.LP
+.DS C
+\fBTable of Contents\fR
+.DE
+.sp 3
+1.\h'|0.4i'\fBIntroduction\fP\l'|5.6i.'\0\01
+.sp
+2.\h'|0.4i'\fBDetermining the HD Curve Data \fP\l'|5.6i.'\0\01
+.br
+\h'|0.4i'2.1.\h'|0.9i'SPOTLIST\l'|5.6i.'\0\02
+.br
+\h'|0.4i'2.2.\h'|0.9i'DEMATCH\l'|5.6i.'\0\02
+.sp
+3.\h'|0.4i'\fBFitting the Curve\fP\l'|5.6i.'\0\02
+.br
+\h'|0.4i'3.1.\h'|0.9i'HDFIT\l'|5.6i.'\0\02
+.br
+\h'|0.9i'3.1.1.\h'|1.5i'Interactive Curve Fitting\l'|5.6i.'\0\03
+.sp
+4.\h'|0.4i'\fBApplying the Transform\fP\l'|5.6i.'\0\05
+.br
+\h'|0.4i'4.1.\h'|0.9i'HDTOI\l'|5.6i.'\0\05
+.sp
+5.\h'|0.4i'\fBAligning Related HD curves\fP\l'|5.6i.'\0\06
+.br
+\h'|0.4i'5.1.\h'|0.9i'HDSHIFT\l'|5.6i.'\0\06
+.sp
+6.\h'|0.4i'\fBTesting the Transformation Algorithm\fP\l'|5.6i.'\0\06
+.br
+\h'|0.4i'6.1.\h'|0.9i'SELFTEST\l'|5.6i.'\0\06
+.sp
+7.\h'|0.4i'\fBThe Wedgefile Database\fP\l'|5.6i.'\0\06
+.br
+\h'|0.4i'7.1.\h'|0.9i'Contents of the NOAO Wedgefile\l'|5.6i.'\0\07
diff --git a/noao/imred/dtoi/doc/hdfit.hlp b/noao/imred/dtoi/doc/hdfit.hlp
new file mode 100644
index 00000000..0b55137e
--- /dev/null
+++ b/noao/imred/dtoi/doc/hdfit.hlp
@@ -0,0 +1,79 @@
+.help hdfit Mar88 imred.dtoi
+.ih
+NAME
+hdfit -- fit characteristic curve to density, exposure data
+.ih
+USAGE
+hdfit database
+.ih
+PARAMETERS
+.ls database
+Database[s] containing the density, log exposure information.
+.le
+.ls function = "power"
+Type of curve to fit; chosen from "power", "legendre", "chebyshev",
+"spline1" or "spline3". Abbreviations are permitted.
+.le
+.ls transform = "logopacitance"
+Transformation performed on the density prior to fitting. Chosen from
+"none", "logopacitance", "k50" or "k75".
+.le
+.ls weighting = "none"
+Weights can be assigned to the independent variable for fitting a curve.
+Choices are "none", "user" and "calculated".
+.le
+.ls order = 4
+Order of the fit.
+.le
+.ls interactive = yes
+Fit the data interactively?
+.le
+.ls device = "stdgraph"
+Interactive graphics device.
+.le
+.ls cursor = "stdgcur"
+Source of cursor input.
+.le
+.ih
+DESCRIPTION
+Task \fIhdfit\fR is used to fit a curve to density and log exposure
+values in preparation for transforming an image from density to intensity.
+The log exposure and density are read from \fBdatabase\fR.
+More than one database can be input,
+in which case one curve is fit to the combined data and the results
+written to each database in the list.
+
+Weights can be applied to the independent variable of the fit.
+Weights can be changed interactively, and are originally chosen from
+"none", "user" and "calculated". A weights value can
+be calculated from the standard deviations, read from \fBdatabase\fR,
+as weight = (normalized density) / sdev. If user weights are to be
+used, they are read from \fBdatabase\fR record "weights" as "wts_vals"
+entries.
+
+When \fBinteractive\fR = yes, the HD curve is plotted and the cursor
+made available for interactively examining and altering the fit.
+The fitting function, transformation and order can be modified; data
+points can be added, deleted or edited. Four choices of independent
+variable are available in \fBhdfit\fR by means of the parameter
+\fBtransform\fR. No transformation can take place, in which case
+the independent variable is the density. Other choices are the log
+opacitance or a Kaiser transform with alpha = 0.50 or 0.75. The
+default choice is to fit log exposure as a function of the log opacitance;
+this is traditionally known as the Baker-Seidel function.
+.ih
+EXAMPLES
+.nf
+Using the defaults as starting parameters, interactively fit a curve to
+the data points in db1.
+
+ cl> hdfit db1
+
+A sixth order power series function is fit in batch mode to the db1 data.
+
+ cl> hdfit db1 order=6 interactive-
+.fi
+.ih
+SEE ALSO
+spotlist, dematch, hdtoi
+.endhelp
diff --git a/noao/imred/dtoi/doc/hdshift.hlp b/noao/imred/dtoi/doc/hdshift.hlp
new file mode 100644
index 00000000..aaa59063
--- /dev/null
+++ b/noao/imred/dtoi/doc/hdshift.hlp
@@ -0,0 +1,50 @@
+.help hdshift Feb87 imred.dtoi
+.ih
+NAME
+hdshift - calculate and subtract zero point to align HD curves.
+.ih
+USAGE
+hdshift database
+.ih
+PARAMETERS
+.ls database
+Input list of databases containing density, exposure and fit information.
+.le
+.ih
+DESCRIPTION
+For each file in \fBdatabase\fR, procedure \fBhdshift\fR calculates and
+subtracts a zero point shift to bring several related HD curves into
+alignment. The individual shifts are calculated by elimination of the
+first coefficient (Bevington, eqn 9-3):
+.nf
+ _ _ _ _
+ a0 = y - a1*X - a2*X**2 - ... - an*X**n
+
+.fi
+Here, the averages over y and X refer to individual \fBdatabase\fR averages;
+the coefficients a1, ... an were previously calculated using data from all
+\fBdatabase\fRs, in task \fIhdfit\fR, and stored in the database. The
+a0 term is calculated individually for each database; this term represents
+the zero point shift in log exposure and will be different for each database.
+
+On output, the log exposure values in each \fBdatabase\fR have been
+shifted to the zero point shift of the first database in the list. The
+log exposure records are now aligned and it would be appropriate
+to run task \fIhdfit\fR on the modified \fBdatabase\fR list and
+determine the common solution.
+.ih
+EXAMPLES
+.nf
+
+Shift the curves in four databases to a common zero point.
+
+ cl> hdshift db1,db2,db3,db4
+.fi
+.ih
+SEE ALSO
+hdfit, hdtoi
+.br
+"Averaging Photographic Characteristic Curves", John Kormendy, from
+"ESO Workshop on Two Dimensional Photometry", Edited by P. Crane and
+K.Kjar, p 69, (1980), an ESO Publication.
+.endhelp
diff --git a/noao/imred/dtoi/doc/hdtoi.hlp b/noao/imred/dtoi/doc/hdtoi.hlp
new file mode 100644
index 00000000..bf4355f0
--- /dev/null
+++ b/noao/imred/dtoi/doc/hdtoi.hlp
@@ -0,0 +1,88 @@
+.help hdtoi May88 imred.dtoi
+.ih
+NAME
+hdtoi -- transform images according to hd curve
+.ih
+USAGE
+hdtoi input output database
+.ih
+PARAMETERS
+.ls input
+List of images to be transformed.
+.le
+.ls output
+List of output image names.
+.le
+.ls database
+Name of text database describing HD curve.
+.le
+.ls fog = ""
+Value of fog level, read from database if unspecified.
+.le
+.ls option = "mean"
+Option for calculating fog density when \fBfog\fR is a file list, can be
+either "mean" or "median".
+.le
+.ls sigma = 3.0
+If \fBfog\fR is a file name, and \fBoption\fR = "mean", the mean fog density
+is iteratively calculated using this rejection criteria.
+.le
+.ls floor = 0.0
+Value assigned to levels below fog, can be either 0.0 or -1.0.
+.le
+.ls ceiling = 30000.
+The final intensities are scaled to this value, such that a saturated
+input density equals \fBceiling\fR on output.
+.le
+.ls datatype = "r"
+Datatype of output image pixels.
+.le
+.ls verbose = yes
+Print log of processing to STDOUT.
+.le
+.ih
+DESCRIPTION
+Task \fIhdtoi\fR transforms one image to another as described by the
+\fBdatabase\fR. There is only one HD curve per run; the same
+transformation is applied to all input images.
+
+The fog value can be obtained in three ways: read from the database, read
+as a floating point number, or calculated from a list of fog images. If
+parameter \fBfog\fR is not specified, the fog value is read from
+\fBdatabase\fR. If \fBfog\fR is specified, it can be entered
+as either a floating point number or as a list of file names. If the
+value cannot be read as a number, it is assumed to be a file name. In that
+case, the density of each file in the fog list is calculated and the
+average of these values is subtracted from \fBinput\fR before processing.
+The algorithm used to calculate the fog density is selected by the
+\fBoption\fR parameter, and is either a "mean" or "median" calculation.
+The fog density can be the mean value after pixels more than the specified
+number of sigma have been rejected, or the median value of all the fog spot
+pixels.
+
+The fog value is subtracted from the input image before the transformation
+takes place. It is possible that some density values will fall below
+the fog level; these values are handled in one of two ways. Values
+below the fog value are set equal to 0.0 when \fBfloor\fR = 0.0. If
+\fBfloor\fR = -1.0, the resulting intensity = -1 * intensity (abs (value)).
+
+A scaling factor is applied to the final intensities, as typically
+they will be < 1.0. The \fBceiling\fR parameter is used to specify what
+value a saturated density is transformed to; all intensities are scaled
+to this upper limit. The precision of the transformation is unaffected by
+this parameter, although caution must be used if the output image pixel
+type is an integer. The user is responsible for choosing
+a \fBceiling\fR that avoids the truncation of significant digits.
+.ih
+EXAMPLES
+Convert three density images to intensity images as described in database db1.
+
+ cl> hdtoi denin* intim1,intim2,intim3 db1
+.ih
+TIME REQUIREMENTS
+Task \fBhdtoi\fR requires 20 cpu seconds to transform a 512 square image, with
+a 12 bit data range, on a VAX 750
+.ih
+SEE ALSO
+spotlist, dematch, hdfit
+.endhelp
diff --git a/noao/imred/dtoi/doc/selftest.hlp b/noao/imred/dtoi/doc/selftest.hlp
new file mode 100644
index 00000000..329c9099
--- /dev/null
+++ b/noao/imred/dtoi/doc/selftest.hlp
@@ -0,0 +1,81 @@
+.help selftest Feb87 imred.dtoi
+.ih
+NAME
+selftest -- test routine to verify \fIdtoi\fR transformation
+.ih
+USAGE
+selftest nbits
+.ih
+PARAMETERS
+.ls nbits = 12
+Dymanic range of data to test.
+.le
+.ls device = "stdgraph"
+Plotting device for graphical output.
+.le
+.ls verbose = no
+A table of density, intensity values is printed if \fBverbose\fR = yes.
+.le
+.ls ceiling = 30000.
+Maximum intensity to output.
+.le
+.ls max_raw = 0
+The maximum raw data value. Needed only if \fInbits\fR equals something
+other than 12, 15 or 0.
+.le
+.ls scale = 0.0
+The raw data value to density scale value. Needed only if \fInbits\fR
+equals something other than 12, 15, or 0.
+.le
+
+.ih
+DESCRIPTION
+Task \fIselftest\fR is a test program for the \fIdtoi\fR package. Its
+output can be examined to see if numerical errors are introduced during
+the density to intensity transformation. It also evaluates truncation
+errors produced when an output image with integer pixels is written.
+
+Many different PDS setups can be investigated with task \fBselftest\fR.
+Setting parameter \fInbits\fR = 12
+indicates PDS format data, with data range 0 to 3071. Setting \fInbits\fR = 15
+indicates FITS format data, with data range 0 to 24575. The special value of
+\fInbits\fR = 0 means a small test data range from 1 to 144 is investigated.
+If any other value of \fInbits\fR is entered, the user is queried for the
+max raw data values and the raw data to density scaling factor.
+
+An intensity vector is generated from a density vector in two different ways.
+The first method uses the density vector and known coefficients to compute
+the intensity. The second method uses the curfit package to generate a
+look up table of intensities as done in task \fBHDTOI\fR. The residual
+of the two intensity vectors is plotted. Ideally, the difference between
+the 'known' intensities and 'calculated' intensities is zero.
+
+The second plot output by \fBselftest\fR shows intensity as a function
+of density. Two lines are overplotted; integer intensity versus density
+and real intensity versus density. Because truncation errors are most
+pronounced at low density values, the plot covers only the lowest 5%
+of the density range. The user should investigate the plot with the
+cursor zoom and expand capabilities to determine if truncation errors
+are significant.
+
+In verbose mode, \fBselftest\fR produced a three column table of raw
+data value, density and calculated intensity.
+
+.ih
+EXAMPLES
+
+.nf
+Run task selftest for 12 bit data with plots appearing on the terminal.
+
+ cl> selftest
+
+.fi
+Run selftest in verbose mode, spooling the output to file 'ditable'. This
+file is then run through the 'fields' task to extract the density and intensity
+columns which are piped to plot. The results in a plot of the look up table.
+.nf
+
+ cl> selftest ver+ > ditable
+ cl> fields ditable 2,3 | graph xlab=Density ylab=Intensity
+.fi
+.endhelp
diff --git a/noao/imred/dtoi/doc/splotlist.hlp b/noao/imred/dtoi/doc/splotlist.hlp
new file mode 100644
index 00000000..43b3f223
--- /dev/null
+++ b/noao/imred/dtoi/doc/splotlist.hlp
@@ -0,0 +1,81 @@
+.help spotlist May88 imred.dtoi
+.ih
+NAME
+spotlist -- calculate densities of calibration spots
+.ih
+USAGE
+spotlist spots fogs database
+.ih
+PARAMETERS
+.ls spots
+List of image files containing the calibration data.
+.le
+.ls fogs
+List of image files containing fog spots.
+.le
+.ls database
+Name for output database.
+.le
+.ls scale = 0.00151 # (4.65 / 3071.)
+The scale factor to convert values in the image files to densities, such
+that scale = density / input_value.
+.le
+.ls maxad = 3071
+The maximum A/D value, that is, the input value corresponding to a
+saturated pixel.
+.le
+.ls option= "mean"
+Option for calculating densities can be either "mean" or "median".
+.le
+.ls sigma = 3.0
+Rejection criteria for iteratively calculating mean density.
+.le
+.ih
+DESCRIPTION
+Task \fIspotlist\fR reads calibration spot images and calculates their
+density and standard deviation. Three records are entered in the
+database: density, standard deviation and number of unrejected pixels.
+Each record contains as many entries as calibration spots.
+
+All input values are multiplied by the \fBscale\fR parameter to convert
+them to densities. The value of \fBscale\fR is not critical to the
+reductions, it is provided so that \fIspotlist\fR output can be in the
+familiar units of density. The default value of \fBscale\fR is correct
+for NOAO PDS data written to a PDS format tape. If a FITS format tape was
+written, \fBscale\fR = 0.0001893. These values are appropriate for the PDS
+with its new 15-bit logarithmic A to D converter. The value of \fBscale\fR
+used is also entered in the database.
+
+Parameter \fBmaxad\fR is the integer input value that represents a
+saturated pixel. This value is used by \fIspotlist\fR to accurately
+calculate the density of a saturated pixel, which is then entered in the
+database. This value of "maxden" will later be used by task \fIhdfit\fR
+to normalize the independent variable vector, and by task \fIhdtoi\fR to
+scale the intensity range precisely to a user specified value.
+
+A fog level is calculated from image \fBfogs\fR, and entered into
+the database file. If more than one image is given for \fBfogs\fR,
+a single fog value is calculated from all fog pixels. The fog level
+is calculated but not subtracted in this procedure. The fog images to be
+averaged should be the same size. An entry for the fog level is made
+in the database.
+
+The \fBspots\fR files are assumed to be ordered such that they are either
+monotonically increasing or decreasing in density, with no omitted spots
+between the first and last measured. The calculated density can be
+calculated two ways; the algorithm used is selected by the \fBoption\fR
+parameter. The density is either the mean spot value after pixels more
+than the specified number of sigma from the mean value have been rejected,
+or the median value of all the spot pixels.
+.ih
+EXAMPLES
+Calculate mean densities of calibration spots which had previously been
+read in from a FITS format tape. The database "db1" will be created.
+
+.nf
+ cl> spotlist spots* fogspot db1 scale=1.893e-4
+.fi
+.ih
+SEE ALSO
+dematch, hdfit, hdtoi
+.endhelp
diff --git a/noao/imred/dtoi/dtoi.cl b/noao/imred/dtoi/dtoi.cl
new file mode 100644
index 00000000..3dd6c42b
--- /dev/null
+++ b/noao/imred/dtoi/dtoi.cl
@@ -0,0 +1,16 @@
+#{
+# DTOI package -- Density to Intensity Transformation Package. (Feb87)
+
+set dtoi = "iraf$noao/imred/dtoi/"
+
+package dtoi
+
+task dematch,
+ hdfit,
+ hdtoi,
+ hdshift,
+ selftest,
+ spotlist = "dtoi$x_dtoi.e"
+
+
+clbye()
diff --git a/noao/imred/dtoi/dtoi.hd b/noao/imred/dtoi/dtoi.hd
new file mode 100644
index 00000000..af554ac2
--- /dev/null
+++ b/noao/imred/dtoi/dtoi.hd
@@ -0,0 +1,11 @@
+# Help directory for the dtoi package.
+
+$doc = "iraf$noao/imred/dtoi/doc/"
+
+dematch hlp=doc$dematch.hlp, src=dematch.x
+hdfit hlp=doc$hdfit.hlp, src=hdfit.x
+hdtoi hlp=doc$hdtoi.hlp, src=hdtoi.x
+hdshift hlp=doc$hdshift.hlp, src=hdshift.x
+spotlist hlp=doc$spotlist.hlp, src=spotlist.x
+selftest hlp=doc$selftest.hlp, src=selftest.x
+revisions sys=Revisions
diff --git a/noao/imred/dtoi/dtoi.men b/noao/imred/dtoi/dtoi.men
new file mode 100644
index 00000000..f22d92eb
--- /dev/null
+++ b/noao/imred/dtoi/dtoi.men
@@ -0,0 +1,6 @@
+ dematch - Match a list of density values to exposure values
+ hdfit - Fit a curve to density, log exposure values
+ hdshift - Align related HD curves
+ hdtoi - Apply DTOI transformation to density image
+ selftest - Self test program to check DTOI transformation
+ spotlist - Generate a list of calibration spot values
diff --git a/noao/imred/dtoi/dtoi.par b/noao/imred/dtoi/dtoi.par
new file mode 100644
index 00000000..494aa73c
--- /dev/null
+++ b/noao/imred/dtoi/dtoi.par
@@ -0,0 +1,2 @@
+version,s,h,"February 13, 1987"
+mode,s,h,ql
diff --git a/noao/imred/dtoi/hd_aravr.x b/noao/imred/dtoi/hd_aravr.x
new file mode 100644
index 00000000..3376264b
--- /dev/null
+++ b/noao/imred/dtoi/hd_aravr.x
@@ -0,0 +1,50 @@
+define MAX_ITERATIONS 10
+include <mach.h>
+
+# HD_ARAV -- Compute the mean and standard deviation of a sample array by
+# iteratively rejecting points further than KSIG from the mean. If the
+# value of KSIG is given as 0.0, a cutoff value will be automatically
+# calculated from the standard deviation and number of points in the sample.
+# The number of pixels remaining in the sample upon termination is returned
+# as the function value.
+#
+# A max_iterations parameter was added to prevent the rejection scheme
+# from oscillating endlessly for nearly saturated pixels. This is the
+# only difference between the vops procedure and hd_aravr. (ShJ 5/88)
+
+int procedure hd_aravr (a, npix, mean, sigma, ksig)
+
+real a[ARB] # input data array
+real mean, sigma, ksig, deviation, lcut, hcut, lgpx
+int npix, niter, ngpix, old_ngpix, awvgr()
+
+begin
+ lcut = -MAX_REAL # no rejection to start
+ hcut = MAX_REAL
+ ngpix = 0
+ niter = 0
+
+ # Iteratively compute mean, sigma and reject outliers until no
+ # more pixels are rejected, or until there are no more pixels,
+ # or until the maximum iterations limit is exceeded.
+
+ repeat {
+ niter = niter + 1
+ old_ngpix = ngpix
+ ngpix = awvgr (a, npix, mean, sigma, lcut, hcut)
+ if (ngpix <= 1)
+ break
+
+ if (ksig == 0.0) { # Chauvenet's relation
+ lgpx = log10 (real(ngpix))
+ deviation = (lgpx * (-0.1042 * lgpx + 1.1695) + .8895) * sigma
+ } else
+ deviation = sigma * abs(ksig)
+
+ lcut = mean - deviation # compute window
+ hcut = mean + deviation
+
+ } until ((old_ngpix == ngpix) || (niter > MAX_ITERATIONS))
+
+ return (ngpix)
+end
diff --git a/noao/imred/dtoi/hdfit.par b/noao/imred/dtoi/hdfit.par
new file mode 100644
index 00000000..7f42aa2a
--- /dev/null
+++ b/noao/imred/dtoi/hdfit.par
@@ -0,0 +1,9 @@
+# Cl parameters for task hdfit are:
+database,f,a,,,,List of database names
+function,s,h,"power",,,Fitting function
+transform,s,h,"logopacitance",,,Independent variable transformation
+order,i,h,4,,,Initial order (ncoeff) of fit
+interactive,b,h,y,,,Interactive fitting flag
+device,s,h,"stdgraph",,,Name of interactive graphics device
+weighting,s,h,"none",,,Type of weighting
+cursor,*gcur,h,"",,,Source of cursor input
diff --git a/noao/imred/dtoi/hdfit.x b/noao/imred/dtoi/hdfit.x
new file mode 100644
index 00000000..04a82f6e
--- /dev/null
+++ b/noao/imred/dtoi/hdfit.x
@@ -0,0 +1,364 @@
+include <math/curfit.h>
+include <imhdr.h>
+include <fset.h>
+include <mach.h>
+include <ctype.h>
+include <error.h>
+include <pkg/gtools.h>
+include <pkg/xtanswer.h>
+include "hdicfit/hdicfit.h"
+
+# T_HDFIT -- Fit a curve. This task fits a characteristic
+# curve to density and log exposure data read from an input
+# database. The interactive curve fitting package is used.
+# The database is updated to contain the values of the fit
+# necessary to reinitialize the curfit package for performing
+# the transformation in hdtoi.
+
+procedure t_hdfit ()
+
+pointer sp, fcn, device, db, gt, exp, wts, save, trans, weight
+pointer dbfile, ic, den, errs
+int db_list, order, interactive, nsave, nvals, wt_type, update
+real ref_fog, real_fog
+double fog, maxden
+
+pointer ddb_map(), gt_init()
+bool clgetb(), fp_equalr(), fp_equald()
+int clpopni(), clgeti(), strncmp(), clgfil(), hd_fit()
+real ic_getr()
+
+begin
+ call smark (sp)
+ call salloc (fcn, SZ_FNAME, TY_CHAR)
+ call salloc (device, SZ_FNAME, TY_CHAR)
+ call salloc (trans, SZ_FNAME, TY_CHAR)
+ call salloc (weight, SZ_FNAME, TY_CHAR)
+ call salloc (dbfile, SZ_FNAME, TY_CHAR)
+
+ # Get cl parameters
+ db_list = clpopni ("database")
+ call clgstr ("function", Memc[fcn], SZ_FNAME)
+ call clgstr ("transform", Memc[trans], SZ_FNAME)
+ order = clgeti ("order")
+
+ # Decide which type of weighting the user wants
+ call clgstr ("weighting", Memc[weight], SZ_FNAME)
+ if (strncmp (Memc[weight], "none", 1) == 0)
+ wt_type = WT_NONE
+ else if (strncmp (Memc[weight], "user", 1) == 0)
+ wt_type = WT_USER
+ else if (strncmp (Memc[weight], "calc", 1) == 0)
+ wt_type = WT_CALC
+ else
+ call error (0, "Unrecognized weighting type")
+
+ # Initialize interactive curve fitting package.
+ gt = gt_init ()
+ call ic_open (ic)
+ call ic_pstr (ic, "function", Memc[fcn])
+ call ic_pstr (ic, "transform", Memc[trans])
+ call ic_puti (ic, "order", order)
+ call ic_pstr (ic, "ylabel", "Log Exposure")
+ call ic_pkey (ic, 5, 'y', 'u')
+
+ if (clgetb ("interactive")) {
+ interactive = YES
+ call clgstr ("device", Memc[device], SZ_FNAME)
+ } else {
+ interactive = NO
+ call strcpy ("", Memc[device], SZ_FNAME)
+ }
+
+ # Read information from each dlog file; accumulate number of values.
+ # The density (not fog subtracted) is returned. The density values
+ # are also sorted in increasing order.
+
+ call hd_rdloge (db_list, exp, den, wts, errs, nvals, fog, maxden,
+ wt_type)
+ if (nvals == 0)
+ call error (1, "T_HDFIT: No data values in sample")
+
+ call hd_sdloge (Memd[den], Memd[exp], Memd[wts], Memd[errs], nvals)
+ call ic_putr (ic, "fog", real(fog))
+ ref_fog = real (fog)
+ call ic_putr (ic, "rfog", ref_fog)
+
+ # Initialize the dtoi/icgfit interface.
+ if (fp_equald (maxden, 0.0D0))
+ call error (1, "Saturated pixel density not initialized")
+ call hdic_init (Memd[den], nvals, maxden)
+
+ update = hd_fit (ic, gt, Memd[den], Memd[exp], Memd[wts], Memd[errs],
+ nvals, save, nsave, Memc[device], interactive)
+
+ if (update == YES) {
+ # Record fit information in (each) database
+ call ic_gstr (ic, "function", Memc[fcn], SZ_FNAME)
+ call ic_gstr (ic, "transform", Memc[trans], SZ_FNAME)
+ real_fog = ic_getr (ic, "fog")
+
+ while (clgfil (db_list, Memc[dbfile], SZ_FNAME) != EOF) {
+ db = ddb_map (Memc[dbfile], APPEND)
+ call ddb_ptime (db)
+ # Add new fog record if it was changed interactively.
+ if (!fp_equalr (real_fog, ref_fog)) {
+ call ddb_prec (db, "fog")
+ call ddb_putr (db, "density", real_fog)
+ }
+
+ call ddb_prec (db, "cv")
+ call ddb_pad (db, "save", Memd[save], nsave)
+ call ddb_pstr (db, "function", Memc[fcn])
+ call ddb_pstr (db, "transformation", Memc[trans])
+
+ call ddb_unmap (db)
+ }
+ }
+
+ call ic_closed (ic)
+ call mfree (save, TY_DOUBLE)
+ call mfree (den, TY_DOUBLE)
+ call mfree (exp, TY_DOUBLE)
+ call mfree (wts , TY_DOUBLE)
+ call mfree (errs, TY_DOUBLE)
+
+ call gt_free (gt)
+ call clpcls (db_list)
+ call sfree (sp)
+end
+
+
+# HD_RLOGE -- Read log exposure, density and weights from a single dloge
+# database file. Pointers to the three arrays are returned as arguments.
+# The number of values accumulated is returned also; note that the value
+# of nvals is changed upon return; it should not be given as a constant.
+# If more than one database is being read (as in HDSHIFT applications),
+# the density ABOVE fog is returned, and the reference fog values set = 0.0
+# The maximum density, the density of a saturated pixel, is read from the
+# first databas and returned.
+
+procedure hd_rdloge (db_list, exp, den, wts, errs, nvals, fog, maxden, wt_type)
+
+int db_list # File descriptor for data base file
+pointer exp # Pointer to exposure array - returned
+pointer den # Pointer to density array - returned
+pointer wts # Pointer to weights array - returned
+pointer errs # Pointer to std deviation array - returned
+int nvals # Number of data pairs read - returned
+double fog # Value of fog read from database - returned
+double maxden # Maximum density, read from db - returned
+int wt_type # Type of weighting
+
+pointer db
+bool sdevrec
+int buflen, off, rec
+int nden, nexp, nwts, nspots, nerrs, nfiles
+char dloge[SZ_FNAME]
+
+pointer ddb_map()
+bool fp_equald()
+int ddb_locate(), ddb_geti(), clgfil(), imtlen()
+real ddb_getr()
+errchk ddb_locate, ddb_gad, malloc, ddb_map, ddb_unmap
+
+begin
+ nvals = 0
+ off = 0
+ buflen = NSPOTS
+ nfiles = imtlen (db_list)
+ maxden = 0.0D0
+
+ # Dynamically allocate memory for arrays; it can be increased later.
+ call malloc (exp, buflen, TY_DOUBLE)
+ call malloc (den, buflen, TY_DOUBLE)
+ call malloc (wts, buflen, TY_DOUBLE)
+ call malloc (errs, buflen, TY_DOUBLE)
+
+ while (clgfil (db_list, dloge, SZ_FNAME) != EOF) {
+ iferr (db = ddb_map (dloge, READ_ONLY)) {
+ call erract (EA_WARN)
+ next
+ }
+
+ # Get fog value to be subtracted from density
+ rec = ddb_locate (db, "fog")
+ fog = double (ddb_getr (db, rec, "density"))
+
+ # Get density array
+ rec = ddb_locate (db, "density")
+ nden = ddb_geti (db, rec, "den_val")
+
+ call ddb_gad (db, rec, "den_val", Memd[den+off], nden, nden)
+ if (nfiles > 1)
+ call asubkd (Memd[den+off], fog, Memd[den+off], nden)
+
+ # Get log exposure array
+ rec = ddb_locate (db, "exposure")
+ nexp = ddb_geti (db, rec, "log_exp")
+ call ddb_gad (db, rec, "log_exp", Memd[exp+off], nexp, nexp)
+
+ # Get saturated pixel density if not already set
+ if (fp_equald (maxden, 0.0D0)) {
+ iferr (rec = ddb_locate (db, "common")){
+ ;
+ } else
+ maxden = double (ddb_getr (db, rec, "maxden"))
+ }
+
+ # Get std deviation array
+ sdevrec = true
+ iferr {
+ rec = ddb_locate (db, "standard deviation")
+ nerrs = ddb_geti (db, rec, "sdev_val")
+ call ddb_gad (db, rec, "sdev_val", Memd[errs+off], nerrs, nerrs)
+ } then {
+ call erract (EA_WARN)
+ call eprintf ("Marker type '[ve]bar' can only show weights\n")
+ call amovkd (0.0D0, Memd[errs+off], nden)
+ sdevrec = FALSE
+ }
+
+ if (wt_type == WT_CALC) {
+ if (sdevrec) {
+ iferr {
+ nspots = min (nden, nexp, nerrs)
+ call adivd (Memd[den+off], Memd[errs+off],
+ Memd[wts+off], nspots)
+ } then {
+ call erract (EA_WARN)
+ call eprintf ("All weights set to 1.0\n")
+ call amovkd (double (1.0), Memd[wts+off], nspots)
+ }
+ } else {
+ nspots = min (nden, nexp)
+ call eprintf ("No sdev record; All weights set to 1.0\n")
+ call amovkd (double (1.0), Memd[wts+off], nspots)
+ }
+ }
+
+ if (wt_type == WT_USER) {
+ # WT_USER: fill "user" weights array
+ iferr {
+ rec = ddb_locate (db, "weight")
+ nwts = ddb_geti (db, rec, "wts_val")
+ nspots = min (nden, nexp, nwts)
+ call ddb_gad (db, rec, "wts_val", Memd[wts+off], nwts, nwts)
+ } then {
+ # Users weights can't be found. Set weights array to 1.0's.
+ call erract (EA_WARN)
+ call eprintf ("All weights set to 1.0\n")
+ nspots = min (nden, nexp)
+ call amovkd (double (1.0), Memd[wts+off], nspots)
+ }
+ }
+
+ if (wt_type == WT_NONE) {
+ # WT_NONE: fill "none" weights array
+ nspots = min (nden, nexp)
+ call amovkd (double (1.0), Memd[wts+off], nspots)
+ }
+
+ # Increment number of counts; reallocate memory if necessary.
+ nvals = nvals + nspots
+ off = off + nspots
+
+ if (nvals > buflen) {
+ buflen = buflen + NSPOTS
+ call realloc (exp, buflen, TY_DOUBLE)
+ call realloc (den, buflen, TY_DOUBLE)
+ call realloc (wts, buflen, TY_DOUBLE)
+ call realloc (errs, buflen, TY_DOUBLE)
+ }
+
+ call ddb_unmap (db)
+ }
+
+ if (nfiles > 1)
+ fog = 0.0D0
+ call clprew (db_list)
+end
+
+
+# HD_SLOGE -- Sort the log exposure, density and weight information in order
+# of increasing exposure value. The sorting is done is place. The three
+# data values are assummed matched on input, that is, exposure[i] matches
+# density[i] with weight[i] for all array entries.
+
+procedure hd_sdloge (density, exposure, weights, errors, nvals)
+
+double density[nvals] # Density array
+double exposure[nvals] # Exposure array
+double weights[nvals] # Weights array
+double errors[nvals] # Standard deviation array
+int nvals # Number of values in data arrays
+
+int i, j
+double temp
+define swap {temp=$1;$1=$2;$2=temp}
+
+begin
+ # Bubble sort - inefficient, but sorting is done only once on
+ # an expected small sample size (16 pts typically).
+
+ for (i = nvals; i > 1; i = i - 1)
+ for (j = 1; j < i; j = j + 1)
+ if (density [j] > density [j+1]) {
+
+ # Out of order; exchange values
+ swap (exposure[j], exposure[j+1])
+ swap ( density[j], density[j+1])
+ swap ( weights[j], weights[j+1])
+ swap ( errors[j], errors[j+1])
+ }
+end
+
+
+# HD_FIT -- Fit the curve to input density, exposure and weight values.
+# The fit can be performed interactively or not.
+
+int procedure hd_fit (ic,
+ gt, den, exp, wts, errs, nvals, save, nsave, dev, interact)
+
+pointer ic
+pointer gt # Graphics tools pointer
+double den[ARB] # Density values
+double exp[ARB] # Exposure values
+double wts[ARB] # Weight array
+double errs[ARB] # Standard deviation array
+int nvals # Number of data pairs to fit
+pointer save # ??
+int nsave # ??
+char dev[SZ_FNAME] # Interactive graphics device
+int interact # Flag for interactive graphics
+
+pointer gp, cv, sp, x, dum
+pointer gopen()
+int update, dcvstati()
+errchk malloc, gopen
+
+begin
+ if (interact == YES) {
+ gp = gopen (dev, NEW_FILE, STDGRAPH)
+ call icg_fitd (ic, gp, "cursor", gt, cv, den, exp, wts, errs, nvals)
+ call gclose (gp)
+ update = IC_UPDATE(ic)
+
+ } else {
+ # Do fit non-interactively
+ call smark (sp)
+ call salloc (x, nvals, TY_DOUBLE)
+ call salloc (dum, nvals, TY_INT)
+ call hdic_transform (ic, den, wts, Memd[x], wts, Memi[dum], nvals)
+ call ic_fitd (ic, cv, Memd[x], exp, wts, nvals, YES, YES, YES, YES)
+ call sfree (sp)
+ update = YES
+ }
+
+ nsave = (dcvstati (cv, CVORDER)) + 7
+ call malloc (save, nsave, TY_DOUBLE)
+ call dcvsave (cv, Memd[save])
+ call dcvfree (cv)
+
+ return (update)
+end
diff --git a/noao/imred/dtoi/hdicfit/hdic.com b/noao/imred/dtoi/hdicfit/hdic.com
new file mode 100644
index 00000000..959df10e
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/hdic.com
@@ -0,0 +1,6 @@
+# Common block for hdtoi package/ icgfit package interface.
+
+int nraw
+double maxden
+pointer den, big_den
+common /raw/maxden, den, big_den, nraw
diff --git a/noao/imred/dtoi/hdicfit/hdicadd.x b/noao/imred/dtoi/hdicfit/hdicadd.x
new file mode 100644
index 00000000..1fae152d
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/hdicadd.x
@@ -0,0 +1,47 @@
+include "hdicfit.h"
+
+# HDIC_ADDPOINT -- Add a density, exposure, weights point into the sample.
+
+procedure hdic_addpoint (ic,
+ nden, nexp, nwts, den, y, wts, userwts, x, wd, sdev, npts)
+
+pointer ic # Pointer to ic data structure
+real nden # New density value to be added
+real nexp # New exposure value to be added
+double nwts # New weight value to be added
+pointer den # Pointer to existing density array
+pointer y # Pointer to existing exposure array
+pointer wts # Pointer to existing wts array
+pointer userwts # Pointer to existing userwts array
+pointer x # Pointer to existing array of ind variables
+pointer wd # Pointer to flag array for deletion reasons
+pointer sdev # Pointer to standard deviation array
+int npts # Number of points, incremented on output
+
+begin
+ npts = npts + 1
+
+ call realloc (den, npts, TY_DOUBLE)
+ call realloc (y, npts, TY_DOUBLE)
+ call realloc (wts, npts, TY_DOUBLE)
+ call realloc (userwts, npts, TY_DOUBLE)
+ call realloc (x, npts, TY_DOUBLE)
+ call realloc (wd, npts, TY_INT)
+ call realloc (sdev, npts, TY_DOUBLE)
+
+ Memd[den+npts-1] = double (nden)
+ Memd[y +npts-1] = double (nexp)
+ Memd[wts+npts-1] = double (nwts)
+ Memd[userwts+npts-1] = double (nwts)
+ Memi[wd +npts-1] = NDELETE
+ Memd[sdev+npts-1] = ADDED_PT
+
+ # Sort the data and then update the reference vector.
+ call hdic_sort (Memd[den], Memd[y], Memd[wts], Memd[userwts],
+ Memi[wd], Memd[sdev], npts)
+ call hdic_init (Memd[den], npts, Memd[den+npts-1])
+
+ IC_NEWX(ic) = YES
+ IC_NEWY(ic) = YES
+ IC_NEWWTS(ic) = YES
+end
diff --git a/noao/imred/dtoi/hdicfit/hdicclean.x b/noao/imred/dtoi/hdicfit/hdicclean.x
new file mode 100644
index 00000000..6c838123
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/hdicclean.x
@@ -0,0 +1,94 @@
+include <pkg/rg.h>
+include "hdicfit.h"
+
+# IC_CLEAN -- Replace rejected points by the fitted values.
+
+procedure ic_cleand (ic, cv, x, y, w, npts)
+
+pointer ic # ICFIT pointer
+pointer cv # Curfit pointer
+double x[ARB] # Ordinates
+double y[ARB] # Abscissas
+double w[ARB] # Weights
+int npts # Number of points
+
+int i, nclean, newreject
+pointer sp, xclean, yclean, wclean
+double dcveval()
+
+begin
+ if ((IC_LOW(ic) == 0.) && (IC_HIGH(ic) == 0.))
+ return
+
+ # If there has been no subsampling and no sample averaging then the
+ # IC_REJPTS(ic) array already contains the rejected points.
+
+ if (npts == IC_NFIT(ic)) {
+ if (IC_NREJECT(ic) > 0) {
+ do i = 1, npts {
+ if (Memi[IC_REJPTS(ic)+i-1] == YES)
+ y[i] = dcveval (cv, x[i])
+ }
+ }
+
+ # If there has been no sample averaging then the rejpts array already
+ # contains indices into the subsampled array.
+
+ } else if (abs(IC_NAVERAGE(ic)) == 1) {
+ if (IC_NREJECT(ic) > 0) {
+ do i = 1, npts {
+ if (Memi[IC_REJPTS(ic)+i-1] == YES)
+ Memd[IC_YFIT(ic)+i-1] =
+ dcveval (cv, Memd[IC_XFIT(ic)+i-1])
+ }
+ }
+ call rg_unpackd (IC_RG(ic), Memd[IC_YFIT(ic)], y)
+
+ # Because ic_fit rejects points from the fitting data which
+ # has been sample averaged the rejpts array refers to the wrong data.
+ # Do the cleaning using ic_deviant to find the points to reject.
+
+ } else if (RG_NPTS(IC_RG(ic)) == npts) {
+ call amovki (NO, Memi[IC_REJPTS(ic)], npts)
+ call ic_deviantd (cv, x, y, w, Memi[IC_REJPTS(ic)], npts,
+ IC_LOW(ic), IC_HIGH(ic), IC_GROW(ic), NO, IC_NREJECT(ic),
+ newreject)
+ if (IC_NREJECT(ic) > 0) {
+ do i = 1, npts {
+ if (Memi[IC_REJPTS(ic)+i-1] == YES)
+ y[i] = dcveval (cv, x[i])
+ }
+ }
+
+ # If there is subsampling then allocate temporary arrays for the
+ # subsample points.
+
+ } else {
+ call smark (sp)
+
+ nclean = RG_NPTS(IC_RG(ic))
+ call salloc (xclean, nclean, TY_DOUBLE)
+ call salloc (yclean, nclean, TY_DOUBLE)
+ call salloc (wclean, nclean, TY_DOUBLE)
+
+ call rg_packd (IC_RG(ic), x, Memd[xclean])
+ call rg_packd (IC_RG(ic), y, Memd[yclean])
+ call rg_packd (IC_RG(ic), w, Memd[wclean])
+ call amovki (NO, Memi[IC_REJPTS(ic)], npts)
+
+ call ic_deviantd (cv, Memd[xclean], Memd[yclean],
+ Memd[wclean], Memi[IC_REJPTS(ic)], nclean, IC_LOW(ic),
+ IC_HIGH(ic), IC_GROW(ic), NO, IC_NREJECT(ic), newreject)
+
+ if (IC_NREJECT(ic) > 0) {
+ do i = 1, npts {
+ if (Memi[IC_REJPTS(ic)+i-1] == YES)
+ Memd[yclean+i-1] = dcveval (cv, Memd[xclean+i-1])
+ }
+ }
+ call rg_unpackd (IC_RG(ic), Memd[yclean], y)
+
+ call sfree (sp)
+ }
+end
+
diff --git a/noao/imred/dtoi/hdicfit/hdicdeviant.x b/noao/imred/dtoi/hdicfit/hdicdeviant.x
new file mode 100644
index 00000000..0c6f8f75
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/hdicdeviant.x
@@ -0,0 +1,116 @@
+include <mach.h>
+include <math/curfit.h>
+
+# IC_DEVIANT -- Find deviant points with large residuals from the fit
+# and reject from the fit.
+#
+# The sigma of the fit residuals is calculated. The rejection thresholds
+# are set at +-reject*sigma. Points outside the rejection threshold are
+# recorded in the reject array.
+
+procedure ic_deviantd (cv, x, y, w, rejpts, npts, low_reject, high_reject,
+ grow, refit, nreject, newreject)
+
+pointer cv # Curve descriptor
+double x[ARB] # Input ordinates
+double y[ARB] # Input data values
+double w[ARB] # Weights
+int rejpts[ARB] # Points rejected
+int npts # Number of input points
+real low_reject, high_reject # Rejection thresholds
+real grow # Rejection radius
+int refit # Refit the curve?
+int nreject # Number of points rejected
+int newreject # Number of new points rejected
+
+int i, j, i_min, i_max, ilast
+double sigma, low_cut, high_cut, residual
+pointer sp, residuals
+
+begin
+ # If low_reject and high_reject are zero then simply return.
+ if ((low_reject == 0.) && (high_reject == 0.))
+ return
+
+ # Allocate memory for the residuals.
+ call smark (sp)
+ call salloc (residuals, npts, TY_DOUBLE)
+
+ # Compute the residuals.
+ call dcvvector (cv, x, Memd[residuals], npts)
+ call asubd (y, Memd[residuals], Memd[residuals], npts)
+
+ # Compute the sigma of the residuals. If there are less than
+ # 5 points return.
+
+ j = 0
+ nreject = 0
+ sigma = 0.
+
+ do i = 1, npts {
+ if ((w[i] != 0.) && (rejpts[i] == NO)) {
+ sigma = sigma + Memd[residuals+i-1] ** 2
+ j = j + 1
+ } else if (rejpts[i] == YES)
+ nreject = nreject + 1
+ }
+
+ if (j < 5) {
+ call sfree (sp)
+ return
+ } else
+ sigma = sqrt (sigma / j)
+
+ if (low_reject > 0.)
+ low_cut = -low_reject * sigma
+ else
+ low_cut = -MAX_REAL
+ if (high_reject > 0.)
+ high_cut = high_reject * sigma
+ else
+ high_cut = MAX_REAL
+
+ # Reject the residuals exceeding the rejection limits.
+ # A for loop is used instead of do because with region growing we
+ # want to modify the loop index.
+
+ newreject = 0
+ for (i = 1; i <= npts; i = i + 1) {
+ if ((w[i] == 0.) || (rejpts[i] == YES))
+ next
+
+ residual = Memd[residuals + i - 1]
+ if ((residual > high_cut) || (residual < low_cut)) {
+ i_min = max (1, int (i - grow))
+ i_max = min (npts, int (i + grow))
+
+ # Reject points from the fit and flag them.
+ do j = i_min, i_max {
+ if ((abs (x[i] - x[j]) <= grow) && (w[j] != 0.) &&
+ (rejpts[j] == NO)) {
+ if (refit == YES)
+ call dcvrject (cv, x[j], y[j], w[j])
+ rejpts[j] = YES
+ newreject = newreject + 1
+ ilast = j
+ }
+ }
+ i = ilast
+ }
+ }
+
+ if ((refit == YES) && (newreject > 0)) {
+ call dcvsolve (cv, i)
+
+ switch (i) {
+ case SINGULAR:
+ call eprintf ("ic_reject: Singular solution\n")
+ case NO_DEG_FREEDOM:
+ call eprintf ("ic_reject: No degrees of freedom\n")
+ }
+ }
+
+ nreject = nreject + newreject
+
+ call sfree (sp)
+end
diff --git a/noao/imred/dtoi/hdicfit/hdicdosetup.x b/noao/imred/dtoi/hdicfit/hdicdosetup.x
new file mode 100644
index 00000000..c9e117ec
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/hdicdosetup.x
@@ -0,0 +1,104 @@
+include <math/curfit.h>
+include "hdicfit.h"
+
+# IC_DOSETUP -- Setup the fit. This is called at the start of each call
+# to ic_fit to update the fitting parameters if necessary.
+
+procedure ic_dosetupd (ic, cv, x, wts, npts, newx, newwts, newfunction, refit)
+
+pointer ic # ICFIT pointer
+pointer cv # Curfit pointer
+double x[ARB] # Ordinates of data
+double wts[ARB] # Weights
+int npts # Number of points in data
+int newx # New x points?
+int newwts # New weights?
+int newfunction # New function?
+int refit # Use cvrefit?
+
+int ord
+pointer rg_xrangesd()
+extern hd_powerd()
+errchk rg_xrangesd, malloc
+
+begin
+ # Set sample points.
+ if ((newx == YES) || (newwts == YES)) {
+ if (npts == 0)
+ call error (0, "No data points for fit")
+
+ call mfree (IC_XFIT(ic), TY_DOUBLE)
+ call mfree (IC_YFIT(ic), TY_DOUBLE)
+ call malloc (IC_XFIT(ic), npts, TY_DOUBLE)
+
+ call mfree (IC_WTSFIT(ic), TY_DOUBLE)
+ call malloc (IC_WTSFIT(ic), npts, TY_DOUBLE)
+
+ call mfree (IC_REJPTS(ic), TY_INT)
+ call malloc (IC_REJPTS(ic), npts, TY_INT)
+ call amovki (NO, Memi[IC_REJPTS(ic)], npts)
+ IC_NREJECT(ic) = 0
+
+ # Set sample points.
+
+ call rg_free (IC_RG(ic))
+ IC_RG(ic) = rg_xrangesd (Memc[IC_SAMPLE(ic)], x, npts)
+ call rg_order (IC_RG(ic))
+ call rg_merge (IC_RG(ic))
+ call rg_wtbind (IC_RG(ic), abs (IC_NAVERAGE(ic)), x, wts, npts,
+ Memd[IC_XFIT(ic)], Memd[IC_WTSFIT(ic)], IC_NFIT(ic))
+
+ if (IC_NFIT(ic) == 0)
+ call error (0, "No sample points for fit")
+
+ if (IC_NFIT(ic) == npts) {
+ call rg_free (IC_RG(ic))
+ call mfree (IC_XFIT(ic), TY_DOUBLE)
+ call mfree (IC_WTSFIT(ic), TY_DOUBLE)
+ IC_YFIT(ic) = NULL
+ IC_WTSFIT(ic) = NULL
+ } else
+ call malloc (IC_YFIT(ic), IC_NFIT(ic), TY_DOUBLE)
+
+ refit = NO
+ }
+
+ # Set curve fitting parameters.
+
+ if ((newx == YES) || (newfunction == YES)) {
+ if (cv != NULL)
+ call dcvfree (cv)
+
+ switch (IC_FUNCTION(ic)) {
+ case LEGENDRE, CHEBYSHEV:
+ ord = min (IC_ORDER(ic), IC_NFIT(ic))
+ call dcvinit (cv, IC_FUNCTION(ic), ord, double (IC_XMIN(ic)),
+ double (IC_XMAX(ic)))
+ case SPLINE1:
+ ord = min (IC_ORDER(ic), IC_NFIT(ic) - 1)
+ if (ord > 0)
+ call dcvinit (cv, SPLINE1, ord, double (IC_XMIN(ic)),
+ double (IC_XMAX(ic)))
+ else
+ call dcvinit (cv, LEGENDRE, IC_NFIT(ic),
+ double (IC_XMIN(ic)), double (IC_XMAX(ic)))
+ case SPLINE3:
+ ord = min (IC_ORDER(ic), IC_NFIT(ic) - 3)
+ if (ord > 0)
+ call dcvinit (cv, SPLINE3, ord, double (IC_XMIN(ic)),
+ double (IC_XMAX(ic)))
+ else
+ call dcvinit (cv, LEGENDRE, IC_NFIT(ic),
+ double (IC_XMIN(ic)), double (IC_XMAX(ic)))
+ case USERFNC:
+ ord = min (IC_ORDER(ic), IC_NFIT(ic))
+ call dcvinit (cv, USERFNC, ord, double (IC_XMIN(ic)),
+ double (IC_XMAX(ic)))
+ call dcvuserfnc (cv, hd_powerd)
+ default:
+ call error (0, "Unknown fitting function")
+ }
+
+ refit = NO
+ }
+end
diff --git a/noao/imred/dtoi/hdicfit/hdicebars.x b/noao/imred/dtoi/hdicfit/hdicebars.x
new file mode 100644
index 00000000..335c161d
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/hdicebars.x
@@ -0,0 +1,217 @@
+include <gset.h>
+include <mach.h>
+include <pkg/gtools.h>
+include "hdicfit.h"
+
+define MSIZE 2.0
+
+# HDIC_EBARS -- Plot data points with their error bars as markers. The
+# independent variable is fog subtracted transformed density.
+
+procedure hdic_ebars (ic, gp, gt, x, y, wts, ebw, npts)
+
+pointer ic # Pointer to ic structure
+pointer gp # Pointer to graphics stream
+pointer gt # Pointer to gtools structure
+double x[ARB] # Array of independent variables
+double y[ARB] # Array of dependent variables
+double wts[ARB] # Array of weights
+double ebw[ARB] # Error bar half width (positive number)
+int npts # Number of points
+
+pointer sp, xr, yr, sz
+int orig_mark, i, xaxis, yaxis, mark, added_mark
+real size, dx, dy, szmk
+int gt_geti()
+bool fp_equald()
+include "hdic.com"
+
+begin
+ call smark (sp)
+
+ xaxis = (IC_AXES (ic, IC_GKEY(ic), 1))
+ yaxis = (IC_AXES (ic, IC_GKEY(ic), 2))
+
+ if (xaxis == 'x' || xaxis == 'u')
+ orig_mark = GM_HEBAR
+ else if (yaxis == 'x' || yaxis == 'u')
+ orig_mark = GM_VEBAR
+ else {
+ call eprintf ("Choose graph type with axes 'u' or 'x'\n")
+ call sfree (sp)
+ return
+ }
+
+ added_mark = GM_CIRCLE
+
+ call salloc (xr, npts, TY_REAL)
+ call salloc (yr, npts, TY_REAL)
+ call salloc (sz, npts, TY_REAL)
+
+ call achtdr (x, Memr[xr], npts)
+ call achtdr (y, Memr[yr], npts)
+ call achtdr (ebw, Memr[sz], npts)
+
+ if (IC_OVERPLOT(ic) == NO) {
+ # Start a new plot
+ call gclear (gp)
+
+ # Set the graph scale and axes
+ call gascale (gp, Memr[xr], npts, 1)
+ call gascale (gp, Memr[yr], npts, 2)
+
+ # If plotting HD curve, set wy2 to maxden, which may have
+ # been updated if a new endpoint was added.
+
+ if ((IC_AXES (ic, IC_GKEY(ic), 1) == 'y') &&
+ (IC_AXES (ic, IC_GKEY(ic), 2) == 'u'))
+ call gswind (gp, INDEF, INDEF, INDEF, real (maxden))
+
+ call gt_swind (gp, gt)
+ call gt_labax (gp, gt)
+ }
+
+ call ggscale (gp, 0.0, 0.0, dx, dy)
+
+ do i = 1, npts {
+ size = Memr[sz+i-1] # Sizes are WCS units; transform them
+ if (gt_geti (gt, GTTRANSPOSE) == NO) {
+ size = size / dx
+ mark = orig_mark
+ szmk = size
+ # Check for added point
+ if (fp_equald (ebw[i], ADDED_PT)) {
+ szmk = MSIZE
+ mark = added_mark
+ }
+
+ # Check for deleted point
+ if (fp_equald (wts[i], 0.0D0)) {
+ szmk = MSIZE
+ mark = mark + GM_CROSS
+ }
+
+ call gmark (gp, Memr[xr+i-1], Memr[yr+i-1], mark, szmk, szmk)
+
+ } else {
+ size = size / dy
+ szmk = size
+ mark = orig_mark
+
+ # Check for added point
+ if (fp_equald (ebw[i], ADDED_PT)) {
+ szmk = MSIZE
+ mark = added_mark
+ }
+
+ # Check for deleted point
+ if (fp_equald (wts[i], 0.0D0)) {
+ szmk = MSIZE
+ mark = mark + GM_CROSS
+ }
+
+ call gmark (gp, Memr[yr+i-1], Memr[xr+i-1], mark, szmk, szmk)
+ }
+ }
+
+ IC_OVERPLOT(ic) = NO
+ call sfree (sp)
+end
+
+
+# HDIC_EBW -- Calculate error bar width for plotting points. Width is
+# returned in NDC units.
+
+procedure hdic_ebw (ic, density, indv, sdev, ebw, npts)
+
+pointer ic # Pointer to ic structure
+double density[ARB] # Untransformed density NOT fog subtracted
+double indv[ARB] # Transformed density above fog
+double sdev[ARB] # Array of standard deviation values, density units
+double ebw[ARB] # Error bar half width (positive numbers)
+int npts # Number of data points
+
+double fog
+pointer sp, denaf, outwe
+int xaxis, yaxis, i
+bool fp_equald()
+real ic_getr()
+
+begin
+ xaxis = (IC_AXES (ic, IC_GKEY(ic), 1))
+ yaxis = (IC_AXES (ic, IC_GKEY(ic), 2))
+
+ if (xaxis == 'u' || yaxis == 'u') {
+ call amovd (sdev, ebw, npts)
+ return
+ }
+
+ call smark (sp)
+ call salloc (denaf, npts, TY_DOUBLE)
+ call salloc (outwe, npts, TY_DOUBLE)
+
+ fog = double (ic_getr (ic, "fog"))
+
+ call asubkd (density, fog, Memd[denaf], npts)
+ call aaddd (Memd[denaf], sdev, Memd[denaf], npts)
+
+ call hdic_ebtran (Memd[denaf], Memd[outwe], npts, IC_TRANSFORM(ic))
+
+ # Subtract transformed values to get errors. Then check for
+ # added points, which are flagged with ebw=ADDED_PT.
+
+ call asubd (Memd[outwe], indv, ebw, npts)
+ do i = 1, npts {
+ if (fp_equald (sdev[i], ADDED_PT))
+ ebw[i] = ADDED_PT
+ }
+
+ call sfree (sp)
+end
+
+
+# HDIC_EBTRAN -- Apply transformation, generating a vector of independent
+# variables from a density vector. The independent variable vector is the
+# standard deviation values and the output values are the errors. This
+# routine checks for ADDED_PT valued standard deviation, which indicates an
+# added point.
+
+procedure hdic_ebtran (density, ind_var, npts, transform)
+
+double density[npts] # Density vector - input
+double ind_var[npts] # Ind variable vector - filled on output
+int npts # Length of data vectors
+int transform # Integer code for transform type
+
+int i
+bool fp_equald()
+
+begin
+ switch (transform) {
+ case HD_LOGO:
+ do i = 1, npts {
+ if (fp_equald (density[i], 0.0))
+ ind_var[i] = 0.0
+ else
+ ind_var[i] = log10 ((10. ** density[i]) - 1.0)
+ }
+ case HD_K75:
+ do i = 1, npts {
+ if (fp_equald (density[i], 0.0))
+ ind_var[i] = 0.0
+ else
+ ind_var[i] = density[i] + 0.75*log10(1.- 10.**(-density[i]))
+ }
+ case HD_K50:
+ do i = 1, npts {
+ if (fp_equald (density[i], 0.0))
+ ind_var[i] = 0.0
+ else
+ ind_var[i] = density[i] + 0.50*log10(1.- 10.**(-density[i]))
+ }
+ case HD_NONE:
+ call amovd (density, ind_var, npts)
+ default:
+ call error (0, "Unrecognized transformation in HDIC_EBTRAN")
+ }
+end
diff --git a/noao/imred/dtoi/hdicfit/hdicerrors.x b/noao/imred/dtoi/hdicfit/hdicerrors.x
new file mode 100644
index 00000000..7722e5e2
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/hdicerrors.x
@@ -0,0 +1,143 @@
+include <math/curfit.h>
+include "hdicfit.h"
+
+# IC_ERRORS -- Compute and error diagnositic information.
+
+procedure ic_errorsd (ic, file, cv, x, y, wts, npts)
+
+pointer ic # ICFIT pointer
+char file[ARB] # Output file
+pointer cv # Curfit pointer
+double x[ARB] # Ordinates
+double y[ARB] # Abscissas
+double wts[ARB] # Weights
+int npts # Number of data points
+
+int i, n, deleted, ncoeffs, fd
+double chisqr, rms
+pointer sp, fit, wts1, coeffs, errors
+
+int dcvstati(), open()
+double ic_rmsd()
+errchk open()
+
+begin
+ # Open the output file.
+ fd = open (file, APPEND, TEXT_FILE)
+
+ # Determine the number of coefficients and allocate memory.
+ ncoeffs = dcvstati (cv, CVNCOEFF)
+ call smark (sp)
+ call salloc (coeffs, ncoeffs, TY_DOUBLE)
+ call salloc (errors, ncoeffs, TY_DOUBLE)
+
+ if (npts == IC_NFIT(ic)) {
+ # Allocate memory for the fit.
+ n = npts
+ call salloc (fit, n, TY_DOUBLE)
+ call salloc (wts1, n, TY_DOUBLE)
+
+ # Eliminate rejected points and count deleted points.
+ call amovd (wts, Memd[wts1], n)
+ if (IC_NREJECT(ic) > 0) {
+ do i = 1, npts {
+ if (Memi[IC_REJPTS(ic)+i-1] == YES)
+ Memd[wts1+i-1] = 0.
+ }
+ }
+ deleted = 0
+ do i = 1, n {
+ if (wts[i] == 0.)
+ deleted = deleted + 1
+ }
+
+ # Get the coefficients and compute the errors.
+ call dcvvector (cv, x, Memd[fit], n)
+ call dcvcoeff (cv, Memd[coeffs], ncoeffs)
+ call dcverrors (cv, y, Memd[wts1], Memd[fit], n, chisqr,
+ Memd[errors])
+ rms = ic_rmsd (x, y, Memd[fit], Memd[wts1], n)
+
+ } else {
+ # Allocate memory for the fit.
+ n = IC_NFIT(ic)
+ call salloc (fit, n, TY_DOUBLE)
+ call salloc (wts1, n, TY_DOUBLE)
+
+ # Eliminate rejected points and count deleted points.
+ call amovd (Memd[IC_WTSFIT(ic)], Memd[wts1], n)
+ if (IC_NREJECT(ic) > 0) {
+ do i = 1, npts {
+ if (Memi[IC_REJPTS(ic)+i-1] == YES)
+ Memd[wts1+i-1] = 0.
+ }
+ }
+ deleted = 0
+ do i = 1, n {
+ if (wts[i] == 0.)
+ deleted = deleted + 1
+ }
+
+ # Get the coefficients and compute the errors.
+ call dcvvector (cv, Memd[IC_XFIT(ic)], Memd[fit], n)
+ rms = ic_rmsd (Memd[IC_XFIT(ic)], Memd[IC_YFIT(ic)],
+ Memd[fit], Memd[wts1], n)
+ call dcvcoeff (cv, Memd[coeffs], ncoeffs)
+ call dcverrors (cv, Memd[IC_YFIT(ic)], Memd[wts1], Memd[fit],
+ n, chisqr, Memd[errors])
+ }
+
+ # Print the error analysis.
+ call fprintf (fd, "total points = %d\nsample points = %d\n")
+ call pargi (npts)
+ call pargi (n)
+ call fprintf (fd, "nrejected = %d\ndeleted = %d\n")
+ call pargi (IC_NREJECT(ic))
+ call pargi (deleted)
+ call fprintf (fd, "RMS = %7.4g\n")
+ call pargd (rms)
+ call fprintf (fd, "square root of reduced chi square = %7.4g\n")
+ call pargd (sqrt (chisqr))
+
+ #call fprintf (fd, "\tcoefficent\terror\n")
+ #do i = 1, ncoeffs {
+ # call fprintf (fd, "\t%10.4e\t%10.4e\n")
+ # call parg$t (Mem$t[coeffs+i-1])
+ # call parg$t (Mem$t[errors+i-1])
+ #}
+
+ # Free allocated memory.
+ call sfree (sp)
+ call close (fd)
+end
+
+
+# IC_RMS -- Compute RMS of points which have not been deleted.
+
+double procedure ic_rmsd (x, y, fit, wts, npts)
+
+double x[ARB] # Ordinates
+double y[ARB] # Abscissas
+double fit[ARB] # Fit
+double wts[ARB] # Weights
+int npts # Number of data points
+
+int i, n
+double resid, rms
+
+begin
+ rms = 0.
+ n = 0
+ do i = 1, npts {
+ if (wts[i] == 0.)
+ next
+ resid = y[i] - fit[i]
+ rms = rms + resid * resid
+ n = n + 1
+ }
+
+ if (n > 0)
+ rms = sqrt (rms / n)
+
+ return (rms)
+end
diff --git a/noao/imred/dtoi/hdicfit/hdicfit.h b/noao/imred/dtoi/hdicfit/hdicfit.h
new file mode 100644
index 00000000..89d9c73d
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/hdicfit.h
@@ -0,0 +1,65 @@
+# Definition file for DTOI task hdfit which uses the hdicfit subdirectory.
+
+define NSPOTS 64 # Initially, max number of calibration spots
+define NVALS_FIT 200 # Number of points in vector of fitted points
+define WT_NONE 0 # No weighting used in fit
+define WT_USER 1 # User specifies weighting in fit
+define WT_CALC 2 # Weighting in fit calculated from std dev
+define MIN_DEN EPSILONR # Density used for setting curfit minval
+define HD_NONE 1 # Ind var is density - no transformation
+define HD_LOGO 2 # Ind var is log opacitance
+define HD_K50 3 # Ind var is Kaiser transform w/ alpha=0.50
+define HD_K75 4 # Ind var is Kaiser transform w/ alpha=0.75
+define UDELETE 100 # Point deleted by user flag
+define PDELETE 101 # Point deleted by program
+define NDELETE 102 # Point not deleted
+define ADDED_PT 0.0 # Indication of added point in sdev array
+
+# The ICFIT data structure - modified for use with the DTOI package.
+
+define IC_NGKEYS 5 # Number of graph keys
+define IC_LENSTRUCT 47 # Length of ICFIT structure
+
+# User fitting parameters
+define IC_FUNCTION Memi[$1] # Function type
+define IC_ORDER Memi[$1+1] # Order of function
+define IC_SAMPLE Memi[$1+2] # Pointer to sample string
+define IC_NAVERAGE Memi[$1+3] # Sampling averaging bin
+define IC_NITERATE Memi[$1+4] # Number of rejection interation
+define IC_TRANSFORM Memi[$1+5] # Type of transformation ** DTOI ONLY **
+define IC_XMIN Memr[P2R($1+6)] # Minimum value for curve
+define IC_XMAX Memr[P2R($1+7)] # Maximum value for curve
+define IC_LOW Memr[P2R($1+8)] # Low rejection value
+define IC_HIGH Memr[P2R($1+9)] # Low rejection value
+define IC_GROW Memr[P2R($1+10)]# Rejection growing radius
+
+# ICFIT parameters used for fitting
+define IC_NFIT Memi[$1+11] # Number of fit points
+define IC_NREJECT Memi[$1+12] # Number of rejected points
+define IC_RG Memi[$1+13] # Pointer for ranges
+define IC_XFIT Memi[$1+14] # Pointer to ordinates of fit points
+define IC_YFIT Memi[$1+15] # Pointer to abscissas of fit points
+define IC_WTSFIT Memi[$1+16] # Pointer to weights of fit points
+define IC_REJPTS Memi[$1+17] # Pointer to rejected points
+
+# ICFIT parameters used for interactive graphics
+define IC_NEWX Memi[$1+18] # New x fit points?
+define IC_NEWY Memi[$1+19] # New y points?
+define IC_NEWWTS Memi[$1+20] # New weights?
+define IC_NEWFUNCTION Memi[$1+21] # New fitting function?
+define IC_NEWTRANSFORM Memi[$1+22] # New transform? ** DTOI ONLY **
+define IC_OVERPLOT Memi[$1+23] # Overplot next plot?
+define IC_FITERROR Memi[$1+24] # Error in fit
+define IC_LABELS Memi[$1+25+$2-1]# Graph axis labels
+define IC_UNITS Memi[$1+27+$2-1]# Graph axis units
+
+define IC_FOG Memr[P2R($1+29)]# *** DTOI ONLY *** value of fog level
+define IC_NEWFOG Memi[$1+30] # Flag for change in fog
+define IC_RESET Memi[$1+31] # Flag for resetting variables
+define IC_UPDATE Memi[$1+32]
+define IC_EBARS Memi[$1+33] # Flag for plotting error bars
+define IC_RFOG Memr[P2R($1+34)]# Reference value of fog for resetting
+
+# ICFIT key definitions
+define IC_GKEY Memi[$1+35] # Graph key
+define IC_AXES Memi[$1+36+($2-1)*2+$3-1] # Graph axis codes
diff --git a/noao/imred/dtoi/hdicfit/hdicfit.x b/noao/imred/dtoi/hdicfit/hdicfit.x
new file mode 100644
index 00000000..91e05f9d
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/hdicfit.x
@@ -0,0 +1,80 @@
+include <math/curfit.h>
+include "hdicfit.h"
+
+# IC_FIT -- Fit a function. This is the main fitting task. It uses
+# flags to define changes since the last fit. This allows the most
+# efficient use of the curfit and ranges packages.
+
+procedure ic_fitd (ic, cv, x, y, wts, npts, newx, newy, newwts, newfunction)
+
+pointer ic # ICFIT pointer
+pointer cv # Curfit pointer
+double x[npts] # Ordinates
+double y[npts] # Data to be fit
+double wts[npts] # Weights
+int npts # Number of points
+int newx # New x points?
+int newy # New y points?
+int newwts # New weights?
+int newfunction # New function?
+
+int ier, refit
+errchk ic_dosetupd
+
+begin
+ # Setup the new parameters.
+ call ic_dosetupd (ic, cv, x, wts, npts, newx, newwts, newfunction,
+ refit)
+
+ if (npts == IC_NFIT(ic)) {
+ # If not sampling use the data array directly.
+ if (refit == NO) {
+ call dcvfit (cv, x, y, wts, npts, WTS_USER, ier)
+ } else if (newy == YES)
+ call dcvrefit (cv, x, y, wts, ier)
+
+ } else {
+ # If sampling first form the sample y values.
+ if ((newx == YES) || (newy == YES) || (newwts == YES))
+ call rg_wtbind (IC_RG(ic), IC_NAVERAGE(ic), y, wts, npts,
+ Memd[IC_YFIT(ic)], Memd[IC_WTSFIT(ic)], IC_NFIT(ic))
+ if (refit == NO) {
+ call dcvfit (cv, Memd[IC_XFIT(ic)], Memd[IC_YFIT(ic)],
+ Memd[IC_WTSFIT(ic)], IC_NFIT(ic), WTS_USER, ier)
+ } else if (newy == YES)
+ call dcvrefit (cv, Memd[IC_XFIT(ic)], Memd[IC_YFIT(ic)],
+ Memd[IC_WTSFIT(ic)], ier)
+ }
+
+ # Check for an error in the fit.
+ switch (ier) {
+ case SINGULAR:
+ call printf ("Singular solution")
+ call flush (STDOUT)
+ case NO_DEG_FREEDOM:
+ call printf ("No degrees of freedom")
+ call flush (STDOUT)
+ return
+ }
+
+ refit = YES
+
+ # Do pixel rejection if desired.
+ if ((IC_LOW(ic) > 0.) || (IC_HIGH(ic) > 0.)) {
+ if (npts == IC_NFIT(ic)) {
+ call ic_rejectd (cv, x, y, wts, Memi[IC_REJPTS(ic)],
+ IC_NFIT(ic), IC_LOW(ic), IC_HIGH(ic), IC_NITERATE(ic),
+ IC_GROW(ic), IC_NREJECT(ic))
+ } else {
+ call ic_rejectd (cv, Memd[IC_XFIT(ic)], Memd[IC_YFIT(ic)],
+ Memd[IC_WTSFIT(ic)], Memi[IC_REJPTS(ic)], IC_NFIT(ic),
+ IC_LOW(ic), IC_HIGH(ic), IC_NITERATE(ic), IC_GROW(ic),
+ IC_NREJECT(ic))
+ }
+
+ if (IC_NREJECT(ic) > 0)
+ refit = NO
+ } else
+ IC_NREJECT(ic) = 0
+end
+
diff --git a/noao/imred/dtoi/hdicfit/hdicgaxes.x b/noao/imred/dtoi/hdicfit/hdicgaxes.x
new file mode 100644
index 00000000..4f016c9d
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/hdicgaxes.x
@@ -0,0 +1,101 @@
+include <pkg/gtools.h>
+include "hdicfit.h"
+
+# ICG_AXES -- Set axes data.
+# The applications program may set additional axes types.
+
+procedure icg_axesd (ic, gt, cv, axis, x, y, z, npts)
+
+pointer ic # ICFIT pointer
+pointer gt # GTOOLS pointer
+pointer cv # CURFIT pointer
+int axis # Output axis
+double x[npts] # Independent variable
+double y[npts] # Dependent variable
+double z[npts] # Output values
+int npts # Number of points
+
+int i, axistype, gtlabel[2], gtunits[2]
+double a, b, xmin, xmax
+pointer label, units
+
+double dcveval(), icg_dvzd()
+errchk adivd()
+extern icg_dvzd()
+
+data gtlabel/GTXLABEL, GTYLABEL/
+data gtunits/GTXUNITS, GTYUNITS/
+
+begin
+ axistype = IC_AXES(ic, IC_GKEY(ic), axis)
+ switch (axistype) {
+ case 'x': # Independent variable
+ call gt_sets (gt, gtlabel[axis], Memc[IC_LABELS(ic,1)])
+ call gt_sets (gt, gtunits[axis], Memc[IC_UNITS(ic,1)])
+ call amovd (x, z, npts)
+ call gt_sets (gt, GTSUBTITLE, "")
+ case 'y': # Dependent variable
+ call gt_sets (gt, gtlabel[axis], Memc[IC_LABELS(ic,2)])
+ call gt_sets (gt, gtunits[axis], Memc[IC_UNITS(ic,2)])
+ call amovd (y, z, npts)
+ call gt_sets (gt, GTSUBTITLE, "")
+ case 'f': # Fitted values
+ call gt_sets (gt, gtlabel[axis], "fit")
+ call gt_sets (gt, gtunits[axis], Memc[IC_UNITS(ic,2)])
+ call dcvvector (cv, x, z, npts)
+ call gt_sets (gt, GTSUBTITLE, "")
+ case 'r': # Residuals
+ call gt_sets (gt, gtlabel[axis], "residuals")
+ call gt_sets (gt, gtunits[axis], Memc[IC_UNITS(ic,2)])
+ call dcvvector (cv, x, z, npts)
+ call asubd (y, z, z, npts)
+ call gt_sets (gt, GTSUBTITLE, "")
+ case 'd': # Ratio
+ call gt_sets (gt, gtlabel[axis], "ratio")
+ call gt_sets (gt, gtunits[axis], "")
+ call dcvvector (cv, x, z, npts)
+# iferr (call adiv$t (y, z, z, npts))
+ call advzd (y, z, z, npts, icg_dvzd)
+ call gt_sets (gt, GTSUBTITLE, "")
+ case 'n': # Linear component removed
+ call gt_sets (gt, gtlabel[axis], "non-linear component")
+ call gt_sets (gt, gtunits[axis], Memc[IC_UNITS(ic,2)])
+ xmin = IC_XMIN(ic)
+ xmax = IC_XMAX(ic)
+ a = dcveval (cv, double(xmin))
+ b = (dcveval (cv, double(xmax)) - a) / (xmax - xmin)
+ do i = 1, npts
+ z[i] = y[i] - a - b * (x[i] - xmin)
+ call gt_sets (gt, GTSUBTITLE, "")
+ default: # User axes types.
+ call malloc (label, SZ_LINE, TY_CHAR)
+ call malloc (units, SZ_LINE, TY_CHAR)
+ if (axis == 1) {
+ call strcpy (Memc[IC_LABELS(ic,1)], Memc[label], SZ_LINE)
+ call strcpy (Memc[IC_UNITS(ic,1)], Memc[units], SZ_LINE)
+ call amovd (x, z, npts)
+ } else {
+ call strcpy (Memc[IC_LABELS(ic,2)], Memc[label], SZ_LINE)
+ call strcpy (Memc[IC_UNITS(ic,2)], Memc[units], SZ_LINE)
+ call amovd (y, z, npts)
+ }
+ call icg_uaxesd (ic, axistype, cv, x, y, z, npts, Memc[label],
+ Memc[units], SZ_LINE)
+ call gt_sets (gt, gtlabel[axis], Memc[label])
+ call gt_sets (gt, gtunits[axis], Memc[units])
+ call gt_sets (gt, GTSUBTITLE, "HD Curve")
+ call mfree (label, TY_CHAR)
+ call mfree (units, TY_CHAR)
+ }
+end
+
+
+# ICG_DVZ -- Error action to take on zero division.
+
+double procedure icg_dvzd (x)
+
+double x # Numerator
+
+begin
+ return (1.)
+end
diff --git a/noao/imred/dtoi/hdicfit/hdicgcolon.x b/noao/imred/dtoi/hdicfit/hdicgcolon.x
new file mode 100644
index 00000000..52299df7
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/hdicgcolon.x
@@ -0,0 +1,284 @@
+include <error.h>
+include <gset.h>
+include "hdicfit.h"
+
+define EB_WTS 10
+define EB_SDEV 11
+
+# List of colon commands.
+define CMDS "|show|sample|naverage|function|order|low_reject|high_reject|\
+ |niterate|grow|errors|vshow|transform|fog|reset|quit|ebars|"
+
+define SHOW 1 # Show values of parameters
+define SAMPLE 2 # Set or show sample ranges
+define NAVERAGE 3 # Set or show sample averaging or medianing
+define FUNCTION 4 # Set or show function type
+define ORDER 5 # Set or show order
+define LOW_REJECT 6 # Set or show lower rejection factor
+define HIGH_REJECT 7 # Set or show upper rejection factor
+# newline 8
+define NITERATE 9 # Set or show rejection iterations
+define GROW 10 # Set or show rejection growing radius
+define ERRORS 11 # Show errors of fit
+define VSHOW 12 # Show verbose information
+define TRANSFORM 13 # Set or show transformation
+define FOG 14 # Set or show value of fog
+define RESET 15 # Reset x, y, wts, npts to original values
+define QUIT 16 # Terminate without updating database
+define EBARS 17 # Set error bars to represent weights or
+ # standard deviations
+
+# ICG_COLON -- Processes colon commands.
+
+procedure icg_colond (ic, cmdstr, gp, gt, cv, x, y, wts, npts)
+
+pointer ic # ICFIT pointer
+char cmdstr[ARB] # Command string
+pointer gp # GIO pointer
+pointer gt # GTOOLS pointer
+pointer cv # CURFIT pointer for error listing
+double x[npts], y[npts], wts[npts] # Data arrays for error listing
+int npts # Number of data points
+
+real rval
+char cmd[SZ_LINE]
+int ncmd, ival, ip, junk
+
+int nscan(), strdic(), strncmp(), ctor()
+string funcs "|chebyshev|legendre|spline1|spline3|power|"
+string tform "|none|logopacitance|k50|k75|"
+
+begin
+ # Use formated scan to parse the command string.
+ # The first word is the command and it may be minimum match
+ # abbreviated with the list of commands.
+
+ call sscan (cmdstr)
+ call gargwrd (cmd, SZ_LINE)
+ ncmd = strdic (cmd, cmd, SZ_LINE, CMDS)
+
+ switch (ncmd) {
+ case SHOW:
+ # show: Show the values of the fitting parameters. The terminal
+ # is cleared and paged using the gtools paging procedures.
+
+ call gargwrd (cmd, SZ_LINE)
+ if (nscan() == 1) {
+ call gdeactivate (gp, AW_CLEAR)
+ call ic_show (ic, "STDOUT", gt)
+ call greactivate (gp, AW_PAUSE)
+ } else {
+ iferr (call ic_show (ic, cmd, gt))
+ call erract (EA_WARN)
+ }
+
+ case SAMPLE:
+ # sample: List or set the sample points.
+
+ call gargwrd (cmd, SZ_LINE)
+ if (cmd[1] == EOS) {
+ call printf ("sample = %s\n")
+ call pargstr (Memc[IC_SAMPLE(ic)])
+ } else {
+ call strcpy (cmd, Memc[IC_SAMPLE(ic)], SZ_LINE)
+ IC_NEWX(ic) = YES
+ }
+
+ case NAVERAGE:
+ # naverage: List or set the sample averging.
+
+ call gargi (ival)
+ if (nscan() == 1) {
+ call printf ("naverage = %d\n")
+ call pargi (IC_NAVERAGE(ic))
+ } else {
+ IC_NAVERAGE(ic) = ival
+ IC_NEWX(ic) = YES
+ }
+
+ case FUNCTION:
+ # function: List or set the fitting function.
+
+ call gargwrd (cmd, SZ_LINE)
+ if (cmd[1] == EOS) {
+ call printf ("function = %s\n")
+ call ic_gstr (ic, "function", cmd, SZ_LINE)
+ call pargstr (cmd)
+ } else {
+ if (strdic (cmd, cmd, SZ_LINE, funcs) > 0) {
+ call ic_pstr (ic, "function", cmd)
+ IC_NEWFUNCTION(ic) = YES
+ } else
+ call printf ("Unknown or ambiguous function")
+ }
+
+ case ORDER:
+ # order: List or set the function order.
+
+ call gargi (ival)
+ if (nscan() == 1) {
+ call printf ("order = %d\n")
+ call pargi (IC_ORDER(ic))
+ } else {
+ IC_ORDER(ic) = ival
+ IC_NEWFUNCTION(ic) = YES
+ }
+
+ case LOW_REJECT:
+ # low_reject: List or set the lower rejection threshold.
+
+ call gargr (rval)
+ if (nscan() == 1) {
+ call printf ("low_reject = %g\n")
+ call pargr (IC_LOW(ic))
+ } else
+ IC_LOW(ic) = rval
+
+ case HIGH_REJECT:
+ # high_reject: List or set the high rejection threshold.
+
+ call gargr (rval)
+ if (nscan() == 1) {
+ call printf ("high_reject = %g\n")
+ call pargr (IC_HIGH(ic))
+ } else
+ IC_HIGH(ic) = rval
+
+ case NITERATE:
+ # niterate: List or set the number of rejection iterations.
+
+ call gargi (ival)
+ if (nscan() == 1) {
+ call printf ("niterate = %d\n")
+ call pargi (IC_NITERATE(ic))
+ } else
+ IC_NITERATE(ic) = ival
+
+ case GROW:
+ # grow: List or set the rejection growing.
+
+ call gargr (rval)
+ if (nscan() == 1) {
+ call printf ("grow = %g\n")
+ call pargr (IC_GROW(ic))
+ } else
+ IC_GROW(ic) = rval
+
+ case ERRORS:
+ call gargwrd (cmd, SZ_LINE)
+ if (nscan() == 1) {
+ call gdeactivate (gp, AW_CLEAR)
+ call ic_show (ic, "STDOUT", gt)
+ call ic_errorsd (ic, "STDOUT", cv, x, y, wts, npts)
+ call greactivate (gp, AW_PAUSE)
+ } else {
+ iferr {
+ call ic_show (ic, cmd, gt)
+ call ic_errorsd (ic, cmd, cv, x, y, wts, npts)
+ } then
+ call erract (EA_WARN)
+ }
+ case VSHOW:
+ # verbose show: Show the values of the fitting parameters.
+ # The terminal is paged using the gtools paging procedure.
+
+ call gargwrd (cmd, SZ_LINE)
+ if (cmd[1] == EOS) {
+ call gdeactivate (gp, AW_CLEAR)
+ call ic_vshowd (ic, "STDOUT", cv, x, y, wts, npts, gt)
+ call greactivate (gp, AW_PAUSE)
+ } else {
+ iferr {
+ call ic_vshowd (ic, cmd, cv, x, y, wts, npts, gt)
+ } then
+ call erract (EA_WARN)
+ }
+ case TRANSFORM:
+ # transform: List or set the transformation type. This
+ # option applies to HDTOI procedures only.
+
+ call gargwrd (cmd, SZ_LINE)
+ if (cmd[1] == EOS) {
+ call printf ("transform = %s\n")
+ call ic_gstr (ic, "transform", cmd, SZ_LINE)
+ call pargstr (cmd)
+ } else {
+ ival= strdic (cmd, cmd, SZ_LINE, tform)
+ if (ival > 0) {
+ call ic_pstr (ic, "transform", cmd)
+ IC_NEWTRANSFORM(ic) = YES
+ IC_NEWX(ic) = YES
+ switch (IC_TRANSFORM(ic)) {
+ case HD_NONE:
+ call ic_pstr (ic, "xlabel", "Density")
+ case HD_LOGO:
+ call ic_pstr (ic, "xlabel",
+ "Log Opacitance: log (10**Den - 1)")
+ case HD_K50:
+ call ic_pstr (ic, "xlabel",
+ "Den + 0.50 * Log (1 - (10 ** -Den))")
+ case HD_K75:
+ call ic_pstr (ic, "xlabel",
+ "Den + 0.75 * Log (1 - (10 ** -Den))")
+ }
+ } else
+ call printf ("Unknown or ambiguous transform")
+ }
+
+ case FOG:
+ # fog: DTOI ONLY - change or reset the value of the fog level
+
+ call gargwrd (cmd, SZ_LINE)
+ if (cmd[1] == EOS) {
+ call printf ("fog = %g\n")
+ call pargr (IC_FOG(ic))
+ } else {
+ if (strncmp (cmd, "reset", 1) == 0)
+ IC_FOG(ic) = IC_RFOG(ic)
+ else {
+ ip = 1
+ junk = ctor (cmd, ip, rval)
+ IC_FOG(ic) = rval
+ }
+ IC_NEWFOG(ic) = YES
+ IC_NEWX(ic) = YES
+ }
+
+ case RESET:
+ # Set flag to reset x, y, wts and npts to original values.
+ IC_RESET(ic) = YES
+ IC_NEWX(ic) = YES
+ IC_NEWY(ic) = YES
+ IC_NEWWTS(ic) = YES
+ IC_NEWFUNCTION(ic) = YES
+ IC_NEWTRANSFORM(ic) = YES
+
+ case QUIT:
+ # Set update flag to know
+ IC_UPDATE(ic) = NO
+
+ case EBARS:
+ # [HV]BAR marker can indicate either errors or weights
+ call gargwrd (cmd, SZ_LINE)
+ if (cmd[1] == EOS) {
+ if (IC_EBARS(ic) == EB_WTS)
+ call printf ("ebars = Weights\n")
+ else if (IC_EBARS(ic) == EB_SDEV)
+ call printf ("ebars = Errors\n")
+ } else {
+ if (strncmp (cmd, "weights", 1) == 0 ||
+ strncmp (cmd, "WEIGHTS", 1) == 0)
+ IC_EBARS(ic) = EB_WTS
+ else if (strncmp (cmd, "errors", 1) == 0 ||
+ strncmp (cmd, "ERRORS", 1) == 0)
+ IC_EBARS(ic) = EB_SDEV
+ else
+ call printf ("Unrecognized value for ebars '%s'\n")
+ call pargstr (cmd)
+ }
+
+ default:
+ call eprintf ("Unrecognized command '%s'\n")
+ call pargstr (cmd)
+ }
+end
diff --git a/noao/imred/dtoi/hdicfit/hdicgdelete.x b/noao/imred/dtoi/hdicfit/hdicgdelete.x
new file mode 100644
index 00000000..82c61f70
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/hdicgdelete.x
@@ -0,0 +1,81 @@
+include <gset.h>
+include <mach.h>
+include <pkg/gtools.h>
+include "hdicfit.h"
+
+define MSIZE 2. # Mark size
+
+# ICG_DELETE -- Delete data point nearest the cursor.
+# The nearest point to the cursor in NDC coordinates is determined.
+
+procedure icg_deleted (ic, gp, gt, cv, x, y, wts, npts, wx, wy)
+
+pointer ic # ICFIT pointer
+pointer gp # GIO pointer
+pointer gt # GTOOLS pointer
+pointer cv # CURFIT pointer
+double x[npts], y[npts] # Data points
+double wts[npts] # Weight array
+int npts # Number of points
+real wx, wy # Position to be nearest
+
+int gt_geti()
+pointer sp, xout, yout
+
+begin
+ call smark (sp)
+ call salloc (xout, npts, TY_DOUBLE)
+ call salloc (yout, npts, TY_DOUBLE)
+
+ call icg_axesd (ic, gt, cv, 1, x, y, Memd[xout], npts)
+ call icg_axesd (ic, gt, cv, 2, x, y, Memd[yout], npts)
+ if (gt_geti (gt, GTTRANSPOSE) == NO)
+ call icg_d1d (ic, gp, Memd[xout], Memd[yout], wts, npts, wx, wy)
+ else
+ call icg_d1d (ic, gp, Memd[yout], Memd[xout], wts, npts, wy, wx)
+
+ call sfree (sp)
+end
+
+
+# ICG_D1D - Do the actual delete.
+
+procedure icg_d1d (ic, gp, x, y, wts, npts, wx, wy)
+
+pointer ic # ICFIT pointer
+pointer gp # GIO pointer
+double x[npts], y[npts] # Data points
+double wts[npts] # Weight array
+int npts # Number of points
+real wx, wy # Position to be nearest
+
+int i, j
+real x0, y0, r2, r2min
+
+begin
+ # Transform world cursor coordinates to NDC.
+ call gctran (gp, wx, wy, wx, wy, 1, 0)
+
+ # Search for nearest point to a point with non-zero weight.
+ r2min = MAX_REAL
+ do i = 1, npts {
+ if (wts[i] == 0.)
+ next
+
+ call gctran (gp, real (x[i]), real (y[i]), x0, y0, 1, 0)
+
+ r2 = (x0 - wx) ** 2 + (y0 - wy) ** 2
+ if (r2 < r2min) {
+ r2min = r2
+ j = i
+ }
+ }
+
+ # Mark the deleted point with a cross and set the weight to zero.
+ if (j != 0) {
+ call gscur (gp, real (x[j]), real (y[j]))
+ call gmark (gp, real (x[j]), real (y[j]), GM_CROSS, MSIZE, MSIZE)
+ wts[j] = 0.
+ IC_NEWWTS(ic) = YES
+ }
+end
diff --git a/noao/imred/dtoi/hdicfit/hdicgfit.x b/noao/imred/dtoi/hdicfit/hdicgfit.x
new file mode 100644
index 00000000..b50ed03c
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/hdicgfit.x
@@ -0,0 +1,402 @@
+include <error.h>
+include <pkg/gtools.h>
+include <mach.h>
+include <gset.h>
+include "hdicfit.h"
+
+define HELP "noao$lib/scr/hdicgfit.key"
+define PROMPT "hdicfit options"
+define EB_WTS 10
+define EB_SDEV 11
+
+# ICG_FIT -- Interactive curve fitting with graphics. This is the main
+# entry point for the interactive graphics part of the icfit package.
+
+procedure icg_fitd (ic, gp, cursor, gt, cv, density, loge, owts, osdev, npts)
+
+pointer ic # ICFIT pointer
+pointer gp # GIO pointer
+char cursor[ARB] # GIO cursor input
+pointer gt # GTOOLS pointer
+pointer cv # CURFIT pointer
+double density[npts] # Original density, not fog subtracted
+double loge[npts] # Original log exposure values
+double owts[npts] # Original weights array
+double osdev[npts] # Original standard deviation array
+int npts # Number of points
+
+real wx, wy, wwy, oldx, oldy
+int wcs, key, nptso
+char cmd[SZ_LINE]
+
+int i, newgraph, axes[2], linetype
+double x1, newwt
+pointer userwts, x, y, wts, den, whydel, sdev, ebw
+
+int clgcur(), stridxs(), scan(), nscan()
+int icg_nearestd(), gstati()
+double dcveval()
+errchk ic_fitd, malloc
+define redraw_ 91
+
+begin
+ # Allocate memory for the fit and a copy of the weights.
+ # The weights are copied because they are changed when points are
+ # deleted. The input x is the untransformed density, and is used
+ # to generate other types of transforms. Points can be added to
+ # the sample, so the y array and weights array can change as well.
+ # The original number of points is also remembered.
+
+ call malloc (userwts, npts, TY_DOUBLE)
+ call malloc (x, npts, TY_DOUBLE)
+ call malloc (y, npts, TY_DOUBLE)
+ call malloc (wts, npts, TY_DOUBLE)
+ call malloc (den, npts, TY_DOUBLE)
+ call malloc (whydel, npts, TY_INT)
+ call malloc (sdev, npts, TY_DOUBLE)
+ call malloc (ebw, npts, TY_DOUBLE)
+
+ call amovd (owts, Memd[userwts], npts)
+ call amovd (owts, Memd[wts], npts)
+ call amovd (loge, Memd[y], npts)
+ call amovd (density, Memd[den], npts)
+ call amovki (NDELETE, Memi[whydel], npts)
+ call amovd (osdev, Memd[sdev], npts)
+ nptso = npts
+
+ # Initialize
+ IC_OVERPLOT(ic) = NO
+ IC_NEWX(ic) = YES
+ IC_NEWY(ic) = YES
+ IC_NEWWTS(ic) = YES
+ IC_NEWFUNCTION(ic) = YES
+ IC_NEWTRANSFORM(ic) = YES
+ IC_UPDATE(ic) = YES
+ IC_EBARS(ic) = EB_SDEV
+
+ # Read cursor commands.
+
+ key = 'f'
+ axes[1] = IC_AXES(ic, IC_GKEY(ic), 1)
+ axes[2] = IC_AXES(ic, IC_GKEY(ic), 2)
+
+ repeat {
+ switch (key) {
+ case '?': # Print help text.
+ call gpagefile (gp, HELP, PROMPT)
+
+ case 'q': # Terminate cursor loop
+ break
+
+ case ':': # List or set parameters
+ if (stridxs ("/", cmd) == 1)
+ call gt_colon (cmd, gp, gt, newgraph)
+ else
+ call icg_colond (ic, cmd, gp, gt, cv, Memd[x],
+ Memd[y], Memd[wts], npts)
+
+ if (IC_RESET(ic) == YES) {
+ npts = nptso
+ call amovd (owts, Memd[userwts], npts)
+ call amovd (owts, Memd[wts], npts)
+ call amovd (loge, Memd[y], npts)
+ call amovd (density, Memd[den], npts)
+ call amovki (NDELETE, Memi[whydel], npts)
+ call amovd (osdev, Memd[sdev], npts)
+ call hdic_init (density, npts, 0.0)
+ }
+
+ # See if user wants to quit without updating
+ if (IC_UPDATE(ic) == NO) {
+ call mfree (x, TY_DOUBLE)
+ call mfree (y, TY_DOUBLE)
+ call mfree (wts, TY_DOUBLE)
+ call mfree (userwts, TY_DOUBLE)
+ call mfree (den, TY_DOUBLE)
+ call mfree (sdev, TY_DOUBLE)
+ return
+ }
+
+ case 'a': # Add data points to the sample. This is only possible
+ # from an HD curve plot.
+
+ if ((IC_AXES (ic, IC_GKEY(ic), 1) == 'y') &&
+ (IC_AXES (ic, IC_GKEY(ic), 2) == 'u')) {
+
+ # Query for weight after plotting current location
+ # call gt_plot (gp, gt, wx, wy, 1)
+ call gmark (gp, wx, wy, GM_CIRCLE, 2.0, 2.0)
+ newwt = 1.0D0
+ call printf ("Enter weight of new point (%g): ")
+ call pargd (newwt)
+ call flush (STDOUT)
+ if (scan() != EOF) {
+ call pargd (x1)
+ if (nscan() == 1) {
+ if (!IS_INDEFD (x1)) {
+ newwt = x1
+ }
+ }
+ }
+
+ } else {
+ call eprintf ("Points can be added only from an HD Curve\n")
+ next
+ }
+
+ # Add fog into "density above fog" value read from cursor
+ wwy = wy + IC_FOG (ic)
+ if (wwy < 0.0) {
+ call eprintf (
+ "New density (%g) is below fog and will not be added\n")
+ call pargr (wwy)
+ next
+ }
+
+ # Add point into sample
+ call eprintf ("New Point: density above fog = %.4f, log ")
+ call pargr (wwy)
+ call eprintf ("exposure = %.4f, weight = %.4f\n")
+ call pargr (wx)
+ call pargd (newwt)
+
+ call hdic_addpoint (ic, wwy, wx, newwt, den, y, wts, userwts,
+ x, whydel, sdev, npts)
+
+ call realloc (ebw, npts, TY_DOUBLE)
+
+ call hdic_transform (ic, Memd[den], Memd[userwts], Memd[x],
+ Memd[wts], Memi[whydel], npts)
+
+ case 'c': # Print the positions of data points.
+ i = icg_nearestd (ic, gp, gt, cv, Memd[x], Memd[y], npts,
+ wx, wy)
+
+ if (i != 0) {
+ call printf ("den= %7.4g x= %7.4g exp= %7.4g fit= %7.4g")
+ call pargd (Memd[den+i-1])
+ call pargd (Memd[x+i-1])
+ call pargd (Memd[y+i-1])
+ call pargd (dcveval (cv, Memd[x+i-1]))
+ }
+
+ case 'd': # Delete data points.
+ call icg_deleted (ic, gp, gt, cv, Memd[x], Memd[y], Memd[wts],
+ npts, wx, wy)
+
+ case 'f': # Fit the function and reset the flags.
+ iferr {
+ # Copy new transformed vector, if necessary
+ if (IC_NEWTRANSFORM(ic) == YES || IC_NEWFOG(ic) == YES)
+ call hdic_transform (ic, Memd[den], Memd[userwts],
+ Memd[x], Memd[wts], Memi[whydel], npts)
+
+ call ic_fitd (ic, cv, Memd[x], Memd[y], Memd[wts], npts,
+ IC_NEWX(ic), IC_NEWY(ic), IC_NEWWTS(ic),
+ IC_NEWFUNCTION(ic))
+
+ IC_NEWX(ic) = NO
+ IC_NEWY(ic) = NO
+ IC_NEWWTS(ic) = NO
+ IC_NEWFUNCTION(ic) = NO
+ IC_NEWTRANSFORM(ic) = NO
+ IC_FITERROR(ic) = NO
+ IC_NEWFOG(ic) = NO
+ newgraph = YES
+ } then {
+ IC_FITERROR(ic) = YES
+ call erract (EA_WARN)
+ newgraph = NO
+ }
+
+ case 'g': # Set graph axes types.
+ call printf ("Graph key to be defined: ")
+ call flush (STDOUT)
+ if (scan() == EOF)
+ goto redraw_
+ call gargc (cmd[1])
+
+ switch (cmd[1]) {
+ case '\n':
+ case 'h', 'i', 'j', 'k', 'l':
+ switch (cmd[1]) {
+ case 'h':
+ key = 1
+ case 'i':
+ key = 2
+ case 'j':
+ key = 3
+ case 'k':
+ key = 4
+ case 'l':
+ key = 5
+ }
+
+ call printf ("Set graph axes types (%c, %c): ")
+ call pargc (IC_AXES(ic, key, 1))
+ call pargc (IC_AXES(ic, key, 2))
+ call flush (STDOUT)
+ if (scan() == EOF)
+ goto redraw_
+ call gargc (cmd[1])
+
+ switch (cmd[1]) {
+ case '\n':
+ default:
+ call gargc (cmd[2])
+ call gargc (cmd[2])
+ if (cmd[2] != '\n') {
+ IC_AXES(ic, key, 1) = cmd[1]
+ IC_AXES(ic, key, 2) = cmd[2]
+ }
+ }
+ default:
+ call printf ("Not a graph key")
+ }
+
+ case 'h':
+ if (IC_GKEY(ic) != 1) {
+ IC_GKEY(ic) = 1
+ newgraph = YES
+ }
+
+ case 'i':
+ if (IC_GKEY(ic) != 2) {
+ IC_GKEY(ic) = 2
+ newgraph = YES
+ }
+
+ case 'j':
+ if (IC_GKEY(ic) != 3) {
+ IC_GKEY(ic) = 3
+ newgraph = YES
+ }
+
+ case 'k':
+ if (IC_GKEY(ic) != 4) {
+ IC_GKEY(ic) = 4
+ newgraph = YES
+ }
+
+ case 'l':
+ if (IC_GKEY(ic) != 5) {
+ IC_GKEY(ic) = 5
+ newgraph = YES
+ }
+
+ case 'o': # Set overplot flag
+ IC_OVERPLOT(ic) = YES
+
+ case 'r': # Redraw the graph
+ newgraph = YES
+
+ case 'u': # Undelete data points.
+ call icg_undeleted (ic, gp, gt, cv, Memd[x], Memd[y],
+ Memd[wts], Memd[userwts], npts, wx, wy)
+
+ case 'w': # Window graph
+ call gt_window (gt, gp, cursor, newgraph)
+
+ case 'x': # Reset the value of the x point.
+ i = icg_nearestd (ic, gp, gt, cv, Memd[x], Memd[y], npts, wx,
+ wy)
+
+ if (i != 0) {
+ call printf ("Enter new x (%g): ")
+ call pargd (Memd[x+i-1])
+ call flush (STDOUT)
+ if (scan() != EOF) {
+ call gargd (x1)
+ if (nscan() == 1) {
+ if (!IS_INDEF (x1)) {
+ oldx = Memd[x+i-1]
+ oldy = Memd[y+i-1]
+ Memd[x+i-1] = x1
+ call hd_redraw (gp, oldx, oldy, x1, oldy)
+ IC_NEWX(ic) = YES
+ }
+ }
+ }
+ }
+
+ case 'y': # Reset the value of the y point.
+ i = icg_nearestd (ic, gp, gt, cv, Memd[x], Memd[y], npts, wx,
+ wy)
+
+ if (i != 0) {
+ call printf ("Enter new y (%g): ")
+ call pargd (Memd[y+i-1])
+ call flush (STDOUT)
+ if (scan() != EOF) {
+ call gargd (x1)
+ if (nscan() == 1) {
+ if (!IS_INDEF (x1)) {
+ oldx = Memd[x+i-1]
+ oldy = Memd[y+i-1]
+ Memd[y+i-1] = x1
+ call hd_redraw (gp, oldx, oldy, oldx, x1)
+ IC_NEWY(ic) = YES
+ }
+ }
+ }
+ }
+
+ case 'z': # Reset the weight value of the nearest point
+ i = icg_nearestd (ic, gp, gt, cv, Memd[x], Memd[y], npts, wx,
+ wy)
+
+ if (i != 0) {
+ call printf ("Enter new weight (%g): ")
+ call pargd (Memd[wts+i-1])
+ call flush (STDOUT)
+ if (scan() != EOF) {
+ call gargd (x1)
+ if (nscan() == 1) {
+ if (!IS_INDEF (x1)) {
+ Memd[wts+i-1] = x1
+ IC_NEWWTS(ic) = YES
+ }
+ }
+ }
+ }
+
+ default: # Let the user decide on any other keys.
+ call icg_user (ic, gp, gt, cv, wx, wy, wcs, key, cmd)
+ }
+
+ # Redraw the graph if necessary.
+redraw_ if (newgraph == YES) {
+ if (IC_AXES(ic, IC_GKEY(ic), 1) != axes[1]) {
+ axes[1] = IC_AXES(ic, IC_GKEY(ic), 1)
+ call gt_setr (gt, GTXMIN, INDEF)
+ call gt_setr (gt, GTXMAX, INDEF)
+ }
+ if (IC_AXES(ic, IC_GKEY(ic), 2) != axes[2]) {
+ axes[2] = IC_AXES(ic, IC_GKEY(ic), 2)
+ call gt_setr (gt, GTYMIN, INDEF)
+ call gt_setr (gt, GTYMAX, INDEF)
+ }
+
+ # Overplot with a different line type
+ if (IC_OVERPLOT(ic) == YES)
+ linetype = min ((gstati (gp, G_PLTYPE) + 1), 4)
+ else
+ linetype = GL_SOLID
+ call gseti (gp, G_PLTYPE, linetype)
+
+ call hdic_ebw (ic, Memd[den], Memd[x], Memd[sdev], Memd[ebw],
+ npts)
+
+ call icg_graphd (ic, gp, gt, cv, Memd[x], Memd[y], Memd[wts],
+ Memd[ebw], npts)
+
+ newgraph = NO
+ }
+ } until (clgcur (cursor, wx, wy, wcs, key, cmd, SZ_LINE) == EOF)
+
+ call mfree (x, TY_DOUBLE)
+ call mfree (y, TY_DOUBLE)
+ call mfree (wts, TY_DOUBLE)
+ call mfree (userwts, TY_DOUBLE)
+ call mfree (den, TY_DOUBLE)
+end
diff --git a/noao/imred/dtoi/hdicfit/hdicggraph.x b/noao/imred/dtoi/hdicfit/hdicggraph.x
new file mode 100644
index 00000000..dcd9ade3
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/hdicggraph.x
@@ -0,0 +1,329 @@
+include <mach.h>
+include <gset.h>
+include <pkg/gtools.h>
+include "hdicfit.h"
+
+define MSIZE 2. # Mark size
+define SZ_TPLOT 7 # String length for plot type
+define EB_WTS 10
+define EB_SDEV 11
+define MAX_SZMARKER 4
+
+# ICG_GRAPH -- Graph data and fit.
+
+procedure icg_graphd (ic, gp, gt, cv, x, y, wts, ebw, npts)
+
+pointer ic # ICFIT pointer
+pointer gp # GIO pointer
+pointer gt # GTOOLS pointers
+pointer cv # Curfit pointer
+double x[npts] # Independent variable
+double y[npts] # Dependent variable
+double wts[npts] # Weights
+double ebw[npts] # Half the error bar width
+int npts # Number of points
+
+pointer xout, yout
+int nvalues
+errchk malloc
+
+begin
+ call malloc (xout, npts, TY_DOUBLE)
+ call malloc (yout, npts, TY_DOUBLE)
+
+ call icg_axesd (ic, gt, cv, 1, x, y, Memd[xout], npts)
+ call icg_axesd (ic, gt, cv, 2, x, y, Memd[yout], npts)
+ call icg_paramsd (ic, cv, x, y, wts, npts, gt)
+
+ call icg_g1d (ic, gp, gt, Memd[xout], Memd[yout], wts, ebw, npts)
+
+ if (npts != IC_NFIT(ic)) {
+ if ((abs (IC_NAVERAGE(ic)) > 1) || (IC_NREJECT(ic) > 0)) {
+ call realloc (xout, IC_NFIT(ic), TY_DOUBLE)
+ call realloc (yout, IC_NFIT(ic), TY_DOUBLE)
+ call icg_axesd (ic, gt, cv, 1, Memd[IC_XFIT(ic)],
+ Memd[IC_YFIT(ic)], Memd[xout], IC_NFIT(ic))
+ call icg_axesd (ic, gt, cv, 2, Memd[IC_XFIT(ic)],
+ Memd[IC_YFIT(ic)], Memd[yout], IC_NFIT(ic))
+ call icg_g2d (ic, gp, gt, Memd[xout], Memd[yout],
+ IC_NFIT(ic))
+ }
+
+ } else if (IC_NREJECT(ic) > 0)
+ call icg_g2d (ic, gp, gt, Memd[xout], Memd[yout], npts)
+
+ nvalues = NVALS_FIT
+ call icg_gfd (ic, gp, gt, cv, nvalues)
+
+ # Mark the the sample regions.
+ call icg_sampled (ic, gp, gt, x, npts, 1)
+
+ call mfree (xout, TY_DOUBLE)
+ call mfree (yout, TY_DOUBLE)
+end
+
+
+# ICG_G1D -- Plot data vector.
+
+procedure icg_g1d (ic, gp, gt, x, y, wts, ebw, npts)
+
+pointer ic # Pointer to ic structure
+pointer gp # Pointer to graphics stream
+pointer gt # Pointer to gtools structure
+double x[npts] # Array of independent variables
+double y[npts] # Array of dependent variables
+double wts[npts] # Array of weights
+double ebw[npts] # Error bar half width in WCS (positive density)
+int npts # Number of points
+
+pointer sp, xr, yr, sz, szmk, gt1, gt2
+char tplot[SZ_TPLOT]
+int i, xaxis, yaxis, symbols[3], markplot
+real size, rmin, rmax, big
+bool fp_equald(), streq(), fp_equalr()
+int strncmp()
+data symbols/GM_PLUS, GM_BOX, GM_CIRCLE/
+include "hdic.com"
+
+begin
+ call smark (sp)
+ call salloc (xr, npts, TY_REAL)
+ call salloc (yr, npts, TY_REAL)
+ call salloc (sz, npts, TY_REAL)
+ call salloc (szmk, npts, TY_REAL)
+
+ call achtdr (x, Memr[xr], npts)
+ call achtdr (y, Memr[yr], npts)
+
+ xaxis = (IC_AXES (ic, IC_GKEY(ic), 1))
+ yaxis = (IC_AXES (ic, IC_GKEY(ic), 2))
+
+ # Set up gtools structure for deleted (gt1) and added (gt2) points
+ call gt_copy (gt, gt1)
+ call gt_setr (gt1, GTXSIZE, MSIZE)
+ call gt_setr (gt1, GTYSIZE, MSIZE)
+ call gt_sets (gt1, GTMARK, "cross")
+
+ call gt_copy (gt, gt2)
+ call gt_setr (gt2, GTXSIZE, MSIZE)
+ call gt_setr (gt2, GTYSIZE, MSIZE)
+ call gt_sets (gt2, GTMARK, "circle")
+
+ markplot = NO
+ call gt_gets (gt, GTTYPE, tplot, SZ_TPLOT)
+ if (strncmp (tplot, "mark", 4) == 0)
+ markplot = YES
+
+ if (IC_OVERPLOT(ic) == NO) {
+ # Start a new plot
+ call gclear (gp)
+
+ # Set the graph scale and axes
+ call gascale (gp, Memr[xr], npts, 1)
+ call gascale (gp, Memr[yr], npts, 2)
+
+ # If plotting HD curve, set wy2 to maxden, which may have
+ # been updated if a new endpoint was added.
+
+ if (xaxis == 'y' && yaxis == 'u')
+ call gswind (gp, INDEF, INDEF, INDEF, real (maxden))
+
+ call gt_swind (gp, gt)
+ call gt_labax (gp, gt)
+ }
+
+ # Calculate size of markers if error bars are being used. If the
+ # weights are being used as the marker size, they are first scaled
+ # between 1.0 and the maximum marker size.
+
+ call gt_gets (gt, GTMARK, tplot, SZ_TPLOT)
+ if (streq (tplot, "hebar") || streq (tplot, "vebar")) {
+ if (IC_EBARS(ic) == EB_WTS) {
+ call achtdr (wts, Memr[sz], npts)
+ call alimr (Memr[sz], npts, rmin, rmax)
+ if (fp_equalr (rmin, rmax))
+ call amovr (Memr[sz], Memr[szmk], npts)
+ else {
+ big = real (MAX_SZMARKER)
+ call amapr (Memr[sz], Memr[szmk], npts,rmin,rmax,1.0, big)
+ }
+ } else {
+ call achtdr (ebw, Memr[sz], npts)
+ call hd_szmk (gp, gt, xaxis, yaxis, tplot, Memr[sz],
+ Memr[szmk], npts)
+ }
+ } else
+ call amovkr (MSIZE, Memr[szmk], npts)
+
+ do i = 1, npts {
+ # Check for deleted point
+ if (fp_equald (wts[i], 0.0D0))
+ call gt_plot (gp, gt1, Memr[xr+i-1], Memr[yr+i-1], 1)
+
+ # Check for added point
+ else if (fp_equald (ebw[i], ADDED_PT))
+ call gt_plot (gp, gt2, Memr[xr+i-1], Memr[yr+i-1], 1)
+
+ else {
+ size = Memr[szmk+i-1]
+ call gt_setr (gt, GTXSIZE, size)
+ call gt_setr (gt, GTYSIZE, size)
+ call gt_plot (gp, gt, Memr[xr+i-1], Memr[yr+i-1], 1)
+ }
+ }
+
+ IC_OVERPLOT(ic) = NO
+ call sfree (sp)
+end
+
+
+# HD_SZMK -- Calculate size of error bar markers. This procedure is
+# called when the marker type is hebar or vebar and the marker size is
+# to be the error in the point, not its weight in the fit.
+
+procedure hd_szmk (gp, gt, xaxis, yaxis, mark, insz, outsz, npts)
+
+pointer gp # Pointer to gio structure
+pointer gt # Pointer to gtools structure
+int xaxis, yaxis # Codes for x and y axis types
+char mark[SZ_TPLOT] # Type of marker to use
+real insz[npts] # Standard deviations in WCS units
+real outsz[npts] # Output size array in NDC units
+int npts # Number of points in arrays
+
+int gt_geti()
+char tplot[SZ_TPLOT]
+real dx, dy
+bool streq()
+
+begin
+ # Check validity of axis types
+ if (xaxis != 'x' && xaxis != 'u' && yaxis != 'x' && yaxis != 'u') {
+ call eprintf ("Choose graph type with axes 'u' or 'x'; ")
+ call eprintf ("Using marker size 2.0\n")
+ call amovkr (MSIZE, outsz, npts)
+ return
+ }
+
+ call gt_gets (gt, GTMARK, tplot, SZ_TPLOT)
+ if (streq (tplot, "hebar")) {
+ if (yaxis == 'x' || yaxis == 'u') {
+ call gt_sets (gt, GTMARK, "vebar")
+ call eprintf ("Marker switched to vebar\n")
+ # call flush (STDOUT)
+ }
+ } else if (streq (tplot, "vebar")) {
+ if (xaxis == 'x' || xaxis == 'u') {
+ call gt_sets (gt, GTMARK, "hebar")
+ call eprintf ("Marker switched to hebar\n")
+ # call flush (STDOUT)
+ }
+ }
+
+ # Need to scale standard deviation from density to NDC units
+ call ggscale (gp, 0.0, 0.0, dx, dy)
+ if (gt_geti (gt, GTTRANSPOSE) == NO)
+ call adivkr (insz, dx, outsz, npts)
+ else
+ call adivkr (insz, dy, outsz, npts)
+end
+
+
+# ICG_G2D -- Show sample range and rejected data on plot.
+
+procedure icg_g2d (ic, gp, gt, x, y, npts)
+
+pointer ic # ICFIT pointer
+pointer gp # GIO pointer
+pointer gt # GTOOLS pointer
+double x[npts], y[npts] # Data points
+int npts # Number of data points
+
+int i
+pointer sp, xr, yr, gt1
+
+begin
+ call smark (sp)
+ call salloc (xr, npts, TY_REAL)
+ call salloc (yr, npts, TY_REAL)
+ call achtdr (x, Memr[xr], npts)
+ call achtdr (y, Memr[yr], npts)
+
+ call gt_copy (gt, gt1)
+ call gt_sets (gt1, GTTYPE, "mark")
+
+ # Mark the sample points.
+
+ if (abs (IC_NAVERAGE(ic)) > 1) {
+ call gt_sets (gt1, GTMARK, "plus")
+ call gt_setr (gt1, GTXSIZE, real (-abs (IC_NAVERAGE(ic))))
+ call gt_setr (gt1, GTYSIZE, 1.)
+ call gt_plot (gp, gt1, Memr[xr], Memr[yr], npts)
+ }
+
+ # Mark the rejected points.
+
+ if (IC_NREJECT(ic) > 0) {
+ call gt_sets (gt1, GTMARK, "diamond")
+ call gt_setr (gt1, GTXSIZE, MSIZE)
+ call gt_setr (gt1, GTYSIZE, MSIZE)
+ do i = 1, npts {
+ if (Memi[IC_REJPTS(ic)+i-1] == YES)
+ call gt_plot (gp, gt1, Memr[xr+i-1], Memr[yr+i-1], 1)
+ }
+ }
+
+ call gt_free (gt1)
+ call sfree (sp)
+end
+
+
+# ICG_GF[RD] -- Overplot the fit on a graph of the data points. A vector
+# is constructed and evaluated, then plotted.
+
+procedure icg_gfd (ic, gp, gt, cv, npts)
+
+pointer ic # ICFIT pointer
+pointer gp # GIO pointer
+pointer gt # GTOOL pointer
+pointer cv # CURFIT pointer
+int npts # Number of points to plot
+
+pointer sp, xr, yr, x, y, xo, yo, gt1
+int gstati()
+
+begin
+ call smark (sp)
+
+ if (IC_FITERROR(ic) == YES)
+ return
+
+ call salloc (xr, npts, TY_REAL)
+ call salloc (yr, npts, TY_REAL)
+ call salloc (x, npts, TY_DOUBLE)
+ call salloc (y, npts, TY_DOUBLE)
+ call salloc (xo, npts, TY_DOUBLE)
+ call salloc (yo, npts, TY_DOUBLE)
+
+ # Calculate big vector of independent variable values. Note value
+ # of npts can change with this call.
+ call hdic_gvec (ic, Memd[x], npts, IC_TRANSFORM(ic))
+
+ # Calculate vector of fit values.
+ call dcvvector (cv, Memd[x], Memd[y], npts)
+
+ # Convert to user function or transpose axes. Change type to reals
+ # for plotting.
+ call icg_axesd (ic, gt, cv, 1, Memd[x], Memd[y], Memd[xo], npts)
+ call icg_axesd (ic, gt, cv, 2, Memd[x], Memd[y], Memd[yo], npts)
+ call achtdr (Memd[xo], Memr[xr], npts)
+ call achtdr (Memd[yo], Memr[yr], npts)
+
+ call gt_copy (gt, gt1)
+ call gt_sets (gt1, GTTYPE, "line")
+ call gt_seti (gt1, GTLINE, gstati (gp, G_PLTYPE))
+ call gt_plot (gp, gt1, Memr[xr], Memr[yr], npts)
+ call gt_free (gt1)
+
+ call sfree (sp)
+end
diff --git a/noao/imred/dtoi/hdicfit/hdicgnearest.x b/noao/imred/dtoi/hdicfit/hdicgnearest.x
new file mode 100644
index 00000000..8d556273
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/hdicgnearest.x
@@ -0,0 +1,72 @@
+include <mach.h>
+include <pkg/gtools.h>
+
+# ICG_NEAREST -- Find the nearest point to the cursor and return the index.
+# The nearest point to the cursor in NDC coordinates is determined.
+# The cursor is moved to the nearest point selected.
+
+int procedure icg_nearestd (ic, gp, gt, cv, x, y, npts, wx, wy)
+
+pointer ic # ICFIT pointer
+pointer gp # GIO pointer
+pointer gt # GTOOLS pointer
+pointer cv # CURFIT pointer
+double x[npts], y[npts] # Data points
+int npts # Number of points
+real wx, wy # Cursor position
+
+int pt
+pointer sp, xout, yout
+int icg_nd(), gt_geti()
+
+begin
+ call smark (sp)
+ call salloc (xout, npts, TY_DOUBLE)
+ call salloc (yout, npts, TY_DOUBLE)
+
+ call icg_axesd (ic, gt, cv, 1, x, y, Memd[xout], npts)
+ call icg_axesd (ic, gt, cv, 2, x, y, Memd[yout], npts)
+
+ if (gt_geti (gt, GTTRANSPOSE) == NO)
+ pt = icg_nd (gp, Memd[xout], Memd[yout], npts, wx, wy)
+ else
+ pt = icg_nd (gp, Memd[yout], Memd[xout], npts, wy, wx)
+ call sfree (sp)
+
+ return (pt)
+end
+
+
+# ICG_ND -- ??
+
+int procedure icg_nd (gp, x, y, npts, wx, wy)
+
+pointer gp # GIO pointer
+double x[npts], y[npts] # Data points
+int npts # Number of points
+real wx, wy # Cursor position
+
+int i, j
+real x0, y0, r2, r2min
+
+begin
+ # Transform world cursor coordinates to NDC.
+ call gctran (gp, wx, wy, wx, wy, 1, 0)
+
+ # Search for nearest point.
+ r2min = MAX_REAL
+ do i = 1, npts {
+ call gctran (gp, real (x[i]), real (y[i]), x0, y0, 1, 0)
+ r2 = (x0 - wx) ** 2 + (y0 - wy) ** 2
+ if (r2 < r2min) {
+ r2min = r2
+ j = i
+ }
+ }
+
+ # Move the cursor to the selected point and return the index.
+ if (j != 0)
+ call gscur (gp, real (x[j]), real (y[j]))
+
+ return (j)
+end
diff --git a/noao/imred/dtoi/hdicfit/hdicgparams.x b/noao/imred/dtoi/hdicfit/hdicgparams.x
new file mode 100644
index 00000000..e502fba1
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/hdicgparams.x
@@ -0,0 +1,94 @@
+include <pkg/gtools.h>
+include "hdicfit.h"
+
+# ICG_PARAMS -- Set parameter string.
+
+procedure icg_paramsd (ic, cv, x, y, wts, npts, gt)
+
+pointer ic # ICFIT pointer
+pointer cv # Curfit pointer
+double x[ARB] # Ordinates
+double y[ARB] # Abscissas
+double wts[ARB] # Weights
+int npts # Number of data points
+pointer gt # GTOOLS pointer
+
+double rms
+int i, n, deleted
+pointer sp, fit, wts1, str, params
+double ic_rmsd()
+
+begin
+ call smark (sp)
+
+ if (npts == IC_NFIT(ic)) {
+ # Allocate memory for the fit.
+ n = npts
+ call salloc (fit, n, TY_DOUBLE)
+ call salloc (wts1, n, TY_DOUBLE)
+
+ # Eliminate rejected points and count deleted points.
+ call amovd (wts, Memd[wts1], n)
+ if (IC_NREJECT(ic) > 0) {
+ do i = 1, npts {
+ if (Memi[IC_REJPTS(ic)+i-1] == YES)
+ Memd[wts1+i-1] = 0.
+ }
+ }
+ deleted = 0
+ do i = 1, n {
+ if (wts[i] == 0.)
+ deleted = deleted + 1
+ }
+
+ # Set the fit and compute the RMS error.
+ call dcvvector (cv, x, Memd[fit], n)
+ rms = ic_rmsd (x, y, Memd[fit], Memd[wts1], n)
+
+ } else {
+ # Allocate memory for the fit.
+ n = IC_NFIT(ic)
+ call salloc (fit, n, TY_DOUBLE)
+ call salloc (wts1, n, TY_DOUBLE)
+
+ # Eliminate rejected points and count deleted points.
+ call amovd (Memd[IC_WTSFIT(ic)], Memd[wts1], n)
+ if (IC_NREJECT(ic) > 0) {
+ do i = 1, npts {
+ if (Memi[IC_REJPTS(ic)+i-1] == YES)
+ Memd[wts1+i-1] = 0.
+ }
+ }
+ deleted = 0
+ do i = 1, n {
+ if (wts[i] == 0.)
+ deleted = deleted + 1
+ }
+
+ # Set the fit and compute the rms error.
+ call dcvvector (cv, Memd[IC_XFIT(ic)], Memd[fit], n)
+ rms = ic_rmsd (Memd[IC_XFIT(ic)], Memd[IC_YFIT(ic)], Memd[fit],
+ Memd[wts1], n)
+ }
+
+ # Print the parameters and errors.
+ call salloc (str, SZ_LINE, TY_CHAR)
+ call salloc (params, 2*SZ_LINE, TY_CHAR)
+
+ call sprintf (Memc[str],SZ_LINE, "function=%s, order=%d, transform=%s")
+ call ic_gstr (ic, "function", Memc[params], 2*SZ_LINE)
+ call pargstr (Memc[params])
+ call pargi (IC_ORDER(ic))
+ call ic_gstr (ic, "transform", Memc[params], SZ_LINE)
+ call pargstr (Memc[params])
+ call sprintf (Memc[params], 2*SZ_LINE,
+ "%s\nfog=%.5f, total=%d, deleted=%d, RMS=%7.4g")
+ call pargstr (Memc[str])
+ call pargr (IC_FOG(ic))
+ call pargi (npts)
+ call pargi (deleted)
+ call pargd (rms)
+ call gt_sets (gt, GTPARAMS, Memc[params])
+
+ call sfree (sp)
+end
diff --git a/noao/imred/dtoi/hdicfit/hdicgredraw.x b/noao/imred/dtoi/hdicfit/hdicgredraw.x
new file mode 100644
index 00000000..d42a0740
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/hdicgredraw.x
@@ -0,0 +1,22 @@
+include <gset.h>
+
+define MSIZE 2.0
+
+# HD_REDRAW -- Redraw a data point. The old position marker is erased,
+# the new marker drawn, and the cursor moved to the new location.
+
+procedure hd_redraw (gp, oldx, oldy, newx, newy)
+
+pointer gp # Pointer to graphics stream
+real oldx # Old x coordinate
+real oldy # Old y coordinate
+real newx # New x coordinate
+real newy # New y coordinate
+
+begin
+ call gseti (gp, G_PMLTYPE, GL_CLEAR)
+ call gmark (gp, oldx, oldy, GM_PLUS, MSIZE, MSIZE)
+ call gseti (gp, G_PMLTYPE, GL_SOLID)
+ call gmark (gp, newx, newy, GM_PLUS, MSIZE, MSIZE)
+ call gscur (gp, newx, newy)
+end
diff --git a/noao/imred/dtoi/hdicfit/hdicgsample.x b/noao/imred/dtoi/hdicfit/hdicgsample.x
new file mode 100644
index 00000000..12eef158
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/hdicgsample.x
@@ -0,0 +1,84 @@
+include <gset.h>
+include <pkg/rg.h>
+include <pkg/gtools.h>
+include "hdicfit.h"
+
+# ICG_SAMPLE -- Mark sample.
+
+procedure icg_sampled (ic, gp, gt, x, npts, pltype)
+
+pointer ic # ICFIT pointer
+pointer gp # GIO pointer
+pointer gt # GTOOLS pointer
+double x[npts] # Ordinates of graph
+int npts # Number of data points
+int pltype # Plot line type
+
+pointer rg
+int i, axis, pltype1
+real xl, xr, yb, yt, dy
+real x1, x2, y1, y2, y3
+
+int gstati(), stridxs(), gt_geti()
+pointer rg_xrangesd()
+
+begin
+ if (stridxs ("*", Memc[IC_SAMPLE(ic)]) > 0)
+ return
+
+ # Find axis along which the independent data is plotted.
+ if (IC_AXES(ic,IC_GKEY(ic),1) == 'x')
+ axis = 1
+ else if (IC_AXES(ic,IC_GKEY(ic),2) == 'x')
+ axis = 2
+ else
+ return
+
+ if (gt_geti (gt, GTTRANSPOSE) == YES)
+ axis = mod (axis, 2) + 1
+
+ pltype1 = gstati (gp, G_PLTYPE)
+ call gseti (gp, G_PLTYPE, pltype)
+ rg = rg_xrangesd (Memc[IC_SAMPLE(ic)], x, npts)
+
+ switch (axis) {
+ case 1:
+ call ggwind (gp, xl, xr, yb, yt)
+
+ dy = yt - yb
+ y1 = yb + dy / 100
+ y2 = y1 + dy / 20
+ y3 = (y1 + y2) / 2
+
+ do i = 1, RG_NRGS(rg) {
+ x1 = x[RG_X1(rg, i)]
+ x2 = x[RG_X2(rg, i)]
+ if ((x1 > xl) && (x1 < xr))
+ call gline (gp, x1, y1, x1, y2)
+ if ((x2 > xl) && (x2 < xr))
+ call gline (gp, x2, y1, x2, y2)
+ call gline (gp, x1, y3, x2, y3)
+ }
+ case 2:
+ call ggwind (gp, yb, yt, xl, xr)
+
+ dy = yt - yb
+ y1 = yb + dy / 100
+ y2 = y1 + dy / 20
+ y3 = (y1 + y2) / 2
+
+ do i = 1, RG_NRGS(rg) {
+ x1 = x[RG_X1(rg, i)]
+ x2 = x[RG_X2(rg, i)]
+ if ((x1 > xl) && (x1 < xr))
+ call gline (gp, y1, x1, y2, x1)
+ if ((x2 > xl) && (x2 < xr))
+ call gline (gp, y1, x2, y2, x2)
+ call gline (gp, y3, x1, y3, x2)
+ }
+ }
+
+ call gseti (gp, G_PLTYPE, pltype1)
+ call rg_free (rg)
+end
+
diff --git a/noao/imred/dtoi/hdicfit/hdicguaxes.x b/noao/imred/dtoi/hdicfit/hdicguaxes.x
new file mode 100644
index 00000000..f8199c87
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/hdicguaxes.x
@@ -0,0 +1,38 @@
+include "hdicfit.h"
+
+# ICG_UAXIS -- Set user axis.
+
+procedure icg_uaxesd (ic, key, cv, x, y, z, npts, label, units, maxchars)
+
+pointer ic # Pointer to ic structure
+int key # Key for axes
+pointer cv # CURFIT pointer
+double x[npts] # Independent variable
+double y[npts] # Dependent variable
+double z[npts] # Output values
+int npts # Number of points
+char label[maxchars] # Axis label
+char units[maxchars] # Units for axis
+int maxchars # Maximum chars in label
+
+int offset
+double fog
+real ic_getr()
+include "hdic.com"
+
+begin
+ # Axis type 'u' returns the untransformed independent variable
+ # in the z array. That is, the original density values after
+ # subtracting the current fog value. Some density values could be
+ # below fog were excluded from the transformed vector.
+
+ call strcpy ("Density above fog", label, maxchars)
+ fog = double (ic_getr (ic, "fog"))
+
+ if (npts == nraw)
+ call asubkd (Memd[den], fog, z, npts)
+ else {
+ offset = big_den + (NVALS_FIT - npts)
+ call asubkd (Memd[offset], fog, z, npts)
+ }
+end
diff --git a/noao/imred/dtoi/hdicfit/hdicgundel.x b/noao/imred/dtoi/hdicfit/hdicgundel.x
new file mode 100644
index 00000000..9a7c68a4
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/hdicgundel.x
@@ -0,0 +1,87 @@
+include <gset.h>
+include <mach.h>
+include <pkg/gtools.h>
+include "hdicfit.h"
+
+define MSIZE 2. # Mark size
+
+# ICG_UNDELETE -- Undelete data point nearest the cursor.
+# The nearest point to the cursor in NDC coordinates is determined.
+
+procedure icg_undeleted (ic, gp, gt, cv, x, y, wts, userwts, npts, wx, wy)
+
+pointer ic # ICFIT pointer
+pointer gp # GIO pointer
+pointer gt # GTOOLS pointer
+pointer cv # CURFIT pointer
+double x[npts], y[npts] # Data points
+double wts[npts], userwts[npts] # Weight arrays
+int npts # Number of points
+real wx, wy # Position to be nearest
+
+pointer sp, xout, yout
+int gt_geti()
+
+begin
+ call smark (sp)
+ call salloc (xout, npts, TY_DOUBLE)
+ call salloc (yout, npts, TY_DOUBLE)
+
+ call icg_axesd (ic, gt, cv, 1, x, y, Memd[xout], npts)
+ call icg_axesd (ic, gt, cv, 2, x, y, Memd[yout], npts)
+ if (gt_geti (gt, GTTRANSPOSE) == NO) {
+ call icg_u1d (ic, gp, Memd[xout], Memd[yout], wts, userwts,
+ npts, wx, wy)
+ } else {
+ call icg_u1d (ic, gp, Memd[yout], Memd[xout], wts, userwts,
+ npts, wy, wx)
+ }
+
+ call sfree (sp)
+end
+
+
+# ICG_U1D -- Do the actual undelete.
+
+procedure icg_u1d (ic, gp, x, y, wts, userwts, npts, wx, wy)
+
+pointer ic # ICFIT pointer
+pointer gp # GIO pointer
+double x[npts], y[npts] # Data points
+double wts[npts], userwts[npts] # Weight arrays
+int npts # Number of points
+real wx, wy # Position to be nearest
+
+int i, j
+real x0, y0, r2, r2min
+
+begin
+ # Transform world cursor coordinates to NDC.
+ call gctran (gp, wx, wy, wx, wy, 1, 0)
+
+ # Search for nearest point to a point with zero weight.
+ r2min = MAX_REAL
+ do i = 1, npts {
+ if (wts[i] != 0.)
+ next
+
+ call gctran (gp, real (x[i]), real (y[i]), x0, y0, 1, 0)
+
+ r2 = (x0 - wx) ** 2 + (y0 - wy) ** 2
+ if (r2 < r2min) {
+ r2min = r2
+ j = i
+ }
+ }
+
+ # Unmark the deleted point and reset the weight.
+ if (j != 0) {
+ call gscur (gp, real (x[j]), real (y[j]))
+ call gseti (gp, G_PMLTYPE, GL_CLEAR)
+ call gmark (gp, real (x[j]), real (y[j]), GM_CROSS, MSIZE, MSIZE)
+ call gseti (gp, G_PMLTYPE, GL_SOLID)
+ call gmark (gp, real (x[j]), real (y[j]), GM_PLUS, MSIZE, MSIZE)
+ wts[j] = userwts[j]
+ IC_NEWWTS(ic) = YES
+ }
+end
diff --git a/noao/imred/dtoi/hdicfit/hdicguser.x b/noao/imred/dtoi/hdicfit/hdicguser.x
new file mode 100644
index 00000000..5e070537
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/hdicguser.x
@@ -0,0 +1,17 @@
+# ICG_USER -- User default action
+
+procedure icg_user (ic, gp, gt, cv, wx, wy, wcs, key, cmd)
+
+pointer ic # ICFIT pointer
+pointer gp # GIO pointer
+pointer gt # GTOOLS pointer
+pointer cv # CURFIT pointer
+real wx, wy # Cursor positions
+int wcs # GIO WCS
+int key # Cursor key
+char cmd[ARB] # Cursor command
+
+begin
+ # Ring bell
+ call printf ("\07")
+end
diff --git a/noao/imred/dtoi/hdicfit/hdicgvec.x b/noao/imred/dtoi/hdicfit/hdicgvec.x
new file mode 100644
index 00000000..81909cb8
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/hdicgvec.x
@@ -0,0 +1,74 @@
+include <mach.h>
+include "hdicfit.h"
+
+# HDIC_GVEC -- Get a vector of data to be plotted. The raw density
+# values are stored in common. From these values, all possible transforms
+# can be generated.
+
+procedure hdic_gvec (ic, xout, npts, transform)
+
+pointer ic # Pointer to ic structure
+double xout[npts] # Output vector
+int npts # Desired npoints to output - possibly changed on output
+int transform # Integer code for desired type of transform
+
+pointer sp, bigdenaf
+int i, j, npts_desired
+double fog, dval
+real ic_getr()
+include "hdic.com"
+
+begin
+ npts_desired = npts
+ if (npts_desired != NVALS_FIT)
+ call error (0, "hdicgvec: nvals != NVALS_FIT")
+
+ call smark (sp)
+ call salloc (bigdenaf, npts, TY_DOUBLE)
+
+ j = 1
+
+ fog = double (ic_getr (ic, "fog"))
+ call asubkd (Memd[big_den], fog, Memd[bigdenaf], npts)
+
+ switch (transform) {
+ case HD_NONE:
+ call amovd (Memd[bigdenaf], xout, NVALS_FIT)
+
+ case HD_LOGO:
+ do i = 1, npts_desired {
+ dval = Memd[bigdenaf+i-1]
+ if (dval < 0.0D0)
+ npts = npts - 1
+ else {
+ xout[j] = log10 ((10.**dval) - 1.0)
+ j = j + 1
+ }
+ }
+
+ case HD_K75:
+ do i = 1, npts_desired {
+ dval = Memd[bigdenaf+i-1]
+ if (dval < 0.0D0)
+ npts = npts - 1
+ else {
+ xout[j] = dval + 0.75 * log10 (1.0 - (10.** (-dval)))
+ j = j + 1
+ }
+ }
+
+ case HD_K50:
+ do i = 1, npts_desired {
+ dval = Memd[bigdenaf+i-1]
+ if (dval < 0.0D0)
+ npts = npts - 1
+ else {
+ xout[j] = dval + 0.50 * log10 (1.0 - (10.** (-dval)))
+ j = j + 1
+ }
+ }
+
+ }
+
+ call sfree (sp)
+end
diff --git a/noao/imred/dtoi/hdicfit/hdicinit.x b/noao/imred/dtoi/hdicfit/hdicinit.x
new file mode 100644
index 00000000..d9730051
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/hdicinit.x
@@ -0,0 +1,60 @@
+include <mach.h>
+include "hdicfit.h"
+
+# HDIC_INIT -- Initialize hdfit/icgfit interface.
+
+procedure hdic_init (density, nvalues, dmax)
+
+double density[nvalues] # Reference density above fog values
+int nvalues # Number of values in sample
+double dmax # Maximum possible density
+
+int i
+pointer sp, base
+double xxmax, xxmin, delta_den
+bool fp_equald()
+include "hdic.com"
+errchk malloc
+
+begin
+ call smark (sp)
+
+ if (den == NULL || big_den == NULL) {
+ call malloc (den, nvalues, TY_DOUBLE)
+ call malloc (big_den, NVALS_FIT, TY_DOUBLE)
+ } else if (nvalues != nraw)
+ call realloc (den, nvalues, TY_DOUBLE)
+
+ nraw = nvalues
+ call salloc (base, NVALS_FIT, TY_DOUBLE)
+
+ # Copy density array to pointer location
+ call amovd (density, Memd[den], nraw)
+
+ # Calculate big vector of density values. The points are spaced
+ # linear in log space, to yield adequate spacing at low density values.
+
+ call alimd (density, nraw, xxmin, xxmax)
+
+ # Put user value for maximum density in common block if it is valid.
+ if (! fp_equald (dmax, 0.0D0))
+ maxden = dmax
+
+ # Make big_den go all the way to maxden, not just xxmax. Make sure
+ # the value of xxmin won't cause the log function to blow up.
+
+ if (xxmin > 0.0D0)
+ ;
+ else
+ xxmin = 2.0 * EPSILOND
+
+ delta_den = (log10 (maxden) - log10 (xxmin)) / double (NVALS_FIT - 1)
+
+ do i = 1, NVALS_FIT
+ Memd[big_den+i-1] = log10 (xxmin) + double (i-1) * delta_den
+
+ call amovkd (10.0D0, Memd[base], NVALS_FIT)
+ call aexpd (Memd[base], Memd[big_den], Memd[big_den], NVALS_FIT)
+
+ call sfree (sp)
+end
diff --git a/noao/imred/dtoi/hdicfit/hdicparams.x b/noao/imred/dtoi/hdicfit/hdicparams.x
new file mode 100644
index 00000000..1840dccd
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/hdicparams.x
@@ -0,0 +1,323 @@
+include "hdicfit.h"
+
+define FUNCTIONS "|chebyshev|legendre|spline3|spline1|power|"
+define TRANSFORMS "|none|logopacitance|k50|k75|"
+
+# IC_OPEN -- Open ICFIT parameter structure.
+
+procedure ic_open (ic)
+
+pointer ic # ICFIT pointer
+errchk malloc
+
+begin
+ # Allocate memory for the package parameter structure.
+ call malloc (ic, IC_LENSTRUCT, TY_STRUCT)
+ call malloc (IC_SAMPLE(ic), SZ_LINE, TY_CHAR)
+ call malloc (IC_LABELS(ic,1), SZ_LINE, TY_CHAR)
+ call malloc (IC_LABELS(ic,2), SZ_LINE, TY_CHAR)
+ call malloc (IC_UNITS(ic,1), SZ_LINE, TY_CHAR)
+ call malloc (IC_UNITS(ic,2), SZ_LINE, TY_CHAR)
+
+ # Set defaults.
+ call ic_pstr (ic, "function", "spline3")
+ call ic_puti (ic, "order", 1)
+ call ic_pstr (ic, "sample", "*")
+ call ic_puti (ic, "naverage", 1)
+ call ic_puti (ic, "niterate", 0)
+ call ic_putr (ic, "low", 0.)
+ call ic_putr (ic, "high", 0.)
+ call ic_putr (ic, "grow", 0.)
+ call ic_pstr (ic, "xlabel", "X")
+ call ic_pstr (ic, "ylabel", "Y")
+ call ic_pstr (ic, "xunits", "")
+ call ic_pstr (ic, "yunits", "")
+ call ic_puti (ic, "key", 1)
+ call ic_pkey (ic, 1, 'x', 'y')
+ call ic_pkey (ic, 2, 'y', 'x')
+ call ic_pkey (ic, 3, 'x', 'r')
+ call ic_pkey (ic, 4, 'x', 'd')
+ call ic_pkey (ic, 5, 'x', 'n')
+
+ # Initialize other parameters
+ IC_RG(ic) = NULL
+ IC_XFIT(ic) = NULL
+ IC_YFIT(ic) = NULL
+ IC_WTSFIT(ic) = NULL
+ IC_REJPTS(ic) = NULL
+end
+
+
+# IC_CLOSER -- Close ICFIT parameter structure.
+
+procedure ic_closer (ic)
+
+pointer ic # ICFIT pointer
+
+begin
+ # Free memory for the package parameter structure.
+ call rg_free (IC_RG(ic))
+ call mfree (IC_XFIT(ic), TY_REAL)
+ call mfree (IC_YFIT(ic), TY_REAL)
+ call mfree (IC_WTSFIT(ic), TY_REAL)
+ call mfree (IC_REJPTS(ic), TY_INT)
+ call mfree (IC_SAMPLE(ic), TY_CHAR)
+ call mfree (IC_LABELS(ic,1), TY_CHAR)
+ call mfree (IC_LABELS(ic,2), TY_CHAR)
+ call mfree (IC_UNITS(ic,1), TY_CHAR)
+ call mfree (IC_UNITS(ic,2), TY_CHAR)
+ call mfree (ic, TY_STRUCT)
+end
+
+
+# IC_CLOSED -- Close ICFIT parameter structure.
+
+procedure ic_closed (ic)
+
+pointer ic # ICFIT pointer
+
+begin
+ # Free memory for the package parameter structure.
+ call rg_free (IC_RG(ic))
+ call mfree (IC_XFIT(ic), TY_DOUBLE)
+ call mfree (IC_YFIT(ic), TY_DOUBLE)
+ call mfree (IC_WTSFIT(ic), TY_DOUBLE)
+ call mfree (IC_REJPTS(ic), TY_INT)
+ call mfree (IC_SAMPLE(ic), TY_CHAR)
+ call mfree (IC_LABELS(ic,1), TY_CHAR)
+ call mfree (IC_LABELS(ic,2), TY_CHAR)
+ call mfree (IC_UNITS(ic,1), TY_CHAR)
+ call mfree (IC_UNITS(ic,2), TY_CHAR)
+ call mfree (ic, TY_STRUCT)
+end
+
+
+# IC_PSTR -- Put string valued parameters.
+
+procedure ic_pstr (ic, param, str)
+
+pointer ic # ICFIT pointer
+char param[ARB] # Parameter to be put
+char str[ARB] # String value
+
+int i
+pointer ptr
+int strdic()
+bool streq()
+
+begin
+ if (streq (param, "sample"))
+ call strcpy (str, Memc[IC_SAMPLE(ic)], SZ_LINE)
+ else if (streq (param, "function")) {
+ call malloc (ptr, SZ_LINE, TY_CHAR)
+ i = strdic (str, Memc[ptr], SZ_LINE, FUNCTIONS)
+ if (i > 0)
+ IC_FUNCTION(ic) = i
+ call mfree (ptr, TY_CHAR)
+ } else if (streq (param, "transform")) {
+ call malloc (ptr, SZ_LINE, TY_CHAR)
+ i = strdic (str, Memc[ptr], SZ_LINE, TRANSFORMS)
+ if (i > 0)
+ IC_TRANSFORM(ic) = i
+ call mfree (ptr, TY_CHAR)
+ } else if (streq (param, "xlabel"))
+ call strcpy (str, Memc[IC_LABELS(ic,1)], SZ_LINE)
+ else if (streq (param, "ylabel"))
+ call strcpy (str, Memc[IC_LABELS(ic,2)], SZ_LINE)
+ else if (streq (param, "xunits"))
+ call strcpy (str, Memc[IC_UNITS(ic,1)], SZ_LINE)
+ else if (streq (param, "yunits"))
+ call strcpy (str, Memc[IC_UNITS(ic,2)], SZ_LINE)
+ else
+ call error (0, "ICFIT: Unknown parameter")
+end
+
+
+# IC_PUTI -- Put integer valued parameters.
+
+procedure ic_puti (ic, param, ival)
+
+pointer ic # ICFIT pointer
+char param[ARB] # Parameter to be put
+int ival # Integer value
+
+bool streq()
+
+begin
+ if (streq (param, "naverage"))
+ IC_NAVERAGE(ic) = ival
+ else if (streq (param, "order"))
+ IC_ORDER(ic) = ival
+ else if (streq (param, "niterate"))
+ IC_NITERATE(ic) = ival
+ else if (streq (param, "key"))
+ IC_GKEY(ic) = ival
+ else if (streq (param, "transform"))
+ IC_TRANSFORM(ic) = ival
+ else
+ call error (0, "ICFIT: Unknown parameter")
+end
+
+
+# IC_PKEY -- Put key parameters.
+# Note the key types must be integers not characters.
+
+procedure ic_pkey (ic, key, xaxis, yaxis)
+
+pointer ic # ICFIT pointer
+int key # Key to be defined
+int xaxis # X axis type
+int yaxis # Y axis type
+
+begin
+ IC_AXES(ic, key, 1) = xaxis
+ IC_AXES(ic, key, 2) = yaxis
+end
+
+
+# IC_GKEY -- Get key parameters.
+
+procedure ic_gkey (ic, key, xaxis, yaxis)
+
+pointer ic # ICFIT pointer
+int key # Key to be gotten
+int xaxis # X axis type
+int yaxis # Y axis type
+
+begin
+ xaxis = IC_AXES(ic, key, 1)
+ yaxis = IC_AXES(ic, key, 2)
+end
+
+
+# IC_PUTR -- Put real valued parameters.
+
+procedure ic_putr (ic, param, rval)
+
+pointer ic # ICFIT pointer
+char param[ARB] # Parameter to be put
+real rval # Real value
+
+bool streq()
+
+begin
+ if (streq (param, "xmin"))
+ IC_XMIN(ic) = rval
+ else if (streq (param, "xmax"))
+ IC_XMAX(ic) = rval
+ else if (streq (param, "low"))
+ IC_LOW(ic) = rval
+ else if (streq (param, "high"))
+ IC_HIGH(ic) = rval
+ else if (streq (param, "grow"))
+ IC_GROW(ic) = rval
+ else if (streq (param, "fog"))
+ IC_FOG(ic) = rval
+ else if (streq (param, "rfog"))
+ IC_RFOG(ic) = rval
+ else
+ call error (0, "ICFIT: Unknown parameter")
+end
+
+
+# IC_GSTR -- Get string valued parameters.
+
+procedure ic_gstr (ic, param, str, maxchars)
+
+pointer ic # ICFIT pointer
+char param[ARB] # Parameter to be put
+char str[maxchars] # String value
+int maxchars # Maximum number of characters
+
+bool streq()
+
+begin
+ if (streq (param, "sample"))
+ call strcpy (Memc[IC_SAMPLE(ic)], str, maxchars)
+ else if (streq (param, "xlabel"))
+ call strcpy (Memc[IC_LABELS(ic,1)], str, maxchars)
+ else if (streq (param, "ylabel"))
+ call strcpy (Memc[IC_LABELS(ic,2)], str, maxchars)
+ else if (streq (param, "xunits"))
+ call strcpy (Memc[IC_UNITS(ic,1)], str, maxchars)
+ else if (streq (param, "yunits"))
+ call strcpy (Memc[IC_UNITS(ic,2)], str, maxchars)
+ else if (streq (param, "function")) {
+ switch (IC_FUNCTION(ic)) {
+ case 1:
+ call strcpy ("chebyshev", str, maxchars)
+ case 2:
+ call strcpy ("legendre", str, maxchars)
+ case 3:
+ call strcpy ("spline3", str, maxchars)
+ case 4:
+ call strcpy ("spline1", str, maxchars)
+ case 5:
+ call strcpy ("power", str, maxchars)
+ }
+ } else if (streq (param, "transform")) {
+ switch (IC_TRANSFORM(ic)) {
+ case 1:
+ call strcpy ("none", str, maxchars)
+ case 2:
+ call strcpy ("logopacitance", str, maxchars)
+ case 3:
+ call strcpy ("k50", str, maxchars)
+ case 4:
+ call strcpy ("k75", str, maxchars)
+ }
+ } else
+ call error (0, "ICFIT: Unknown parameter")
+end
+
+
+# IC_GETI -- Get integer valued parameters.
+
+int procedure ic_geti (ic, param)
+
+pointer ic # ICFIT pointer
+char param[ARB] # Parameter to be gotten
+
+bool streq()
+
+begin
+ if (streq (param, "naverage"))
+ return (IC_NAVERAGE(ic))
+ else if (streq (param, "order"))
+ return (IC_ORDER(ic))
+ else if (streq (param, "niterate"))
+ return (IC_NITERATE(ic))
+ else if (streq (param, "key"))
+ return (IC_GKEY(ic))
+ else if (streq (param, "transform"))
+ return (IC_TRANSFORM(ic))
+
+ call error (0, "ICFIT: Unknown parameter")
+end
+
+
+# IC_GETR -- Get real valued parameters.
+
+real procedure ic_getr (ic, param)
+
+pointer ic # ICFIT pointer
+char param[ARB] # Parameter to be put
+
+bool streq()
+
+begin
+ if (streq (param, "xmin"))
+ return (IC_XMIN(ic))
+ else if (streq (param, "xmax"))
+ return (IC_XMAX(ic))
+ else if (streq (param, "low"))
+ return (IC_LOW(ic))
+ else if (streq (param, "high"))
+ return (IC_HIGH(ic))
+ else if (streq (param, "grow"))
+ return (IC_GROW(ic))
+ else if (streq (param, "fog"))
+ return (IC_FOG(ic))
+
+ call error (0, "ICFIT: Unknown parameter")
+end
diff --git a/noao/imred/dtoi/hdicfit/hdicreject.x b/noao/imred/dtoi/hdicfit/hdicreject.x
new file mode 100644
index 00000000..82dd093c
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/hdicreject.x
@@ -0,0 +1,39 @@
+# IC_REJECT -- Reject points with large residuals from the fit.
+#
+# The sigma of the fit residuals is calculated. The rejection thresholds
+# are set at low_reject*sigma and high_reject*sigma. Points outside the
+# rejection threshold are rejected from the fit and flagged in the rejpts
+# array. Finally, the remaining points are refit.
+
+procedure ic_rejectd (cv, x, y, w, rejpts, npts, low_reject, high_reject,
+ niterate, grow, nreject)
+
+pointer cv # Curve descriptor
+double x[npts] # Input ordinates
+double y[npts] # Input data values
+double w[npts] # Weights
+int rejpts[npts] # Points rejected
+int npts # Number of input points
+real low_reject, high_reject # Rejection threshold
+int niterate # Number of rejection iterations
+real grow # Rejection radius
+int nreject # Number of points rejected
+
+int i, newreject
+
+begin
+ # Initialize rejection.
+ nreject = 0
+ call amovki (NO, rejpts, npts)
+
+ if (niterate <= 0)
+ return
+
+ # Find deviant points.
+ do i = 1, niterate {
+ call ic_deviantd (cv, x, y, w, rejpts, npts, low_reject,
+ high_reject, grow, YES, nreject, newreject)
+ if (newreject == 0)
+ break
+ }
+end
diff --git a/noao/imred/dtoi/hdicfit/hdicshow.x b/noao/imred/dtoi/hdicfit/hdicshow.x
new file mode 100644
index 00000000..521f04d3
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/hdicshow.x
@@ -0,0 +1,52 @@
+include <pkg/gtools.h>
+include "hdicfit.h"
+
+# IC_SHOW -- Show the values of the parameters.
+
+procedure ic_show (ic, file, gt)
+
+pointer ic # ICFIT pointer
+char file[ARB] # Output file
+pointer gt # GTOOLS pointer
+
+int fd
+pointer str
+int open()
+long clktime()
+errchk open, malloc
+
+begin
+ fd = open (file, APPEND, TEXT_FILE)
+ call malloc (str, SZ_LINE, TY_CHAR)
+
+ call cnvtime (clktime(0), Memc[str], SZ_LINE)
+ call fprintf (fd, "\n# %s\n")
+ call pargstr (Memc[str])
+
+ call gt_gets (gt, GTTITLE, Memc[str], SZ_LINE)
+ call fprintf (fd, "# %s\n")
+ call pargstr (Memc[str])
+
+ call gt_gets (gt, GTYUNITS, Memc[str], SZ_LINE)
+ if (Memc[str] != EOS) {
+ call fprintf (fd, "fit units = %s\n")
+ call pargstr (Memc[str])
+ }
+
+ call ic_gstr (ic, "function", Memc[str], SZ_LINE)
+ call fprintf (fd, "function = %s\n")
+ call pargstr (Memc[str])
+
+ call fprintf (fd, "order = %d\n")
+ call pargi (IC_ORDER(ic))
+
+ call ic_gstr (ic, "transform", Memc[str], SZ_LINE)
+ call fprintf (fd, "transform = %s\n")
+ call pargstr (Memc[str])
+
+ call fprintf (fd, "fog = %g\n")
+ call pargr (IC_FOG(ic))
+
+ call mfree (str, TY_CHAR)
+ call close (fd)
+end
diff --git a/noao/imred/dtoi/hdicfit/hdicsort.x b/noao/imred/dtoi/hdicfit/hdicsort.x
new file mode 100644
index 00000000..16d6e0a6
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/hdicsort.x
@@ -0,0 +1,38 @@
+# HDIC_SORT -- sort the log exposure, density and weight information in order
+# of increasing density value. The sorting is done is place. The four
+# data values are assummed matched on input, that is, exposure[i] matches
+# density[i] with weight[i] (and userwts[i]) for all array entries.
+
+procedure hdic_sort (density, exposure, weights, userwts, whydel, sdev, nvals)
+
+double density[nvals] # Density array
+double exposure[nvals] # Log exposure array
+double weights[nvals] # Weights array
+double userwts[nvals] # Reference weights array
+int whydel[nvals] # Flag array of reasons for deletion
+double sdev[nvals] # Array of standard deviations
+int nvals # Number of values to sort
+
+int i, j
+double temp
+define swap {temp=$1;$1=$2;$2=temp}
+int itemp
+define iswap {itemp=$1;$1=$2;$2=itemp}
+
+begin
+ # Bubble sort - inefficient, but sorting is done infrequently
+ # an expected small sample size (16 pts typically).
+
+ for (i = nvals; i > 1; i = i - 1)
+ for (j = 1; j < i; j = j + 1)
+ if (density [j] > density[j+1]) {
+
+ # Out of order; exchange values
+ swap (exposure[j], exposure[j+1])
+ swap ( density[j], density[j+1])
+ swap ( weights[j], weights[j+1])
+ swap ( userwts[j], userwts[j+1])
+ iswap ( whydel[j], whydel[j+1])
+ swap ( sdev[j], sdev[j+1])
+ }
+end
diff --git a/noao/imred/dtoi/hdicfit/hdictrans.x b/noao/imred/dtoi/hdicfit/hdictrans.x
new file mode 100644
index 00000000..0ee89037
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/hdictrans.x
@@ -0,0 +1,155 @@
+include <mach.h>
+include "hdicfit.h"
+
+# HDIC_TRANSFORM -- Transform density to independent variable of fit. The
+# desired transform is stored in the ic structure. A vector of x values
+# is returned, as is a possibly modified weights array. The minimum and
+# maximum limits of the fit are updated in the ic structure; the labels
+# are set also when IC_NEWTRANSFORM = YES. The fog value is subtracted
+# from the input density array and the transform performed.
+
+procedure hdic_transform (ic, density, userwts, xout, wts, whydel, npts)
+
+pointer ic # Pointer to ic structure
+double density[npts] # Array of original density values
+double userwts[npts] # Array of original weights values
+double xout[npts] # Transformed density above fog (returned)
+double wts[npts] # Input weights array
+int whydel[npts] # Reason for deletion array
+int npts # The number of density points - maybe changed on output
+
+int i
+pointer denaf, sp
+double fog, xxmin, xxmax, dval
+bool fp_equald()
+real ic_getr()
+include "hdic.com"
+
+begin
+ # Allocate space for density above fog array
+ call smark (sp)
+ call salloc (denaf, npts, TY_DOUBLE)
+
+ fog = double (ic_getr (ic, "fog"))
+ call asubkd (density, fog, Memd[denaf], npts)
+
+ switch (IC_TRANSFORM(ic)) {
+ case HD_NONE:
+ do i = 1, npts {
+ xout[i] = Memd[denaf+i-1]
+ # In every case, if the point was deleted by the program,
+ # restore it.
+ if (whydel[i] == PDELETE) {
+ wts[i] = userwts[i]
+ whydel[i] = NDELETE
+ }
+ }
+
+ call ic_pstr (ic, "xlabel", "Density above Fog")
+ xxmin = MIN_DEN - fog
+ xxmax = maxden
+ call ic_putr (ic, "xmin", real (xxmin))
+ call ic_putr (ic, "xmax", real (xxmax))
+
+ case HD_LOGO:
+ call ic_pstr (ic, "xlabel", "Log Opacitance: Log (10**Den - 1)")
+ xxmin = log10 ((10. ** (MIN_DEN)) - 1.0)
+ xxmax = log10 ((10. ** (maxden)) - 1.0)
+ call ic_putr (ic, "xmin", real (xxmin))
+ call ic_putr (ic, "xmax", real (xxmax))
+
+ do i = 1, npts {
+ dval = Memd[denaf+i-1]
+ if (dval < 0.0D0 || (fp_equald (dval, 0.0D0))) {
+ xout[i] = dval
+ wts[i] = 0.0D0
+ whydel[i] = PDELETE
+
+ } else {
+ xout[i] = log10 ((10. ** (dval)) - 1.0)
+
+ # If point had been deleted, find out why. It affects the
+ # weights value returned. Only if the point was previously
+ # deleted by the program, restore it; otherwise, leave it
+ # alone.
+
+ if (fp_equald (wts[i], 0.0D0)) {
+ if (whydel[i] == PDELETE) {
+ wts[i] = userwts[i]
+ whydel[i] = NDELETE
+ }
+ } else
+ wts[i] = userwts[i]
+ }
+ }
+
+ case HD_K75:
+ call ic_pstr (ic, "xlabel", "Den + 0.75 * Log (1 - (10 ** -Den))")
+ xxmin = MIN_DEN + 0.75 * log10 (1.0 - (10. ** (-MIN_DEN)))
+ xxmax = maxden + 0.75 * log10 (1.0 - (10. ** (-maxden)))
+ call ic_putr (ic, "xmin", real (xxmin))
+ call ic_putr (ic, "xmax", real (xxmax))
+
+ do i = 1, npts {
+ dval = Memd[denaf+i-1]
+ if (dval < 0.0D0 || (fp_equald (dval, 0.0D0))) {
+ xout[i] = dval
+ wts[i] = 0.0D0
+ whydel[i] = PDELETE
+
+ } else {
+ xout[i] = dval + 0.75 * log10 (1.0 - (10.** (-dval)))
+
+ # If point had been deleted, find out why. It affects the
+ # weights value returned. Only if the point was previously
+ # deleted by the program, restore it; otherwise, leave it
+ # alone.
+
+ if (fp_equald (wts[i], 0.0D0)) {
+ if (wts[i] == PDELETE) {
+ wts[i] = userwts[i]
+ whydel[i] = NDELETE
+ }
+ } else
+ wts[i] = userwts[i]
+ }
+ }
+
+ case HD_K50:
+ call ic_pstr (ic, "xlabel", "Den + 0.50 * Log (1 - (10 ** -Den))")
+ xxmin = MIN_DEN + 0.50 * log10 (1.0 - (10. ** (-MIN_DEN)))
+ xxmax = maxden + 0.50 * log10 (1.0 - (10. ** (-maxden)))
+ call ic_putr (ic, "xmin", real (xxmin))
+ call ic_putr (ic, "xmax", real (xxmax))
+
+ do i = 1, npts {
+ dval = Memd[denaf+i-1]
+ if (dval < 0.0D0 || (fp_equald (dval, 0.0D0))) {
+ xout[i] = dval
+ wts[i] = 0.0D0
+ whydel[i] = PDELETE
+
+ } else {
+ xout[i] = dval + 0.50 * log10 (1.0 - (10.** (-dval)))
+
+ # If point had been deleted, find out why. It affects the
+ # weights value returned. Only if the point was previously
+ # deleted by the program, restore it; otherwise, leave it
+ # alone.
+
+ if (fp_equald (wts[i], 0.0D0)) {
+ if (wts[i] == PDELETE) {
+ wts[i] = userwts[i]
+ whydel[i] = NDELETE
+ }
+ } else
+ wts[i] = userwts[i]
+ }
+ }
+
+ default:
+ call eprintf ("Unrecognizable Transform\n")
+ }
+
+ call sfree (sp)
+end
diff --git a/noao/imred/dtoi/hdicfit/hdicvshow.x b/noao/imred/dtoi/hdicfit/hdicvshow.x
new file mode 100644
index 00000000..e62f6522
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/hdicvshow.x
@@ -0,0 +1,155 @@
+include <math/curfit.h>
+include "hdicfit.h"
+
+# IC_VSHOW -- Show fit parameters in verbose mode.
+
+procedure ic_vshowd (ic, file, cv, x, y, wts, npts, gt)
+
+pointer ic # ICFIT pointer
+char file[ARB] # Output file
+pointer cv # Curfit pointer
+double x[ARB] # Ordinates
+double y[ARB] # Abscissas
+double wts[ARB] # Weights
+int npts # Number of data points
+pointer gt # Graphics tools pointer
+
+double chisqr, rms
+int i, n, deleted, ncoeffs, fd
+pointer sp, fit, wts1, coeffs, errors
+
+int dcvstati(), open()
+double ic_rmsd()
+errchk open()
+
+begin
+ # Do the standard ic_show option, then add on the verbose part.
+ call ic_show (ic, file, gt)
+
+ if (npts == 0) {
+ call eprintf ("Incomplete output - no data points for fit\n")
+ return
+ }
+
+ # Open the output file.
+ fd = open (file, APPEND, TEXT_FILE)
+
+ # Determine the number of coefficients and allocate memory.
+ ncoeffs = dcvstati (cv, CVNCOEFF)
+
+ call smark (sp)
+ call salloc (coeffs, ncoeffs, TY_DOUBLE)
+ call salloc (errors, ncoeffs, TY_DOUBLE)
+
+ if (npts == IC_NFIT(ic)) {
+ # Allocate memory for the fit.
+ n = npts
+ call salloc (fit, n, TY_DOUBLE)
+ call salloc (wts1, n, TY_DOUBLE)
+
+ # Eliminate rejected points and count deleted points.
+ call amovd (wts, Memd[wts1], n)
+ if (IC_NREJECT(ic) > 0) {
+ do i = 1, npts {
+ if (Memi[IC_REJPTS(ic)+i-1] == YES)
+ Memd[wts1+i-1] = 0.
+ }
+ }
+ deleted = 0
+ do i = 1, n {
+ if (wts[i] == 0.)
+ deleted = deleted + 1
+ }
+
+ # Get the coefficients and compute the errors.
+ call dcvvector (cv, x, Memd[fit], n)
+ call dcvcoeff (cv, Memd[coeffs], ncoeffs)
+ call dcverrors (cv, y, Memd[wts1], Memd[fit], n, chisqr,
+ Memd[errors])
+ rms = ic_rmsd (x, y, Memd[fit], Memd[wts1], n)
+
+ } else {
+ # Allocate memory for the fit.
+ n = IC_NFIT(ic)
+ call salloc (fit, n, TY_DOUBLE)
+ call salloc (wts1, n, TY_DOUBLE)
+
+ # Eliminate rejected points and count deleted points.
+ call amovd (Memd[IC_WTSFIT(ic)], Memd[wts1], n)
+ if (IC_NREJECT(ic) > 0) {
+ do i = 1, npts {
+ if (Memi[IC_REJPTS(ic)+i-1] == YES)
+ Memd[wts1+i-1] = 0.
+ }
+ }
+ deleted = 0
+ do i = 1, n {
+ if (wts[i] == 0.)
+ deleted = deleted + 1
+ }
+
+ # Get the coefficients and compute the errors.
+ call dcvvector (cv, Memd[IC_XFIT(ic)], Memd[fit], n)
+ rms = ic_rmsd (Memd[IC_XFIT(ic)], Memd[IC_YFIT(ic)],
+ Memd[fit], Memd[wts1], n)
+ call dcvcoeff (cv, Memd[coeffs], ncoeffs)
+ call dcverrors (cv, Memd[IC_YFIT(ic)], Memd[wts1], Memd[fit],
+ n, chisqr, Memd[errors])
+ }
+
+ # Print the error analysis.
+ call fprintf (fd, "total points = %d\n")
+ call pargi (npts)
+ call fprintf (fd, "deleted = %d\n")
+ call pargi (deleted)
+ call fprintf (fd, "RMS = %7.4g\n")
+ call pargd (rms)
+ call fprintf (fd, "square root of reduced chi square = %7.4g\n")
+ call pargd (sqrt (chisqr))
+
+ call fprintf (fd, "# \t coefficent\t error\n")
+ do i = 1, ncoeffs {
+ call fprintf (fd, "\t%10.4e\t%10.4e\n")
+ call pargd (Memd[coeffs+i-1])
+ call pargd (Memd[errors+i-1])
+ }
+
+ # Print x,y pairs and weights
+ call ic_listxywd (fd, cv, x, y, wts, npts)
+
+ call sfree (sp)
+ call close (fd)
+end
+
+
+# IC_LISTXYW -- List data as x,y pairs on output with their weights. Used
+# for verbose show procedure. The untransformed density is also output,
+# regardless of what transformation may have been applied.
+
+procedure ic_listxywd (fd, cv, xvals, yvals, weights, nvalues)
+
+int fd # File descriptor of output file
+pointer cv # Pointer to curfit structure
+int nvalues # Number of data values
+double xvals[nvalues] # Array of x data values
+double yvals[nvalues] # Array of y data values
+double weights[nvalues] # Array of weight values
+
+int i
+double dcveval()
+include "hdic.com"
+
+begin
+ call fprintf (fd,"\n#%15t Density %27t X %39t Yfit %51t LogE %63tWts\n")
+
+ do i = 1, nvalues {
+ call fprintf (fd,
+ "%2d %15t%-12.7f%27t%-12.7f%39t%-12.7f%51t%-12.7f%63t%-12.7f\n")
+ call pargi (i)
+ call pargd (Memd[den+i-1])
+ call pargd (xvals[i])
+ call pargd (dcveval (cv, xvals[i]))
+ call pargd (yvals[i])
+ call pargd (weights[i])
+ }
+end
diff --git a/noao/imred/dtoi/hdicfit/mkpkg b/noao/imred/dtoi/hdicfit/mkpkg
new file mode 100644
index 00000000..5fc5031f
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/mkpkg
@@ -0,0 +1,37 @@
+# HDICFIT package. *** Modified from icgfit package for DTOI applications ***
+
+update:
+ $update libhdic.a
+
+libhdic.a:
+
+ hdicclean.x hdicfit.h <pkg/rg.h>
+ hdicdeviant.x <mach.h> <math/curfit.h>
+ hdicdosetup.x hdicfit.h <math/curfit.h>
+ hdicerrors.x hdicfit.h <math/curfit.h>
+ hdicfit.x hdicfit.h <math/curfit.h>
+ hdicgaxes.x hdicfit.h <pkg/gtools.h>
+ hdicgcolon.x hdicfit.h <error.h> <gset.h>
+ hdicgdelete.x hdicfit.h <gset.h> <mach.h> <pkg/gtools.h>
+ hdicgfit.x hdicfit.h <error.h> <pkg/gtools.h> <mach.h> <gset.h>
+ hdicggraph.x hdicfit.h hdic.com <gset.h> <pkg/gtools.h> <mach.h>
+ hdicgnearest.x <mach.h> <pkg/gtools.h>
+ hdicgparams.x hdicfit.h <pkg/gtools.h>
+ hdicgsample.x hdicfit.h <gset.h> <pkg/gtools.h> <pkg/rg.h>
+ hdicguaxes.x hdic.com hdicfit.h
+ hdicgundel.x hdicfit.h <gset.h> <mach.h> <pkg/gtools.h>
+ hdicguser.x
+ hdicparams.x hdicfit.h
+ hdicreject.x
+ hdicshow.x hdicfit.h <pkg/gtools.h>
+ hdicvshow.x hdicfit.h hdic.com <math/curfit.h>
+
+ hdictrans.x hdicfit.h <mach.h> hdic.com
+ hdicgvec.x hdicfit.h <mach.h> hdic.com
+ hdicadd.x hdicfit.h
+ hdicinit.x hdic.com hdicfit.h <mach.h>
+ hdicsort.x
+ userfcn.x <error.h>
+ hdicgredraw.x <gset.h>
+ hdicebars.x hdicfit.h hdic.com <pkg/gtools.h> <gset.h> <mach.h>
+ ;
diff --git a/noao/imred/dtoi/hdicfit/userfcn.x b/noao/imred/dtoi/hdicfit/userfcn.x
new file mode 100644
index 00000000..d5dba4ed
--- /dev/null
+++ b/noao/imred/dtoi/hdicfit/userfcn.x
@@ -0,0 +1,37 @@
+include <error.h>
+
+# HD_POWERR -- Construct the basis functions for a power series function.
+# Invoked from curfit as a user function. Real version.
+
+procedure hd_powerr (x, order, k1, k2, basis)
+
+real x # array of data points
+int order # order of polynomial, order = 1, constant
+real k1, k2 # normalizing constants - unused
+real basis[ARB] # basis functions
+
+int i
+
+begin
+ do i = 1, order
+ iferr (basis[i] = x ** (i-1))
+ call erract (EA_FATAL)
+end
+
+
+# HD_POWERD -- Double version of above.
+
+procedure hd_powerd (x, order, k1, k2, basis)
+
+double x # array of data points
+int order # order of polynomial, order = 1, constant
+double k1, k2 # normalizing constants - unused
+double basis[ARB] # basis functions
+
+int i
+
+begin
+ do i = 1, order
+ iferr (basis[i] = x ** (i-1))
+ call erract (EA_FATAL)
+end
diff --git a/noao/imred/dtoi/hdshift.par b/noao/imred/dtoi/hdshift.par
new file mode 100644
index 00000000..c1fdf5c9
--- /dev/null
+++ b/noao/imred/dtoi/hdshift.par
@@ -0,0 +1,2 @@
+# Cl parameters for task hdshift are:
+database,s,a,"",,,List of database file
diff --git a/noao/imred/dtoi/hdshift.x b/noao/imred/dtoi/hdshift.x
new file mode 100644
index 00000000..cde846ad
--- /dev/null
+++ b/noao/imred/dtoi/hdshift.x
@@ -0,0 +1,184 @@
+include <math/curfit.h>
+
+# T_HDSHIFT -- Task hdshift in the dtoi package. This task is provided
+# to support Kormendy's method of combining related characteristic curves.
+# A zero point shift in log exp unique to each set of spots is calculated and
+# subtracted. A single curve is fit to the combined, shifted data in
+# a separate task (hdfit).
+
+procedure t_hdshift ()
+
+pointer sp, de, fun, save, db, cv, ps_coeff, den, exp, cvf
+int fd, rec, nsave, ncoeff, nvalues, i, nfile, junk
+real a0, ref_a0
+
+pointer ddb_map()
+int clpopni(), ddb_locate(), ddb_geti(), cvstati(), strncmp(), clgfil()
+
+begin
+ # Allocate space on stack for string buffers
+ call smark (sp)
+ call salloc (de, SZ_FNAME, TY_CHAR)
+ call salloc (cvf, SZ_FNAME, TY_CHAR)
+ call salloc (fun, SZ_FNAME, TY_CHAR)
+
+ # Get list of the database names. The curfit information is retrieved
+ # from the first file in the list, the list is then rewound.
+
+ fd = clpopni ("database")
+ junk = clgfil (fd, Memc[cvf], SZ_FNAME)
+ call clprew (fd)
+
+ # Get coefficients of common fit from cv_file
+ db = ddb_map (Memc[cvf], READ_ONLY)
+ rec = ddb_locate (db, "cv")
+ nsave = ddb_geti (db, rec, "save")
+ call salloc (save, nsave, TY_REAL)
+ call ddb_gar (db, rec, "save", Memr[save], nsave, nsave)
+ call ddb_gstr (db, rec, "function", Memc[fun], SZ_LINE)
+
+ call cvrestore (cv, Memr[save])
+ ncoeff = cvstati (cv, CVNCOEFF)
+ call salloc (ps_coeff, ncoeff, TY_REAL)
+
+ if (strncmp (Memc[fun], "power", 5) == 0)
+ call cvcoeff (cv, Memr[ps_coeff], ncoeff)
+ else
+ call cvpower (cv, Memr[ps_coeff], ncoeff)
+
+ do i = 1, ncoeff {
+ call eprintf ("%d %.7g\n")
+ call pargi (i)
+ call pargr (Memr[ps_coeff+i-1])
+ }
+
+ call ddb_unmap (db)
+
+ nfile = 0
+ while (clgfil (fd, Memc[de], SZ_FNAME) != EOF) {
+ db = ddb_map (Memc[de], READ_ONLY)
+ call hds_read (db, den, exp, nvalues)
+ call hds_calc (den, exp, nvalues, Memr[ps_coeff], ncoeff, a0)
+ nfile = nfile + 1
+ if (nfile == 1)
+ ref_a0 = a0
+ a0 = a0 - ref_a0
+
+ call printf ("file %s: subtracting zero point a0 = %.7g\n")
+ call pargstr (Memc[de])
+ call pargr (a0)
+
+ # Write new log exposure information to database
+ db = ddb_map (Memc[de], APPEND)
+ call hds_wdb (db, exp, nvalues, a0)
+ call mfree (den, TY_REAL)
+ call mfree (exp, TY_REAL)
+ call ddb_unmap (db)
+ }
+
+ call clpcls (fd)
+ call sfree (sp)
+end
+
+
+# HDS_READ -- Read the density and exposure values from the database file.
+# The density above fog and log exposure values are returned, as well as
+# the number of data pairs read.
+
+procedure hds_read (db, den, exp, nvalues)
+
+pointer db # Pointer to input database file
+pointer den # Pointer to density array - returned
+pointer exp # Pointer to exposure array - returned
+int nvalues # Number of data pairs read - returned
+
+real fog
+int nden, nexp, rec
+int ddb_locate(), ddb_geti()
+real ddb_getr()
+
+begin
+ # Get fog value to be subtracted from density
+ rec = ddb_locate (db, "fog")
+ fog = ddb_getr (db, rec, "density")
+
+ # Get density array
+ rec = ddb_locate (db, "density")
+ nden = ddb_geti (db, rec, "den_val")
+ call malloc (den, nden, TY_REAL)
+ call ddb_gar (db, rec, "den_val", Memr[den], nden, nden)
+ call asubkr (Memr[den], fog, Memr[den], nden)
+
+ # Get exposure array
+ rec = ddb_locate (db, "exposure")
+ nexp = ddb_geti (db, rec, "log_exp")
+ call malloc (exp, nexp, TY_REAL)
+ call ddb_gar (db, rec, "log_exp", Memr[exp], nexp, nexp)
+
+ nvalues = min (nden, nexp)
+end
+
+
+# HDS_CALC -- Calculate the individual shift, a0.
+
+procedure hds_calc (den, exp, nvalues, ps_coeff, ncoeff, a0)
+
+pointer den
+pointer exp
+int nvalues
+real ps_coeff[ARB]
+int ncoeff
+real a0
+
+int i
+real yavg, ycalc, xavg
+
+begin
+ # Calculate average density and log exposure values
+ xavg = 0.0
+ yavg = 0.0
+
+ do i = 1, nvalues {
+ xavg = xavg + Memr[den+i-1]
+ yavg = yavg + Memr[exp+i-1]
+ }
+
+ xavg = xavg / real (nvalues)
+ yavg = yavg / real (nvalues)
+
+ ycalc = 0.0
+ do i = 2, ncoeff
+ ycalc = ycalc + ps_coeff[i] * (xavg ** real (i-1))
+
+ # Subtraction yields the zero point shift in question
+ a0 = yavg - ycalc
+end
+
+
+# HDS_WDB -- Write shifted log exposure values to database.
+
+procedure hds_wdb (db, exp, nvalues, a0)
+
+pointer db # Pointer to database
+pointer exp # Pointer to array of exposure values
+int nvalues # Number of exposure values in sample
+real a0 # Shift to be subtracted
+
+pointer sp, expsub
+
+begin
+ call smark (sp)
+ call salloc (expsub, nvalues, TY_REAL)
+
+ call ddb_ptime (db)
+ call ddb_prec (db, "exposure")
+
+ call eprintf ("a0 = %g\n")
+ call pargr (a0)
+
+ call asubkr (Memr[exp], a0, Memr[expsub], nvalues)
+ call ddb_par (db, "log_exp", Memr[expsub], nvalues)
+
+ call ddb_putr (db, "A0 shift", a0)
+ call sfree (sp)
+end
diff --git a/noao/imred/dtoi/hdtoi.par b/noao/imred/dtoi/hdtoi.par
new file mode 100644
index 00000000..e26cde83
--- /dev/null
+++ b/noao/imred/dtoi/hdtoi.par
@@ -0,0 +1,11 @@
+# Cl parameters are:
+input,f,a,,,,List of images to be transformed
+output,f,a,,,,List of output image names
+database,f,a,,,,Database containing fit parameters
+fog,s,h,"",,,Value of fog - read from database if unspecified
+sigma,r,h,3.0,,,Rejection criteria for determining mean fog
+floor,r,h,0.0,,,Value assigned to levels below fog
+ceiling,r,h,30000.,,,Scale highest density to this intensity value
+datatype,s,h,r,,,Pixel type of output image
+option,s,h,mean,"mean|median",,Choice of fog algorithm (mean or median)
+verbose,b,h,yes,,,Print log of processing to STDOUT
diff --git a/noao/imred/dtoi/hdtoi.x b/noao/imred/dtoi/hdtoi.x
new file mode 100644
index 00000000..5b550ea8
--- /dev/null
+++ b/noao/imred/dtoi/hdtoi.x
@@ -0,0 +1,407 @@
+include <imhdr.h>
+include <mach.h>
+include <math/curfit.h>
+include <error.h>
+include "hdicfit/hdicfit.h"
+
+# T_HDTOI -- transform an image from density to intensity, according
+# to an hd curve described in an input database. A look up table of
+# all possible values is generated with the curfit package, and
+# then the image is transformed line by line. A fog value is subtracted
+# from the image prior to transformation, and it can be entered as either
+# a number or a list of fog images from which the fog value is calculated.
+# If a fog value has not been entered by the user, it is read from the database.
+
+procedure t_hdtoi ()
+
+pointer sp, cv, fog, db, im_in, lut, im_out, imageout, imagein, option
+bool verbose
+int minval, maxval, in_list, rec, ip, out_list, fog_list, ngpix
+int datatype, nluv, updatedb, nfpix
+real sigma, floor, scale, fog_val, sdev
+
+char clgetc()
+bool streq(), clgetb()
+pointer ddb_map(), immap()
+int imtopenp(), ddb_locate(), ctor(), imtlen(), imtgetim()
+int get_data_type(), imtopen()
+real clgetr(), ddb_getr()
+
+begin
+ call smark (sp)
+ call salloc (cv, SZ_FNAME, TY_CHAR)
+ call salloc (fog, SZ_LINE, TY_CHAR)
+ call salloc (imageout, SZ_FNAME, TY_CHAR)
+ call salloc (imagein, SZ_FNAME, TY_CHAR)
+
+ # Get cl parameters
+ in_list = imtopenp ("input")
+ out_list = imtopenp ("output")
+ call clgstr ("database", Memc[cv], SZ_FNAME)
+ call clgstr ("fog", Memc[fog], SZ_LINE)
+ sigma = clgetr ("sigma")
+ floor = clgetr ("floor")
+ verbose = clgetb ("verbose")
+ updatedb = NO
+
+ datatype = get_data_type (clgetc ("datatype"))
+ if (datatype == ERR)
+ call eprintf ("Using input pixel datatype for output\n")
+
+ db = ddb_map (Memc[cv], READ_ONLY)
+ rec = ddb_locate (db, "common")
+ scale = ddb_getr (db, rec, "scale")
+
+ # If not specified by user, get fog value from database. User can
+ # specify fog as a real number or a list of fog file names.
+
+ if (streq (Memc[fog], "")) {
+ rec = ddb_locate (db, "fog")
+ fog_val = ddb_getr (db, rec, "density")
+ } else {
+ ip = 1
+ if (ctor (Memc[fog], ip, fog_val) == 0) {
+ if (verbose)
+ call eprintf ("Calculating fog value ...\n")
+ fog_list = imtopen (Memc[fog])
+ call salloc (option, SZ_FNAME, TY_CHAR)
+ call clgstr ("option", Memc[option], SZ_FNAME)
+ call hd_fogcalc (fog_list, fog_val, sdev, ngpix, scale, sigma,
+ Memc[option], nfpix)
+
+ call eprintf ("Fog density = %f, sdev = %f, ngpix = %d\n")
+ call pargr (fog_val)
+ call pargr (sdev)
+ call pargi (ngpix)
+
+ updatedb = YES
+ }
+ }
+
+ # Generate look up table. First, the range of input values to
+ # calculate output values for must be determined. Arguments
+ # minval and maxval are integers because we assume all input
+ # images are short integers.
+
+ call hd_glimits (in_list, minval, maxval)
+ nluv = (maxval - minval) + 1
+ call salloc (lut, nluv, TY_REAL)
+
+ if (verbose)
+ call eprintf ("Generating look up table ...\n")
+ call hd_wlut (db, Memr[lut], minval, maxval, fog_val, floor)
+
+ # Loop through input images, applying transform
+ if (imtlen (in_list) != imtlen (out_list)) {
+ call imtclose (in_list)
+ call imtclose (out_list)
+ call error (0, "Number of input and output images not the same")
+ }
+
+ while ((imtgetim (in_list, Memc[imagein], SZ_FNAME) != EOF) &&
+ (imtgetim (out_list, Memc[imageout], SZ_FNAME) != EOF)) {
+
+ iferr (im_in = immap (Memc[imagein], READ_ONLY, 0)) {
+ call erract (EA_WARN)
+ next
+ }
+
+ iferr (im_out = immap (Memc[imageout], NEW_COPY, im_in)) {
+ call imunmap (im_in)
+ call erract (EA_WARN)
+ next
+ }
+
+ if (verbose) {
+ call eprintf ("Density to Intensity Transform: %s ===> %s\n")
+ call pargstr (Memc[imagein])
+ call pargstr (Memc[imageout])
+ }
+
+ call hd_transform (im_in, im_out, Memr[lut], nluv, minval, datatype)
+
+ call imunmap (im_in)
+ call imunmap (im_out)
+ }
+
+ call ddb_unmap (db)
+ call imtclose (in_list)
+ call imtclose (out_list)
+
+ if (updatedb == YES) {
+ db = ddb_map (Memc[cv], APPEND)
+ # Write fog information to database as single record
+ call ddb_prec (db, "fog")
+ call ddb_putr (db, "density", fog_val)
+ call ddb_putr (db, "sdev", sdev)
+ call ddb_puti (db, "ngpix", ngpix)
+ call ddb_pstr (db, "option", Memc[option])
+ call ddb_unmap (db)
+ }
+
+ call sfree (sp)
+end
+
+
+# HD_TRANSFORM -- Apply transformation to image.
+
+procedure hd_transform (im, im_out, lu_table, nvals, minval, datatype)
+
+pointer im # Input image header pointer
+pointer im_out # Transformed image header pointer
+real lu_table[ARB] # Array of intensity values
+int nvals # Number of values in the lut
+int minval # Offset to first value in look up table
+int datatype # Pixel type on output
+
+int j, ncols
+pointer ptr_in, ptr_out, sp, luti
+pointer impl2r(), imgl2i(), impl2i()
+
+begin
+ if (datatype == ERR)
+ IM_PIXTYPE(im_out) = IM_PIXTYPE(im)
+ else
+ IM_PIXTYPE(im_out) = datatype
+
+ ncols = IM_LEN(im,1)
+
+ switch (datatype) {
+ case TY_REAL, TY_DOUBLE:
+ # Loop over input image rows. The look up table is left as
+ # a real array and a floating point image is written out.
+
+ do j = 1, IM_LEN(im,2) {
+ ptr_in = imgl2i (im, j)
+ ptr_out = impl2r (im_out, j)
+ call asubki (Memi[ptr_in], minval, Memi[ptr_in], ncols)
+ call alutr (Memi[ptr_in], Memr[ptr_out], ncols, lu_table)
+ }
+
+ default:
+ # Loop over input image rows. The look up table is truncated
+ # to type integer.
+
+ call smark (sp)
+ call salloc (luti, nvals, TY_INT)
+ call achtri (lu_table, Memi[luti], nvals)
+
+ do j = 1, IM_LEN(im,2) {
+ ptr_in = imgl2i (im, j)
+ ptr_out = impl2i (im_out, j)
+ call asubki (Memi[ptr_in], minval, Memi[ptr_in], ncols)
+ call aluti (Memi[ptr_in], Memi[ptr_out], ncols, Memi[luti])
+ }
+
+ call sfree (sp)
+ }
+end
+
+
+# HD_WLUT -- write look up table, such that intensity = lut [a/d output].
+# An entry is made in the look up table for every possible input value,
+# from minval to maxval.
+
+procedure hd_wlut (db, lut, minval, maxval, fog_val, floor)
+
+pointer db # Pointer to database file
+real lut[ARB] # Pointer to look up table, which gets filled here
+int minval # Minimum value to transform
+int maxval # Maximum value to transform
+real fog_val # Fog value to be subtracted from densities
+real floor # Value assigned to densities below fog
+
+bool zerofloor
+pointer sp, trans, fcn, save, cv, dens, ind_var, value
+int rec, nsave, i, function, nneg, npos, nvalues
+real scale, maxcvval, factor, maxexp, maxden, maxdenaf
+
+bool fp_equalr()
+int strncmp(), ddb_locate(), ddb_geti(), cvstati()
+real ddb_getr(), clgetr(), cveval()
+extern hd_powerr()
+
+begin
+ call smark (sp)
+ call salloc (trans, SZ_FNAME, TY_CHAR)
+ call salloc (fcn, SZ_FNAME, TY_CHAR)
+
+ nvalues = (maxval - minval) + 1
+ call salloc (ind_var, nvalues, TY_REAL)
+ call salloc (dens, nvalues, TY_REAL)
+ call salloc (value, nvalues, TY_REAL)
+
+ rec = ddb_locate (db, "common")
+ scale = ddb_getr (db, rec, "scale")
+ maxden = ddb_getr (db, rec, "maxden")
+
+ rec = ddb_locate (db, "cv")
+ nsave = ddb_geti (db, rec, "save")
+ call salloc (save, nsave, TY_REAL)
+ call ddb_gar (db, rec, "save", Memr[save], nsave, nsave)
+ call ddb_gstr (db, rec, "transformation", Memc[trans], SZ_LINE)
+
+ call cvrestore (cv, Memr[save])
+ function = cvstati (cv, CVTYPE)
+
+ if (function == USERFNC) {
+ # Need to restablish choice of user function
+ call ddb_gstr (db, rec, "function", Memc[fcn], SZ_FNAME)
+ if (strncmp (Memc[fcn], "power", 1) == 0)
+ call cvuserfnc (cv, hd_powerr)
+ else
+ call error (0, "Unknown user function in database")
+ }
+
+ maxdenaf = maxden - fog_val
+ call hd_aptrans (maxdenaf, maxcvval, 1, Memc[trans])
+ maxcvval = 10.0 ** (cveval (cv, maxcvval))
+ factor = clgetr ("ceiling") / maxcvval
+ maxexp = real (MAX_EXPONENT) - (log10 (factor) + 1.0)
+
+ zerofloor = false
+ if (fp_equalr (0.0, floor))
+ zerofloor = true
+
+ do i = 1, nvalues
+ Memr[value+i-1] = real (minval + i - 1)
+
+ # Scale all posible voltage values to density above fog
+ call altmr (Memr[value], Memr[dens], nvalues, scale, -fog_val)
+
+ # Find index of first value greater than MIN_DEN. Values less than
+ # this must be handled as the user specified with the floor parameter.
+
+ for (nneg=0; Memr[dens+nneg] < MIN_DEN; nneg=nneg+1)
+ ;
+ npos = nvalues - nneg
+
+ # Generate independent variable vector and then lut values. The
+ # logic is different if there are values below fog. Evaluating
+ # the polynomial fit with cvvector yields the log exposure. This
+ # is then converted to intensity and scaled by a user supplied factor.
+
+ if (nneg > 0) {
+ if (zerofloor) {
+ call amovkr (0.0, lut, nneg)
+ call hd_aptrans (Memr[dens+nneg],Memr[ind_var],npos,Memc[trans])
+ call cvvector (cv, Memr[ind_var], lut[nneg+1], npos)
+ call argtr (lut[nneg+1], npos, maxexp, maxexp)
+ do i = nneg+1, nvalues
+ lut[i] = (10. ** lut[i]) * factor
+
+ } else {
+ call amulkr (Memr[dens], -1.0, Memr[dens], nneg)
+
+ # Care must be taken so that no density of value 0.0 is
+ # passed to hd_aptrans. This would cause an overflow.
+
+ do i = 1, nneg {
+ if (fp_equalr (Memr[dens], 0.0))
+ Memr[dens] = MIN_DEN
+ }
+
+ call hd_aptrans (Memr[dens],Memr[ind_var], nvalues, Memc[trans])
+ call cvvector (cv, Memr[ind_var], lut, nvalues)
+ call argtr (lut, nvalues, maxexp, maxexp)
+ do i = 1, nvalues
+ lut[i] = (10.0 ** lut[i]) * factor
+ call amulkr (lut, -1.0, lut, nneg)
+ }
+
+ } else {
+ call hd_aptrans (Memr[dens], Memr[ind_var], nvalues, Memc[trans])
+ call cvvector (cv, Memr[ind_var], lut, nvalues)
+ call argtr (lut, nvalues, maxexp, maxexp)
+ do i = 1, nvalues
+ lut[i] = (10.0 ** lut[i]) * factor
+ }
+
+ call cvfree (cv)
+ call sfree (sp)
+end
+
+
+# HD_APTRANS -- Apply transformation, generating a vector of independent
+# variables from a density vector. It is assummed all values in the
+# input density vector are valid and will not cause arithmetic errors.
+# No checking for out of bounds values is performed.
+
+procedure hd_aptrans (density, ind_var, nvalues, transform)
+
+real density[nvalues] # Density vector - input
+real ind_var[nvalues] # Ind variable vector - filled on output
+int nvalues # Length of vectors
+char transform[ARB] # String containing transformation type
+
+int i
+int strncmp()
+
+begin
+ if (strncmp (transform, "logopacitance", 1) == 0) {
+ do i = 1, nvalues
+ ind_var[i] = log10 ((10. ** density[i]) - 1.0)
+
+ } else if (strncmp (transform, "k75", 2) == 0) {
+ do i = 1, nvalues
+ ind_var[i] = density[i] + .75 * log10(1. - 10. ** (-density[i]))
+
+ } else if (strncmp (transform, "k50", 2) == 0) {
+ do i = 1, nvalues
+ ind_var[i] = density[i] + .50 * log10(1. - 10. ** (-density[i]))
+
+ } else if (strncmp (transform, "none", 1) == 0) {
+ do i = 1, nvalues
+ ind_var[i] = density[i]
+
+ } else
+ call error (0, "Unrecognized transformation in database file")
+end
+
+
+# HD_GLIMITS -- Determinine the range of max and min values for a list
+# of images.
+
+procedure hd_glimits (in_list, minval, maxval)
+
+int in_list # File descriptor for list of images
+int minval # Smallest pixel value - returned
+int maxval # Largest pixel value - returned
+
+pointer im
+char image[SZ_FNAME]
+real current_min, current_max, min, max
+pointer immap()
+int imtgetim()
+errchk imtgetim, im_minmax, imtrew
+
+begin
+ current_min = MAX_REAL
+ current_max = EPSILONR
+
+ while (imtgetim (in_list, image, SZ_FNAME) != EOF) {
+ iferr (im = immap (image, READ_ONLY, 0))
+ # Just ignore it, warning will be printed by t_hdtoi
+ next
+
+ # Update min max values if necessary
+ if (IM_LIMTIME(im) < IM_MTIME(im))
+ call im_minmax (im, IM_MIN(im), IM_MAX(im))
+
+ min = IM_MIN(im)
+ max = IM_MAX(im)
+
+ if (min < current_min)
+ current_min = min
+
+ if (max > current_max)
+ current_max = max
+
+ call imunmap (im)
+ }
+
+ minval = int (current_min)
+ maxval = int (current_max)
+
+ call imtrew (in_list)
+end
diff --git a/noao/imred/dtoi/minmax.x b/noao/imred/dtoi/minmax.x
new file mode 100644
index 00000000..97d113f0
--- /dev/null
+++ b/noao/imred/dtoi/minmax.x
@@ -0,0 +1,73 @@
+include <imhdr.h>
+
+# IM_MINMAX -- Compute the minimum and maximum pixel values of an image.
+# Works for images of any dimensionality, size, or datatype, although
+# the min and max values can currently only be stored in the image header
+# as real values.
+
+procedure im_minmax (im, min_value, max_value)
+
+pointer im # image descriptor
+real min_value # minimum pixel value in image (out)
+real max_value # maximum pixel value in image (out)
+
+pointer buf
+bool first_line
+long v[IM_MAXDIM]
+short minval_s, maxval_s
+long minval_l, maxval_l
+real minval_r, maxval_r
+int imgnls(), imgnll(), imgnlr()
+errchk amovkl, imgnls, imgnll, imgnlr, alims, aliml, alimr
+
+begin
+ call amovkl (long(1), v, IM_MAXDIM) # start vector
+ first_line = true
+ min_value = INDEF
+ max_value = INDEF
+
+ switch (IM_PIXTYPE(im)) {
+ case TY_SHORT:
+ while (imgnls (im, buf, v) != EOF) {
+ call alims (Mems[buf], IM_LEN(im,1), minval_s, maxval_s)
+ if (first_line) {
+ min_value = minval_s
+ max_value = maxval_s
+ first_line = false
+ } else {
+ if (minval_s < min_value)
+ min_value = minval_s
+ if (maxval_s > max_value)
+ max_value = maxval_s
+ }
+ }
+ case TY_USHORT, TY_INT, TY_LONG:
+ while (imgnll (im, buf, v) != EOF) {
+ call aliml (Meml[buf], IM_LEN(im,1), minval_l, maxval_l)
+ if (first_line) {
+ min_value = minval_s
+ max_value = maxval_s
+ first_line = false
+ } else {
+ if (minval_l < min_value)
+ min_value = minval_l
+ if (maxval_l > max_value)
+ max_value = maxval_l
+ }
+ }
+ default:
+ while (imgnlr (im, buf, v) != EOF) {
+ call alimr (Memr[buf], IM_LEN(im,1), minval_r, maxval_r)
+ if (first_line) {
+ min_value = minval_r
+ max_value = maxval_r
+ first_line = false
+ } else {
+ if (minval_r < min_value)
+ min_value = minval_r
+ if (maxval_r > max_value)
+ max_value = maxval_r
+ }
+ }
+ }
+end
diff --git a/noao/imred/dtoi/mkpkg b/noao/imred/dtoi/mkpkg
new file mode 100644
index 00000000..80d5b737
--- /dev/null
+++ b/noao/imred/dtoi/mkpkg
@@ -0,0 +1,40 @@
+# Make the DTOI package.
+
+$call relink
+$exit
+
+update:
+ $call relink
+ $call install
+ ;
+
+relink:
+ $call update@hdicfit
+ $update libpkg.a
+ $call dtoi
+ ;
+
+install:
+ $move xx_dtoi.e noaobin$x_dtoi.e
+ ;
+
+dtoi:
+ $omake x_dtoi.x
+ $link x_dtoi.o libpkg.a hdicfit/libhdic.a -lxtools -lcurfit\
+ -o xx_dtoi.e
+ ;
+
+libpkg.a:
+ database.x <ctotok.h> <ctype.h> <finfo.h> <time.h>
+ dematch.x <error.h>
+ hd_aravr.x <mach.h>
+ hdfit.x hdicfit/hdicfit.h <ctype.h> <error.h> <fset.h>\
+ <imhdr.h> <mach.h> <math/curfit.h> <pkg/gtools.h>\
+ <pkg/xtanswer.h>
+ hdshift.x <math/curfit.h>
+ hdtoi.x hdicfit/hdicfit.h <error.h> <imhdr.h> <mach.h>\
+ <math/curfit.h>
+ minmax.x <imhdr.h>
+ selftest.x <gio.h> <gset.h> <mach.h>
+ spotlist.x <error.h> <fset.h> <imhdr.h> <mach.h>
+ ;
diff --git a/noao/imred/dtoi/selftest.par b/noao/imred/dtoi/selftest.par
new file mode 100644
index 00000000..75445cf7
--- /dev/null
+++ b/noao/imred/dtoi/selftest.par
@@ -0,0 +1,8 @@
+# Parameters for task selftest
+nbits,i,q,12,,,Test data range
+device,s,h,"stdgraph",,,Output device
+verbose,b,h,no,,,"Print density, intensity values?"
+ceiling,r,h,30000.,,,Scale densest point to this intensity
+max_raw,i,q,0,,,Max raw data value
+scale,r,q,,0.0,,Raw value to density scale factor
+mode,s,h,ql
diff --git a/noao/imred/dtoi/selftest.x b/noao/imred/dtoi/selftest.x
new file mode 100644
index 00000000..3a7a4a4a
--- /dev/null
+++ b/noao/imred/dtoi/selftest.x
@@ -0,0 +1,290 @@
+include <gio.h>
+include <gset.h>
+include <mach.h>
+
+define A0 (-1.74743)
+define A1 (0.73)
+define A2 (-0.24)
+define A3 (0.035)
+define MAXDEN 6.0
+
+# T_SELFTEST -- a test procedure for the DTOI package. Two intensity vectors
+# are calculated in different ways and compared. A plot of the residuals is
+# shown. A plot showing the extent of truncation errors is also drawn. Two
+# standard ranges of data values are available: 12 bit, representing PDS
+# format data and 15 bit, representing the FITS data format available on the
+# PDS. Any other choice results in a small test, ranging from 1 - 144.
+
+procedure t_selftest
+
+bool verbose
+char device[SZ_FNAME]
+pointer sp, intk, intc, raw, den, gp
+int min_raw, max_raw, nvalues, i, nbits
+real scale, factor, ceiling
+
+bool clgetb()
+pointer gopen()
+int clgeti()
+real clgetr()
+
+begin
+ call smark (sp)
+
+ nbits = clgeti ("nbits")
+
+ switch (nbits) {
+ case 12:
+ min_raw = 1
+ max_raw = 3072
+ scale = 0.00151
+ case 15:
+ min_raw = 1
+ max_raw = 24576
+ scale = 4.65 / 24575.
+ case 0:
+ call eprintf ("Using test data range from 1 - 144\n")
+ min_raw = 1
+ max_raw = 144
+ scale = 0.0325
+ default:
+ call eprintf ("Unknown case: nbits = '%d', Please supply values:\n")
+ call pargi (nbits)
+ min_raw = 1
+ max_raw = clgeti ("max_raw")
+ # max density = 6.0. Density = raw value * scale.
+ call clputr ("scale.p_maximum", real (MAXDEN / max_raw))
+ call clputr ("scale.p_default", real (4.65 / (max_raw - 1)))
+ scale = clgetr ("scale")
+ }
+
+ call clgstr ("device", device, SZ_FNAME)
+ verbose = clgetb ("verbose")
+ ceiling = clgetr ("ceiling")
+
+ gp = gopen (device, NEW_FILE, STDGRAPH)
+
+ nvalues = max_raw - min_raw + 1
+ call salloc (intk, nvalues, TY_REAL)
+ call salloc (intc, nvalues, TY_REAL)
+ call salloc (den, nvalues, TY_REAL)
+ call salloc (raw, nvalues, TY_REAL)
+
+ do i = 1, nvalues
+ Memr[raw+i-1] = min_raw + i - 1
+
+ call amulkr (Memr[raw], scale, Memr[den], nvalues)
+
+ call hd_known (min_raw, max_raw, scale, Memr[intk], nvalues)
+ call hd_calc (min_raw, max_raw, scale, Memr[intc], nvalues)
+
+ if (verbose) {
+ factor = ceiling / Memr[intc+nvalues-1]
+ call printf ("# %20tRaw Value %40tDensity %60tIntensity\n\n")
+ do i = 1, nvalues {
+ call printf ("%20t%d %40t%g %60t%g\n")
+ call pargi (i)
+ call pargr (Memr[den+i-1])
+ call pargr (Memr[intc+i-1] * factor)
+ }
+ }
+
+ call hd_plotit (gp, Memr[den], Memr[intk], Memr[intc], nvalues)
+
+ call hd_trunc (gp, Memr[den], nvalues, ceiling, Memr[intc])
+
+ call gclose (gp)
+ call sfree (sp)
+end
+
+
+# HD_KNOWN -- Calculate vector of known intensity values.
+
+procedure hd_known (min_raw, max_raw, scale, intk, nvalues)
+
+int min_raw # Minimum raw data value
+int max_raw # Maximum raw data value
+real scale # Density = raw_value * scale
+real intk[nvalues] # Known intensities - filled on return
+int nvalues # Number of intensity values requested
+
+int i
+real density, logo
+real exp
+
+begin
+ do i = min_raw, max_raw {
+ density = max (EPSILONR, i * scale)
+ logo = log10 ((10. ** density) - 1.0)
+ exp = A0 + A1 * logo + A2 * logo ** 2 + A3 * logo ** 3
+ intk[i] = 10 ** (exp)
+ }
+end
+
+
+# HD_CALC -- Calcuate vector of intensity values as in HDTOI.
+
+procedure hd_calc (min, max, scale, intc, nvalues)
+
+int min # Minimum raw data value
+int max # Maximum raw data value
+real scale # Density = raw_value * scale
+real intc[nvalues] # Calculated intensity values - filled on return
+int nvalues # Number of intensity values requested
+
+real cfit[9]
+pointer sp, lut
+
+begin
+ call smark (sp)
+ call salloc (lut, nvalues, TY_REAL)
+
+ cfit[1] = 5.0
+ cfit[2] = 4.0
+ cfit[3] = -10.0
+ cfit[4] = MAXDEN
+ cfit[5] = 1.
+ cfit[6] = A0
+ cfit[7] = A1
+ cfit[8] = A2
+ cfit[9] = A3
+ call st_wlut (Memr[lut], min, max, scale, cfit)
+ call st_transform (min, max, Memr[lut], nvalues, intc)
+
+ call sfree (sp)
+end
+
+
+# HD_TRUNC -- Investigate truncation errors for real versus int output image.
+
+procedure hd_trunc (gp, density, nvalues, ceiling, intc)
+
+pointer gp # Pointer to graphics stream
+real density[nvalues] # Density array
+int nvalues # Number of density, intensity values
+real ceiling # Max intensity to output
+real intc[nvalues] # Calculated intensity values
+
+pointer sp, yint, yreal
+int npvals
+real factor
+
+begin
+ call smark (sp)
+
+ # Only the lowest 5% of the data values are plotted
+ npvals = nvalues * 0.05
+
+ call salloc (yint, npvals, TY_INT)
+ call salloc (yreal, npvals, TY_REAL)
+
+ # Scale intensity vector to ceiling
+ factor = ceiling / intc[nvalues]
+
+ call amulkr (intc, factor, intc, npvals)
+ call achtri (intc, Memi[yint], npvals)
+ call achtir (Memi[yint], Memr[yreal], npvals)
+
+ call gascale (gp, density, npvals, 1)
+ call gascale (gp, Memr[yreal], npvals, 2)
+ call gsview (gp, 0.2, 0.9, 0.1, 0.4)
+ call gseti (gp, G_ROUND, YES)
+ call glabax (gp,
+ "Expand to see Truncation Errors\n (real=SOLID, integer=DASHED)",
+ "Density (Lowest 5% only)", "Intensity")
+
+ call gseti (gp, G_PLTYPE, GL_SOLID)
+ call gpline (gp, density, intc, npvals)
+
+ call gseti (gp, G_PLTYPE, GL_DASHED)
+ call gpline (gp, density, Memr[yreal], npvals)
+
+ call sfree (sp)
+end
+
+
+# HD_PLOTIT -- Plot residuals of calculated versus known itensity.
+
+procedure hd_plotit (gp, density, intk, intc, nvalues)
+
+pointer gp # Pointer to graphics stream
+real density[nvalues] # Density array
+real intk[nvalues] # Array of known intensities
+real intc[nvalues] # Array of calculated intensities
+int nvalues # Number of density, intensity values
+
+pointer sp, resid
+
+begin
+ call smark (sp)
+ call salloc (resid, nvalues, TY_REAL)
+
+ call asubr (intk, intc, Memr[resid], nvalues)
+
+ call gascale (gp, density, nvalues, 1)
+ call gascale (gp, Memr[resid], nvalues, 2)
+ call gsview (gp, 0.2, 0.9, 0.6, 0.9)
+ call gseti (gp, G_ROUND, YES)
+
+ call glabax (gp, "Residual Intensity\n (Known - Calculated)",
+ "Density", "")
+ call gpline (gp, density, Memr[resid], nvalues)
+
+ call sfree (sp)
+end
+
+
+# ST_WLUT -- Generate look up table, using technique of HDTOI.
+
+procedure st_wlut (lut, min, max, scale, cfit)
+
+real lut[ARB] # Look up table of intensities
+int min # Minimum raw data value
+int max # Maximum raw data value
+real scale # Density = raw_value * scale
+real cfit[ARB] # Coefficient array for restoring curfit
+
+pointer cv, sp, den, indv, kv
+int nvalues, i
+extern hd_powerr()
+
+begin
+ call smark (sp)
+ nvalues = max - min + 1
+ call salloc (den, nvalues, TY_REAL)
+ call salloc (indv, nvalues, TY_REAL)
+ call salloc (kv, nvalues, TY_REAL)
+ do i = 1, nvalues
+ Memr[kv+i-1] = real (i)
+
+ call amulkr (Memr[kv], scale, Memr[den], nvalues)
+
+ call cvrestore (cv, cfit)
+ call cvuserfnc (cv, hd_powerr)
+
+ call hd_aptrans (Memr[den], Memr[indv], nvalues, "logo")
+ call cvvector (cv, Memr[indv], lut, nvalues)
+ do i = 1, nvalues
+ lut[i] = 10.0 ** lut[i]
+
+ call cvfree (cv)
+ call sfree (sp)
+end
+
+
+# ST_TRANSFORM -- Apply transformation from look up table to input vector.
+
+procedure st_transform (min, max, lut, nvalues, intc)
+
+int min # Minimum raw data value
+int max # Maximum raw data value
+real lut[ARB] # Array of intensity values
+int nvalues # Number of density, intensity values
+real intc[ARB] # Calculated intensities - returned
+
+int i
+
+begin
+ do i = 1, nvalues
+ intc[i] = lut[i]
+end
diff --git a/noao/imred/dtoi/spotlist.par b/noao/imred/dtoi/spotlist.par
new file mode 100644
index 00000000..8134c8de
--- /dev/null
+++ b/noao/imred/dtoi/spotlist.par
@@ -0,0 +1,8 @@
+# The cl parameters for task spotlist in the dtoi package
+spots,f,a,,,,List of image files containing spot data
+fogs,f,a,,,,List of images containing fog spots
+database,f,a,,,,Name of output database file
+scale,r,h,0.00151,,,Input value to density scale factor
+maxad,i,h,3071,,,Integer A/D value of saturated pixel
+sigma,r,h,3.0,,,Rejection criteria when determining mean density
+option,s,h,mean,"mean|median",,Choice of algorithm (mean or median)
diff --git a/noao/imred/dtoi/spotlist.x b/noao/imred/dtoi/spotlist.x
new file mode 100644
index 00000000..8f4ffeee
--- /dev/null
+++ b/noao/imred/dtoi/spotlist.x
@@ -0,0 +1,395 @@
+include <error.h>
+include <imhdr.h>
+include <mach.h>
+include <fset.h>
+
+# T_SPOTLIST -- calculates the densities and standard deviations of calibration
+# spots read in as IRAF images. Entries for density, sdev, spot number
+# and number of pixels used in the average are made in the output database.
+# These values are entered for all spots and the fog level. The
+# fog level is calculated but not subtracted in this procedure.
+
+procedure t_spotlist ()
+
+pointer db, sp, den, ngpix, sdev, dloge, option, npix
+int spot_fd, fog_fd, fngpix, nspots, maxad, fnpix
+real scale, sigma, fsdev, fog
+double maxden
+
+pointer ddb_map()
+int imtopenp(), imtlen(), clgeti(), strncmp()
+real clgetr()
+
+begin
+ call smark (sp)
+ call salloc (dloge, SZ_FNAME, TY_CHAR)
+ call salloc (option, SZ_FNAME, TY_CHAR)
+
+ # Get parameters and open file name templates
+ spot_fd = imtopenp ("spots")
+ fog_fd = imtopenp ("fogs")
+ call clgstr ("database", Memc[dloge], SZ_FNAME)
+ scale = clgetr ("scale")
+ maxad = clgeti ("maxad")
+ sigma = clgetr ("sigma")
+ call clgstr ("option", Memc[option], SZ_FNAME)
+
+ maxden = maxad * double (scale)
+
+ # Allocate space for density, standard deviation and ngpix arrays
+ nspots = imtlen (spot_fd)
+ call salloc ( den, nspots, TY_REAL)
+ call salloc (sdev, nspots, TY_REAL)
+ call salloc (ngpix, nspots, TY_INT)
+ call salloc ( npix, nspots, TY_INT)
+
+ # Calculate densities depending on algorithm option. The
+ # number of saturated pixels per spot is also calculated now.
+
+ if (strncmp (Memc[option], "median", 3) == 0)
+ call hd_median (spot_fd, Memr[den], Memr[sdev], Memi[ngpix],
+ nspots, scale, Memi[npix])
+ else
+ call hd_mean (spot_fd, Memr[den], Memr[sdev], Memi[ngpix],
+ nspots, scale, sigma, Memi[npix])
+
+ # Calculate fog level and count saturated pixels
+ call hd_fogcalc (fog_fd, fog, fsdev, fngpix, scale, sigma,
+ Memc[option], fnpix)
+
+ # Now print results to stdout
+ call hd_printit (Memr[den], Memr[sdev], Memi[npix], Memi[ngpix],
+ fog, fsdev, fnpix, fngpix, nspots)
+
+ # Open output database file and write spot information
+ db = ddb_map (Memc[dloge], APPEND)
+ call hd_wspotdb (db, Memr[den], Memr[sdev], Memi[ngpix], nspots)
+
+ # Write fog information to database as single record
+ call ddb_prec (db, "fog")
+ call ddb_putr (db, "density", fog)
+ call ddb_putr (db, "sdev", fsdev)
+ call ddb_puti (db, "ngpix", fngpix)
+
+ # Scale info gets written to database also (very precisely!)
+ call ddb_prec (db, "common")
+ call ddb_putr (db, "scale", scale)
+ call ddb_putd (db, "maxden", maxden)
+ call ddb_pstr (db, "option", Memc[option])
+
+ call ddb_unmap (db)
+
+ call imtclose (spot_fd)
+ call imtclose (fog_fd)
+ call sfree (sp)
+end
+
+
+# HD_MEAN -- Calculate mean density of calibration spots.
+
+procedure hd_mean (spot_fd, den, sdev, ngpix, nspots, scale, sigma, npix)
+
+int spot_fd # File descriptor for list of spots
+real den[ARB] # Mean density values - filled on return
+real sdev[ARB] # Standard deviation array - filled on return
+int ngpix[ARB] # Number of unrejected pixels - filled on return
+int nspots # Number of spots in list
+real scale # Scale for voltage to density conversion
+real sigma # Rejection criteria set by user
+int npix[ARB] # Number of pixels per spot
+
+pointer im, spot, sp, pix
+int i, junk, ncols, nlines
+pointer immap(), imgs2r()
+int imtgetim(), hd_aravr()
+errchk imgs2r, amulkr, hd_aravr
+
+begin
+ call smark (sp)
+ call salloc (spot, SZ_FNAME, TY_CHAR)
+
+ # Loop over spot rasters. Calculate density and standard deviation.
+ for (i = 1; i <= nspots; i = i + 1) {
+ junk = imtgetim (spot_fd, Memc[spot], SZ_FNAME)
+ iferr (im = immap (Memc[spot], READ_ONLY, 0)) {
+ call erract (EA_WARN)
+ next
+ }
+
+ ncols = IM_LEN(im,1)
+ nlines = IM_LEN(im,2)
+ npix[i] = ncols * nlines
+
+ # For all pixels in the image, scale the a/d value to density and
+ # calculate the mean value, using a mean rejection algorithm.
+
+ pix = imgs2r (im, 1, ncols, 1, nlines)
+ call amulkr (Memr[pix], scale, Memr[pix], npix[i])
+ ngpix[i] = hd_aravr (Memr[pix], npix[i], den[i], sdev[i], sigma)
+ call imunmap (im)
+ }
+
+ call sfree (sp)
+end
+
+
+# HD_MEDIAN -- Calculate median density of calibration spots.
+
+procedure hd_median (spot_fd, den, sdev, ngpix, nspots, scale, npix)
+
+int spot_fd # File descriptor for list of spots
+real den[ARB] # Mean density values - filled on return
+real sdev[ARB] # Standard deviation of input spots
+int ngpix[ARB] # Number of pixels not rejected
+int nspots # Number of spots in list
+real scale # Scale for voltage to density conversion
+int npix[ARB] # Number of pixels per spot
+
+pointer im, spot, sp, pix
+int i, junk, ncols, nlines
+real junk_mean
+pointer immap(), imgs2r()
+int imtgetim()
+real amedr()
+errchk imgs2r, amulkr, amedr
+
+begin
+ call smark (sp)
+ call salloc (spot, SZ_FNAME, TY_CHAR)
+
+ # Loop over spot rasters. Calculate density and standard deviation.
+ for (i = 1; i <= nspots; i = i + 1) {
+ junk = imtgetim (spot_fd, Memc[spot], SZ_FNAME)
+ iferr (im = immap (Memc[spot], READ_ONLY, 0)) {
+ call erract (EA_WARN)
+ next
+ }
+
+ ncols = IM_LEN(im,1)
+ nlines = IM_LEN(im,2)
+ npix[i] = ncols * nlines
+
+ # For all pixels in the image, scale the a/d value to density and
+ # calculate the median value. For the user's information, the
+ # sigma is also calculated in a call to aavgr.
+
+ pix = imgs2r (im, 1, ncols, 1, nlines)
+ call amulkr (Memr[pix], scale, Memr[pix], npix[i])
+ den[i] = amedr (Memr[pix], npix[i])
+ ngpix[i] = npix[i]
+ call aavgr (Memr[pix], npix[i], junk_mean, sdev[i])
+ call imunmap (im)
+ }
+
+ call sfree (sp)
+end
+
+
+# HD_FOGCALC -- Calculate fog density.
+
+procedure hd_fogcalc (fog_fd, fog, fsdev, fngpix, scale, sigma, option, nfpix)
+
+int fog_fd # File descriptor for list of fog spots
+real fog # Mean fog value - returned
+real fsdev # Standard deviation - returned
+int fngpix # Number of pixels used - returned
+real scale # Voltage to density scaling factor
+real sigma # Rejection criteria - set by user
+char option[ARB] # User's choice of mean/median algorithm
+int nfpix # Total number of fog pixels
+
+pointer pix, im, sp, fogfile, ptr
+int nfog, maxfog, i, junk, ncols, nlines, npix, total_pix, op
+real junk_mean
+pointer immap(), imgs2r()
+int imtlen(), imtgetim(), hd_aravr(), strncmp()
+real amedr()
+errchk calloc, imgs2r, aaddr, amulkr, hd_aravr
+
+begin
+ call smark (sp)
+ call salloc (fogfile, SZ_FNAME, TY_CHAR)
+
+ pix = NULL
+ total_pix = 0
+ op = 0
+ nfog = imtlen (fog_fd)
+ maxfog = nfog
+ do i = 1, maxfog {
+ junk = imtgetim (fog_fd, Memc[fogfile], SZ_FNAME)
+ iferr (im = immap (Memc[fogfile], READ_ONLY, 0)) {
+ call erract (EA_WARN)
+ nfog = nfog - 1
+ next
+ }
+
+ ncols = IM_LEN(im,1)
+ nlines = IM_LEN(im,2)
+ npix = ncols * nlines
+ total_pix = total_pix + npix
+
+ if (pix == NULL)
+ # Initialize space for accumulating pixels
+ call calloc (pix, npix, TY_REAL)
+ else
+ # Increase space for accumulating pixels
+ call realloc (pix, total_pix, TY_REAL)
+
+ # Build up vector of fog pixels
+ ptr = imgs2r (im, 1, ncols, 1, nlines)
+ call amovr (Memr[ptr], Memr[pix+op], npix)
+ op = op + npix
+
+ call imunmap (im)
+ }
+
+ # Scale values to density and calculate fog and std deviation
+
+ if (nfog > 0) {
+# 7 Sept 1989, S. Rooke: in Suzanne's absence, made following bugfix after
+# bug reported by Steve Majewski that fog values are off by 1/n images where
+# multiple fog images are used in a single run. The total_pix already contains
+# the sum of all pixel values, so the fog pixel values should not be divided
+# by nfog. This should be verified by Suzanne on her return, and these comments
+# removed.
+# call amulkr (Memr[pix], scale / real (nfog), Memr[pix], total_pix)
+ call amulkr (Memr[pix], scale, Memr[pix], total_pix)
+ if (strncmp (option, "median", 3) == 0) {
+ fog = amedr (Memr[pix], total_pix)
+ fngpix = total_pix
+ call aavgr (Memr[pix], total_pix, junk_mean, fsdev)
+ } else
+ fngpix = hd_aravr (Memr[pix], total_pix, fog, fsdev, sigma)
+ } else {
+ fog = 0.0
+ fsdev = 0.0
+ fngpix = 0
+ }
+ nfpix = total_pix
+
+ call mfree (pix, TY_REAL)
+ call sfree (sp)
+end
+
+
+# HD_WSPOTDB -- Write spot information to database file. Values are first
+# sorted in order of increasing density.
+
+procedure hd_wspotdb (db, density, sdev, ngpix, nspots)
+
+pointer db # Pointer to database
+real density[ARB] # Array of densities
+real sdev [ARB] # Array of standard deviations
+int ngpix [ARB] # Array of npix used in calculations
+int nspots # Number of density spots
+
+begin
+ if (density[1] > density[nspots]) {
+ # Need to reorder arrays
+ call hd_reorderr (density, nspots)
+ call hd_reorderr ( sdev, nspots)
+ call hd_reorderi ( ngpix, nspots)
+ }
+
+ call ddb_ptime (db)
+
+ # Density record
+ call ddb_prec (db, "density")
+ call ddb_par (db, "den_val", density, nspots)
+
+ # Standard deviation of density is written to a record
+ call ddb_prec (db, "standard deviation")
+ call ddb_par (db, "sdev_val", sdev, nspots)
+
+ # Record for npix_used
+ call ddb_prec (db, "ngpix")
+ call ddb_pai (db, "npix_val", ngpix, nspots)
+end
+
+
+# HD_REORDERR - Flip order of real array in place.
+
+procedure hd_reorderr (array, nvals)
+
+real array[ARB] # Real array to be reordered
+int nvals # Number of elements in array
+
+pointer sp, tmp
+int i
+
+begin
+ call smark (sp)
+ call salloc (tmp, nvals, TY_REAL)
+
+ call amovr (array, Memr[tmp], nvals)
+ do i = 1, nvals
+ array[i] = Memr[tmp+nvals-i]
+
+ call sfree (sp)
+end
+
+
+# HD_REORDERI -- Flip order of integer array in place.
+
+procedure hd_reorderi (array, nvals)
+
+int array[ARB] # Integer array to be ordered
+int nvals # Number of elements in array
+
+pointer sp, tmp
+int i
+
+begin
+ call smark (sp)
+ call salloc (tmp, nvals, TY_INT)
+
+ call amovi (array, Memi[tmp], nvals)
+ do i = 1, nvals
+ array[i] = Memi[tmp+nvals-i]
+
+ call sfree (sp)
+end
+
+
+# HD_PRINTIT -- Neatly printout all the accumulated information.
+
+procedure hd_printit (den, sdev, npix, ngpix, fog, fsdev, fnpix, fngpix, nspots)
+
+real den[ARB] # density array
+real sdev[ARB] # std deviation array
+int npix[ARB] # npix array
+int ngpix[ARB] # ngoodpix array
+real fog # fog value
+real fsdev # std deviation of fog
+int fnpix # npix in fog
+int fngpix # ngoodpix in fog
+int nspots # number of spots
+int i
+
+begin
+
+ call fseti (STDOUT, F_FLUSHNL, YES)
+
+ call printf ("\n # Number of P")
+ call printf ("ixels\n")
+ call printf ("# Spot Number Density Std Deviation Total Used Rej")
+ call printf ("ected \n")
+
+ do i = 1, nspots {
+ call printf (" %d %17t%.4f %27t%.4f %43t%d %5d %6d \n")
+ call pargi (i)
+ call pargr (den[i])
+ call pargr (sdev[i])
+ call pargi (npix[i])
+ call pargi (ngpix[i])
+ call pargi (npix[i] - ngpix[i])
+ }
+
+ call printf (" FOG %17t%.4f %27t%.4f %43t%d %5d %6d \n")
+ call pargr (fog)
+ call pargr (fsdev)
+ call pargi (fnpix)
+ call pargi (fngpix)
+ call pargi (fnpix - fngpix)
+
+end
diff --git a/noao/imred/dtoi/x_dtoi.x b/noao/imred/dtoi/x_dtoi.x
new file mode 100644
index 00000000..5fd0cc72
--- /dev/null
+++ b/noao/imred/dtoi/x_dtoi.x
@@ -0,0 +1,6 @@
+task spotlist = t_spotlist,
+ hdfit = t_hdfit,
+ hdshift = t_hdshift,
+ hdtoi = t_hdtoi,
+ dematch = t_dematch,
+ selftest = t_selftest