diff options
author | Joseph Hunkeler <jhunkeler@gmail.com> | 2015-07-08 20:46:52 -0400 |
---|---|---|
committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2015-07-08 20:46:52 -0400 |
commit | fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4 (patch) | |
tree | bdda434976bc09c864f2e4fa6f16ba1952b1e555 /noao/twodspec/multispec | |
download | iraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz |
Initial commit
Diffstat (limited to 'noao/twodspec/multispec')
84 files changed, 12104 insertions, 0 deletions
diff --git a/noao/twodspec/multispec/Revisions b/noao/twodspec/multispec/Revisions new file mode 100644 index 00000000..1e62477c --- /dev/null +++ b/noao/twodspec/multispec/Revisions @@ -0,0 +1,28 @@ +.help revisions Jun88 noao.twodspec.multispec +.nf +The multispec package is no longer compiled and defined. The source code +will someday be revised and the capabilities of tracing and deblending +will be returned. (8/23/90, Valdes) + +==== +V2.9 +==== + +noao$twodspec/multispec/t_fitgauss5.x + Valdes, Oct. 3, 1986 + 1. Missing third argument to msmap. Found in the AOS port. + +==================================== +Version 2.3 Release, August 18, 1986 +==================================== + +From Valdes Oct. 23, 1985: + +1. Recoded msio.x and dbio.x to remove entry statements and instead use +separate procedures with a common block. +------ +From Valdes Oct. 11, 1985: + +1. The MSPLOT script using PLOT.GRAPH has been removed and an interactive +task based on GIO has replaced it. +.endhelp diff --git a/noao/twodspec/multispec/_msfindspec1.cl b/noao/twodspec/multispec/_msfindspec1.cl new file mode 100644 index 00000000..1d9ae624 --- /dev/null +++ b/noao/twodspec/multispec/_msfindspec1.cl @@ -0,0 +1,41 @@ +#{ _MSFINDSPEC1 -- Create a new database, find the peaks, trace, and fit a +# function. + +#image,f,a,,,,Image +#sample_lines,s,a,"10x50",,,Sample image lines +#start,i,a,1,,,Starting image line +#min_nspectra,i,a,1,,,Minimum number of spectra to be found +#max_nspectra,i,a,100,,,Maximum number of spectra to be found +#separation,i,a,20,,,Minimum separation between spectra +#threshold,r,a,0.,,,Minimum peak threshold for selecting spectra +#contrast,r,a,0.1,,,Maximum contrast between peaks +#width,r,a,10,,,Width of spectra +#naverage,i,a,20,1,,Number of lines to average +#verbose,b,a,no,,,Verbose output? + +{ + # Verbose message. + if (verbose) { + time + print (" Find the spectra in ", image, ".") + } + + # Create a new database. + newextraction (image, "", sample_lines=sample_lines) + + # Find the peaks. + findpeaks (image, start, contrast, separation=separation, + threshold=threshold, min_npeaks=min_nspectra, edge=width/3, + max_npeaks=max_nspectra, naverage=naverage) + + # Initialize the model parameters and fit the model with tracking. + msset (image, "s0", 1., lines=start) + msset (image, "s1", 0., lines=start) + msset (image, "s2", 0., lines=start) + fitgauss5 (image, start, lower=-width/2, upper=width/2, + lines="*", spectra="*", naverage=naverage, track=yes, + algorithm=2) + + # Fit the default interpolation function to the positions. + fitfunction (image, parameter="x0", lines="*", spectra="*") +} diff --git a/noao/twodspec/multispec/_msfindspec1.par b/noao/twodspec/multispec/_msfindspec1.par new file mode 100644 index 00000000..5263bedb --- /dev/null +++ b/noao/twodspec/multispec/_msfindspec1.par @@ -0,0 +1,15 @@ + +# _MSFINDSPEC1 -- Create a new database, find the peaks, trace, and fit a +# function. + +image,f,a,,,,Image +sample_lines,s,a,"10x50",,,Sample image lines +start,i,a,1,,,Starting image line +min_nspectra,i,a,1,,,Minimum number of spectra to be found +max_nspectra,i,a,100,,,Maximum number of spectra to be found +separation,i,a,20,,,Minimum separation between spectra +threshold,r,a,0.,,,Minimum peak threshold for selecting spectra +contrast,r,a,0.1,,,Maximum contrast between peaks +width,r,a,10,,,Width of spectra +naverage,i,a,20,1,,Number of lines to average +verbose,b,a,no,,,Verbose output? diff --git a/noao/twodspec/multispec/_msfindspec2.cl b/noao/twodspec/multispec/_msfindspec2.cl new file mode 100644 index 00000000..d09212fc --- /dev/null +++ b/noao/twodspec/multispec/_msfindspec2.cl @@ -0,0 +1,28 @@ +#{ _MSFINDSPEC2 -- Create a new database, initialize with a template +# image, refine the positions, and fit a position function. + +#image,f,a,,,,Image +#template,f,a,,,,Template image +#width,r,a,10,,,Width of spectra +#naverage,i,a,20,1,,Number of lines to average +#verbose,b,a,no,,,Verbose output? + +{ + # Verbose message. + if (verbose) { + time + print (" Find the spectra in ", image, " using template image ", + template, ".") + } + + # Create a new database and initialize with a template image. + newextraction (image, template) + + # Refit the model. + fitgauss5 (image, 1, lower=-width/2, upper=width/2, + lines="*", spectra="*", naverage=naverage, track=no, + algorithm=2) + + # Fit the default interpolation function to the positions. + fitfunction (image, parameter="x0", lines="*", spectra="*") +} diff --git a/noao/twodspec/multispec/_msfindspec2.par b/noao/twodspec/multispec/_msfindspec2.par new file mode 100644 index 00000000..d9e10b5d --- /dev/null +++ b/noao/twodspec/multispec/_msfindspec2.par @@ -0,0 +1,8 @@ +# _MSFINDSPEC2 -- Create a new database, initialize with a template +# image, refine the positions, and fit a position function. + +image,f,a,,,,Image +template,f,a,,,,Template image +width,r,a,10,,,Width of spectra +naverage,i,a,20,1,,Number of lines to average +verbose,b,a,no,,,Verbose output? diff --git a/noao/twodspec/multispec/_msfindspec3.cl b/noao/twodspec/multispec/_msfindspec3.cl new file mode 100644 index 00000000..d8150a90 --- /dev/null +++ b/noao/twodspec/multispec/_msfindspec3.cl @@ -0,0 +1,22 @@ +#{ _MSFINDSPEC3 -- Refine the model and fit a position function. + +#image,f,a,,,,Image +#width,r,a,10,,,Width of spectra +#naverage,i,a,20,1,,Number of lines to average +#verbose,b,a,no,,,Verbose output? + +{ + # Verbose message. + if (verbose) { + time + print (" Refit the spectra in ", image, ".") + } + + # Refit the model. + fitgauss5 (image, 1, lower=-width/2, upper=width/2, + lines="*", spectra="*", naverage=naverage, track=no, + algorithm=2) + + # Fit the default interpolation function to the positions. + fitfunction (image, parameter="x0", lines="*", spectra="*") +} diff --git a/noao/twodspec/multispec/_msfindspec3.par b/noao/twodspec/multispec/_msfindspec3.par new file mode 100644 index 00000000..fccb3d23 --- /dev/null +++ b/noao/twodspec/multispec/_msfindspec3.par @@ -0,0 +1,6 @@ +# _MSFINDSPEC3 -- Refine the model and fit a position function. + +image,f,a,,,,Image +width,r,a,10,,,Width of spectra +naverage,i,a,20,1,,Number of lines to average +verbose,b,a,no,,,Verbose output? diff --git a/noao/twodspec/multispec/armsr.x b/noao/twodspec/multispec/armsr.x new file mode 100644 index 00000000..2f9ce657 --- /dev/null +++ b/noao/twodspec/multispec/armsr.x @@ -0,0 +1,44 @@ +# ARMSR -- Compute the rms of an array. + +real procedure armsr (a, npoints) + +real a[ARB] # Return rms of this array +int npoints # Number of points in the array + +int i +real avg, rms + +begin + avg = 0. + rms = 0. + do i = 1, npoints { + avg = avg + a[i] + rms = rms + a[i] * a[i] + } + rms = sqrt ((npoints * rms - avg * avg) / (npoints * (npoints - 1))) + + return (rms) +end + + +# ARMSRR -- Compute the vector rms between two real arrays. + +real procedure armsrr (a, b, npoints) + +real a[ARB] # First array +real b[ARB] # Second array +int npoints # Number of points + +int i +real residual, rms + +begin + rms = 0. + do i = 1, npoints { + residual = a[i] - b[i] + rms = rms + residual ** 2 + } + rms = sqrt (rms / npoints) + + return (rms) +end diff --git a/noao/twodspec/multispec/clinput.x b/noao/twodspec/multispec/clinput.x new file mode 100644 index 00000000..163c8354 --- /dev/null +++ b/noao/twodspec/multispec/clinput.x @@ -0,0 +1,28 @@ +# Specialized CL get routines. + + +# CLGRANGES -- Get a range. A range string is input and the string is +# decoded into a range array. The number of values in the range array is +# returned by the function. + +int procedure clgranges (param, min_value, max_value, ranges, max_ranges) + +char param[ARB] +int min_value +int max_value +int ranges[ARB] +int max_ranges + +char str[SZ_LINE] +int n + +int decode_ranges() + +begin + call clgstr (param, str, SZ_LINE) + + if (decode_ranges (str,ranges,max_ranges,min_value,max_value,n) == ERR) + call error (0, "Error in range string") + + return (n) +end diff --git a/noao/twodspec/multispec/dbio/dbio.h b/noao/twodspec/multispec/dbio/dbio.h new file mode 100644 index 00000000..dd9f65f1 --- /dev/null +++ b/noao/twodspec/multispec/dbio/dbio.h @@ -0,0 +1,24 @@ + +# Definitions for subset DBIO + +define SZ_DB_KEY 79 # Size of database reference keys +define MAX_DB_DES 10 # Maximum number of DBIO descriptors +define DB_ERRCODE 1000 # Start of DBIO error codes + +# DBIO descriptor + +define LEN_DB_DES 3 + +define DB_FD Memi[$1] # The database FIO descriptor +define DB_DIC Memi[$1+1] # Pointer to the dictionary memory +define DB_UPDATE Memi[$1+2] # Has dictionary been change [y/n] + +# DBIO dictionary entry. Each entry is referenced with the pointer to the +# dictionary memory ($1) and the entry number ($2). + +define LEN_DB_ENTRY 43 + +define DB_KEY Memi[$1+($2-1)*LEN_DB_ENTRY] # Key +define DB_OFFSET Meml[$1+($2-1)*LEN_DB_ENTRY+40] # File Offset +define DB_SZ_ELEM Memi[$1+($2-1)*LEN_DB_ENTRY+41] # Element size +define DB_DIM Memi[$1+($2-1)*LEN_DB_ENTRY+42] # Number of elements diff --git a/noao/twodspec/multispec/dbio/dbio.x b/noao/twodspec/multispec/dbio/dbio.x new file mode 100644 index 00000000..faa21cef --- /dev/null +++ b/noao/twodspec/multispec/dbio/dbio.x @@ -0,0 +1,564 @@ + +include <fset.h> +include <error.h> +include "dbio.h" + +.help dbio 2 "Subset Database I/O Procedures" +.sh +1. Introduction + + These DBIO procedures are a subset of the general +DBIO design described in "Specifications of the IRAF DBIO Interface" by +Doug Tody (Oct 1983). It is designed to allow programs written using +the subset DBIO to be easily converted to the full DBIO. It's features +are: +.ls 4 1. +Database open and close. +.le +.ls 4 2. +Reference to entries by a (possibly) subscripted record name string. +.le +.ls 4 3. +Ability to add new record types as desired. +.le +.ls 4 4. +Error recovery procedure to cleanup after an uncaught error. +.le + +The primary limitations are: +.ls 4 1. +No aliases. +.le +.ls 4 2. +No datatyping and no self-describing structures. +.le +.ls 4 3. +No deletions of entries. +.le +.sh +2. Procedures + +.nf + db = dbopen (file_name, mode, max_entries) + db = dbreopen (db) + dbclose (db) + dbenter (db, record_name, sz_elem, nreserve) + y/n = dbaccess (db, record_name) + nread = dbread (db, reference, buf, maxelems) + dbwrite (db, reference, buf, nelems) +.fi + + A new, empty database is created by opening with access modes NEW_FILE +or TEMP_FILE. The dictionary will be intialized to allow max_entries +number of dictionary entries. The other legal access modes are READ_ONLY and +READ_WRITE. The max_entries argument is not used with these modes. To create +a new entry in the database the name of the record, the size of a record +element, and the maximum number of such records to be stored are specified. +This differs from the full DBIO specification in that a record is described +only by a size instead of a datatype. Also it is not possible to increase +the number of elements once it has been entered. The database read and +write procedures do no type conversion. They read procedure returns +the number of elements read. If a reference is not found in the +dictionary in either reading or writing an error condition occurs. +Also an attempt to read or write an element exceeding the dimension +entered in the dictionary will create an error condition. +.endhelp + + +# DBOPEN, DBREOPEN -- Open a database file. + +pointer procedure dbopen (file_name, ac_mode, db_nentries) + +# Procedure dbopen parameters: +char file_name[SZ_FNAME] # Database filename +int ac_mode # Access mode (new,temp,r,rw) +int db_nentries # Creation dictionary size + +# Entry dbreopen parameters: +pointer dbreopen # Function type +pointer db_old # Old database descriptor + +int mode +pointer fd, db # FIO descriptor and DBIO descriptor +pointer dic +int nelem, nentries + +bool strne() +int open(), dbread(), reopen() +errchk db_getdes, calloc, dbenter, dbread, db_init + +begin + # Check for valid access mode. Valid modes require read permission. + # If a valid access mode open database with FIO. + mode = ac_mode + if ((mode == WRITE_ONLY) || (mode == APPEND)) + call error (DB_ERRCODE + 0, "Invalid database access mode") + fd = open (file_name, mode, BINARY_FILE) + goto 10 + +entry dbreopen (db_old) + + fd = reopen (DB_FD(db_old), mode) + + # Get DBIO descriptor +10 call db_getdes (db) + DB_FD(db) = fd + + # If the database is being created enter the dictionary in the file. + # If the database already exists read the current dictionary and + # check to see if the file is a database. + switch (mode) { + case NEW_FILE, TEMP_FILE: + # Allocate dictionary space and enter it in the database. + # The request entries is increased by one for the dictionary + # database entry itself. + nentries = db_nentries + 1 + call calloc (dic, nentries * LEN_DB_ENTRY, TY_STRUCT) + DB_DIC(db) = dic + call dbenter (db, "db_dictionary", LEN_DB_ENTRY * SZ_STRUCT, + nentries) + case READ_ONLY, READ_WRITE: + # Read dictionary. + call db_init (db, 1) + dic = DB_DIC(db) + nelem = dbread (db, "db_dictionary", Memi[dic], 1) + if (nelem != 1) + call error (DB_ERRCODE + 1, "Error reading database dictionary") + if (strne (DB_KEY(dic, 1), "db_dictionary")) + call error (DB_ERRCODE + 2, "File is not a database") + + nentries = DB_DIM(dic, 1) + call db_init (db, nentries) + dic = DB_DIC(db) + nelem = dbread (db, "db_dictionary", Memi[dic], nentries) + if (nelem != nentries) + call error (DB_ERRCODE + 3, "Error reading database dictionary") + } + + return (db) +end + + +# DB_INIT -- Initialize the program dictionary space + +procedure db_init (db, db_nentries) + +pointer db +int db_nentries + +pointer dic + +long note() +errchk mfree, calloc, seek + +begin + # Allocate dictionary memory + dic = DB_DIC(db) + if (dic != NULL) + call mfree (dic, TY_STRUCT) + call calloc (dic, db_nentries * LEN_DB_ENTRY, TY_STRUCT) + DB_DIC(db) = dic + + # Fill in dictionary entry + call strcpy ("db_dictionary", DB_KEY(dic, 1), SZ_DB_KEY) + DB_SZ_ELEM(dic, 1) = LEN_DB_ENTRY * SZ_STRUCT + DB_DIM(dic, 1) = db_nentries + call seek (DB_FD(db), BOF) + DB_OFFSET(dic, 1) = note (DB_FD(db)) +end + +# DBENTER -- Make a new entry in the database dictionary and reserve +# file space in the database. + +procedure dbenter (db, record_name, sz_elem, nreserve) + +pointer db # DBIO descriptor +char record_name[SZ_DB_KEY] # Record name string +int sz_elem # Size of record element in CHARS +int nreserve # Number of record elements to reserve + +int i +int sz_reserve, sz_buf +pointer dic, buf + +bool streq() +int fstati() +long note() + +errchk calloc, dbclose, write, seek + +begin + # Check access mode + if (fstati(DB_FD(db), F_WRITE) == NO) + call error (DB_ERRCODE + 4, "Database is read only") + + # Find the last entry. Check for attempts to redefine an + # entry and to overflow the dictionary. + dic = DB_DIC(db) + for (i = 1; i <= DB_DIM(dic, 1); i = i + 1) { + if (DB_DIM(dic, i) == 0) + break + if (streq (record_name, DB_KEY(dic, i))) + call error (DB_ERRCODE + 5, "Attempt to redefine dictionary entry") + } + if ((i > 1) && (i > DB_DIM(dic, 1))) + call error (DB_ERRCODE + 6, "Database dictionary is full") + + # Make dictionary entry + call strcpy (record_name, DB_KEY(dic, i), SZ_DB_KEY) + DB_SZ_ELEM(dic, i) = sz_elem + DB_DIM(dic, i) = nreserve + call seek (DB_FD(db), EOF) + DB_OFFSET(dic, i) = note (DB_FD(db)) + DB_UPDATE(db) = YES + + # Initialize file space to zero. Zero file blocks for efficiency. + sz_reserve = sz_elem * nreserve + sz_buf = min (fstati (DB_FD(db), F_BLKSIZE), sz_reserve) + call calloc (buf, sz_buf, TY_CHAR) + + while (sz_reserve > 0) { + call write (DB_FD(db), Memc[buf], sz_buf) + sz_reserve = sz_reserve - sz_buf + sz_buf = min (sz_buf, sz_reserve) + } + call mfree (buf, TY_CHAR) +end + +# DBACCESS -- Is data reference in the database? + +bool procedure dbaccess (db, record_name) + +pointer db # DBIO descriptor +char record_name[SZ_DB_KEY] # Record name string + +int i +pointer dic + +bool streq() + +begin + dic = DB_DIC(db) + for (i = 1; i <= DB_DIM(dic, 1); i = i + 1) { + if (DB_DIM(dic, i) == 0) + return (FALSE) + if (streq (record_name, DB_KEY(dic, i))) + return (TRUE) + } + return (FALSE) +end + + +# DBNEXTNAME -- Return name of the next dictionary entry. + +int procedure dbnextname (db, previous, outstr, maxch) + +pointer db # DBIO descriptor +char previous[ARB] +char outstr[ARB] +int maxch + +int i +pointer dic + +bool streq(), strne() + +begin + dic = DB_DIC(db) + i = 1 + if (strne (previous, "")) { + for (; i <= DB_DIM(dic, 1); i = i + 1) { + if (DB_DIM(dic, i) == 0) + return (EOF) + if (streq (previous, DB_KEY(dic, i))) + break + } + } + i = i + 1 + if ((i > DB_DIM(dic, 1)) || (DB_DIM(dic, i) == 0)) + return (EOF) + else + call strcpy (DB_KEY(dic, i), outstr, maxch) + + return (OK) +end + + +#DBREAD - Read data from the database. +# The number of data elements read is returned. + +int procedure dbread (db, ref, buf, maxelems) + +pointer db # Database file descriptor +char ref[ARB] # Data reference +char buf[ARB] # Data buffer +int maxelems # Number of elements to be read + +int i, j +int stat, sz_elem, index, nread +long offset +pointer dic + +int strncmp(), strlen(), stridxs(), ctoi() +bool streq() +int read() +errchk read, dbclose + +begin + dic = DB_DIC(db) + + # Decode the data reference and set the file offset and the size + # of the data element. If a valid data reference is not found + # then a read status of 0 is returned. + + j = stridxs ("[", ref) + for (i = 1; i <= DB_DIM(dic, 1); i = i + 1) { + if (DB_DIM(dic, i) == 0) + call error (DB_ERRCODE + 7, "Database request not found") + if (j == 0) { + if (streq (ref, DB_KEY(dic, i))) + break + } else { + if (strlen (DB_KEY(dic, i)) == j - 1) + if (strncmp (ref, DB_KEY(dic, i), j - 1) == 0) + break + } + } + + offset = DB_OFFSET(dic, i) + sz_elem = DB_SZ_ELEM(dic, i) + nread = maxelems + if (j > 0) { + j = ctoi (ref, j + 1, index) + if (j > 0) { + if (maxelems > DB_DIM(dic, i) - index + 1) { + call error (DB_ERRCODE + 8, "Database request out of bounds") + } + offset = offset + (index - 1) * sz_elem + } + } + + # Seek and read the data + call seek (DB_FD(db), offset) + stat = read (DB_FD(db), buf, sz_elem * nread) / sz_elem + return (stat) +end + + +# DBWRITE - Write data to the database. + +procedure dbwrite (db, ref, buf, nelems) + +pointer db # DBIO descriptor +char ref[ARB] # Data reference +char buf[ARB] # Data buffer +int nelems # Number of elements to written + +int i, j +int sz_elem, index, nwritten +long offset +pointer dic + +int strncmp(), strlen(), stridxs(), ctoi() +bool streq() +errchk write, dbclose + +begin + dic = DB_DIC(db) + + # Decode the data reference and set the file offset and the size + # of the data element. If a valid data reference is not found + # then the data is not written and a write status of 0 is returned. + + j = stridxs ("[", ref) + for (i = 1; i <= DB_DIM(dic, 1); i = i + 1) { + if (DB_DIM(dic, i) == 0) + call error (DB_ERRCODE + 9, "Database request not found") + if (j == 0) { + if (streq (ref, DB_KEY(dic, i))) + break + } else { + if (strlen (DB_KEY(dic, i)) == j - 1) + if (strncmp (ref, DB_KEY(dic, i), j - 1) == 0) + break + } + } + + offset = DB_OFFSET(dic, i) + sz_elem = DB_SZ_ELEM(dic, i) + nwritten = nelems + if (j > 0) { + j = ctoi (ref, j + 1, index) + if (j > 0) { + if (nelems > DB_DIM(dic, i) - index + 1) { + call error (DB_ERRCODE + 10, "Database request out of bounds") + } + offset = offset + (index - 1) * sz_elem + } + } + + # Seek and write the data + call seek (DB_FD(db), offset) + call write (DB_FD(db), buf, sz_elem * nwritten) + return +end + + +# DBCLOSE -- Update the dictionary in the database, close the database +# and free DBIO descriptor. + +procedure dbclose (db) + +pointer db + +begin + # Update dictionary in database + if (DB_UPDATE(db) == YES) + call dbwrite (db, "db_dictionary", Memi[DB_DIC(db)], + DB_DIM(DB_DIC(db), 1)) + + call close (DB_FD(db)) + call db_freedes (db) +end + + +# Procedures accessing the DBIO descriptor list. +# +# DB_GETDES -- Allocate and return a DBIO descriptor. Post error recovery. +# DB_FREEDES -- Close a database and free allocated memory. +# DB_ERROR -- Take error recovery action by closing all open databases. + +procedure db_getdes (db) + +pointer db # Allocated DBIO descriptor + +extern db_error() +errchk malloc() + +int ndes # Number of allocated DBIO descriptors +pointer dbdes[MAX_DB_DES] # DBIO descriptor list + +common /dbiocom/ ndes, dbdes + +int init +data init/YES/ + +begin + if (init == YES) { + ndes = 0 + init = NO + } + + # Check to see if the requested descriptor would overflow the descriptor + # list. If not allocate memory for the descriptor otherwise + # start error handling. On the first call post the error handler. + + if (ndes == MAX_DB_DES) + call error (DB_ERRCODE + 11, "Attempt to open too many database files") + + ndes = ndes + 1 + call malloc (dbdes[ndes], LEN_DB_DES, TY_STRUCT) + db = dbdes[ndes] + DB_FD(db) = NULL + DB_DIC(db) = NULL + DB_UPDATE(db) = NO + + if (ndes == 1) + call onerror (db_error) +end + + +# DB_FREEDES -- Close a database and free allocated memory. + +procedure db_freedes (db) + +pointer db # DBIO descriptor to be freed + +int i + +int ndes # Number of allocated DBIO descriptors +pointer dbdes[MAX_DB_DES] # DBIO descriptor list + +common /dbiocom/ ndes, dbdes + +begin + + # Locate the specified descriptor in the descriptor list. + # If the descriptor is not in the list do nothing. + # If the descriptor is in the list free allocated + # memory and remove the entry from the list. + + for (i = 1; (i <= ndes) && (db != dbdes[i]); i = i + 1) + ; + if (i > ndes) + return + + if (DB_DIC(db) != NULL) + call mfree (DB_DIC(db), TY_STRUCT) + call mfree (db, TY_STRUCT) + + if (i < ndes) + dbdes[i] = dbdes[ndes] + ndes = ndes - 1 +end + + +# DB_ERROR -- Take error recovery action by closing all open databases. + +procedure db_error (error_code) + +int error_code # Error code + +int i + +int ndes # Number of allocated DBIO descriptors +pointer dbdes[MAX_DB_DES] # DBIO descriptor list + +common /dbiocom/ ndes, dbdes + +begin + # Let fio_cleanup deal with the open files and the system + # restart deal with freeing the stack. This procedure + # cleans up the dbio descriptors and updates the database + # dictionary. + + do i = 1, ndes + # Update dictionary in database. Catch errors. + if (DB_UPDATE(dbdes[i]) == YES) + iferr (call dbwrite (dbdes[i], "db_dictionary", + Memi[DB_DIC(dbdes[i])], DB_DIM(DB_DIC(dbdes[i]), 1))) + call erract (EA_WARN) + + call db_freedes (dbdes[i]) +end + + +int procedure dbgeti (db, key, type) + +pointer db +char key[ARB] +char type[ARB] + +int i +pointer dic + +bool streq() + +begin + dic = DB_DIC(db) + for (i = 1; i <= DB_DIM(dic, 1); i = i + 1) { + if (DB_DIM(dic, i) == 0) + call error (0, "Key not in database") + if (streq (key, DB_KEY(dic, i))) + break + } + if (i > DB_DIM(dic, 1)) + call error (0, "Key not in database") + + if (streq (type, "r_len")) + return (DB_DIM(dic, i)) + else if (streq (type, "r_size")) + return (DB_SZ_ELEM(dic, i)) + else + call error (0, "Unknown database key attribute") +end diff --git a/noao/twodspec/multispec/dbio/mkpkg b/noao/twodspec/multispec/dbio/mkpkg new file mode 100644 index 00000000..f1aee503 --- /dev/null +++ b/noao/twodspec/multispec/dbio/mkpkg @@ -0,0 +1,9 @@ +# Multispec/dbio library. + +$checkout libpkg.a ../ +$update libpkg.a +$checkin libpkg.a ../ + +libpkg.a: + dbio.x dbio.h + ; diff --git a/noao/twodspec/multispec/doc/MSalgo.ms b/noao/twodspec/multispec/doc/MSalgo.ms new file mode 100644 index 00000000..0c64e2b3 --- /dev/null +++ b/noao/twodspec/multispec/doc/MSalgo.ms @@ -0,0 +1,1032 @@ +.de FX +.nf +.ps -2 +.ss 25 +.cs R 25 +.. +.de EX +.ps +2 +.ss +.cs R +.fi +.. +.EQ +delim $$ +.EN +.RP +.TL +Algorithms for the Multi-Spectra Extraction Package +.AU +Francisco Valdes +.K2 +.TU +.AB +The algorithms for the Multi-Spectra Extraction Package (\fBmultispec\fR) +in the Image Reduction and Analysis Facility (\fBIRAF\fR) is described. +The basic aspects of the general two dimensional aperture spectra extraction +problem are first discussed. +The specific algorithms for extraction of multi-aperture plate and +Echelle digital data are presented. Results of the authors experiments +with this type of data are included. +The detailed specification of the package is given in a second document, +\fIDetailed Specifications for the Multi-Spectra Extraction Package\fB. +.AE +.NH +Introduction +.PP +There are an increasing number of astronomical instruments which produce +multiple spectra on a two dimensional detector. +The basic concept is to use one dimension for wavelength, +the dispersion dimension, and the other, the cross dimension, for +packing additional information during a single exposure. +For example, the cross dimension can be different objects or +different spectral orders. The classic multi-spectra instrument is +the Echelle spectrograph. New instruments are the aperture plate and +Medusa spectrographs. +.PP +There is an additional aspect of the multi-spectra format; namely, +the individual spectra can contain spatial data. An example of +this would be multiple slit spectra in which each slit spectra contains +sky signal and object signal. In the following +discussion we limit the spectra to be simple aperture spectra in +which we only desire to sum the intensities at each wavelength to form +a one dimensional spectrum. +.PP +The analysis of multi-spectra aperture data consists of two steps; the +separation and extraction into individual aperture spectra +and the calibration and measurement of the spectra. These steps can +either be incorporated into one analysis package or two separate +packages. There are advantages to the first approach since some +aspects of the individual spectra are directly related by the physical +geometry of the multi-spectra format. However, because packages for +the analysis of individual spectra exist we begin by dividing the +reduction into separate extraction and analysis tasks. It is +important to realize, however, that the existing analysis tools are not well +suited to reducing the larger number of spectra and treating sets of +spectra together. +.PP +The latter part of this paper describes the algorithms for the +extraction of two types of data; the multi-aperture plate (MAP) +and Echelle used with digital detectors. However, +it is important to keep the more general problem in mind +and the remainder of this introduction considers the different +conceptual aspects of the multi-spectra extraction task. +Table 1 lists many of the general properties of multi-spectra aperture data. +The other two columns give possible alternatives that each property may take. + +.TS +center box; +c s s +c s s +c c s += = = +c || c | c. +Table 1: Aspects of Multi-Spectral Data + +Property Alternatives +detector digital photographic +alignment aligned skewed +blending blended unblended +aperture holes slits +spectral resolution low high +.TE + +.PP +The detector determines what kind of calibration procedures are +required to produce intensity from the measurements. +A digital detector requires sensitivity calibrations on all scales. +This is the "flat field" problem. There are also corrections for +bias and dark current. Photographic detectors require +intensity calibration. Data which are not aligned with the natural +dimensions of the digital image require extra procedures. Two types +of non-alignment are a rotation of the dispersion dimension relative +to the pixel dimension and a "wiggling" or "snaking" of the dispersion +dimension. Blending refers to the degree of contamination along the +cross dimension. Blended data requires extra effort to correct for +the overlap between different spectra and to determine the background. +The aperture defines the extent of the spectra in the cross dimension. +The two most relevant choices are holes and slits. In some +instruments, like the Echelle, the size of the aperture can be varied +at the time of the observations. Finally, the spectral resolution is +important in conjunction with digital detectors. If the resolution is +high then quartz flat field calibrations are relatively easy because +the spectral +signature need not be considered. Otherwise, the flat field problem +is more difficult because the gain variations of the detector +must be separated from the natural spectral intensity variation of the +quartz. +.PP +There is always some confusion of terms when talking about multi-spectra +data; in particular, the terms x, y, line, and band. +The image pixel dimensions are refered to as x and y. We assume +for the moment that the alignment of the multi-spectra format is such +that x corresponds to the cross dimension and y to the dispersion +dimension. If this is not the case a rotation or interpolation +program can be used to approximately orient the data in this way. +A line is the set of intensity values as a function of x at constant y. +In other words, a line is a cut across the dispersion dimension. +A band is the average of more than one line. +The image residing on disk will generally be organized +such that x varies more rapidly and a line of the image is easily +obtained. In this form a display of the image will have the spectra +running vertically. In the Cyber extraction package the data is +organized with x corresponding to the dispersion dimension. +.NH +Multi-Spectra Image Formats +.PP +The remainder of this paper will refer to two specfic and very +different multi-spectra formats; the Kitt Peak Multi-Aperture Plate +System and the Kitt Peak Echelle Spectrograph. +.NH 2 +Kitt Peak Multi-Aperture Plate System +.PP +The reduction of data from multi-aperture plate observations is the +driving force for the development of a multi-spectra extraction +package. This application turns out to have most of the worse aspects +of the properties listed in Table 1. The multi-aperture plate spectrograph uses +digital dectectors with low resolution, the spectra are blended and +change alignment along the pixel dimension. Furthermore, the camera +has a variable point-spread function and focus, +suffers from flexture problems, has a different illumination for +the quartz than object exposures, and unexplained background level +variations (in the CRYOCAM). There are two detectors which have been +used with the multi-aperture plate system, the Cryogenic Camera +(CRYOCAM) and the High Gain Video Spectrometer (HGVS). +.NH 2 +Echelle +.PP +As some of the algorithms were developed the Echelle data was brought +to my attention. It is considerably simpler than the MAP data because +it is unblended and of high spectral resolution. +Furthermore, the quartz exposure +can be made wider than the object exposures and flexture is not a +problem. The principle problem in this data was the +prevalence of cosmic rays. It pointed to the need to maintain generality +in dealing with both the MAP data and other types of +multi-spectra data which have different profiles, may or may not be +merged, and may or may not have different widths in quartz and object. +Dealing with the cosmic ray problem lead to a very effective solution +usable in both the Echelle and multi-aperture plate data. +.NH +User Level Extraction Logic +.PP +The user should generally only be concerned with the logical steps of +extracting the individual spectra from the multi-spectra image. This +means that apart from specifying the detector system and the format +he should not deal with details of the detector and the format. +In the paper, +\fIDetailed Specifications for the Multi-Spectra Extraction Package\fB, +the \fBIRAF\fR extraction package design and program specifications +are described. +.NH +Flat Fields +.PP +There are two types of flat field situations depending on the spectral +resolution. When the resolution is high then the spectral signature of +the continum calibration source, a quartz exposure, will be unimportant +and variations in the signal will be due to detector sensitivity variations. +In this case the quartz frame, or average of several frames, is the flat +field and division of the object frames by the quartz frame is all that +is required. However, a special +image division program is desirable to handle the region of low or absent +signal between the the spectra. This is described in section 4.2. +.PP +In the alternate case of lower resolution the quartz spectral signature is +larger than the detector response variations. A flat +field in which the intrinsic quartz spectrum is removed is produced by +assuming that the true value of a pixel is given by the smoothed average +of the pixels near that point in position and wavelength and taking +the ratio of the data value to the smoothed value. +This requires a special smoothing program described in section 4.1. +After the flat field is generated then the same image division +program used for the Echelle data is applied. +The image division and smoothing programs are general image operators and +not specific to the Multi-Spectra Extraction Package. +.NH 2 +MULTISPEC_FLAT +.PP +The multi-aperture plate data varies in both dimensions. Thus, any averaging +to smooth the image must take this variation into account. In the Cyber +a flat field for the multi-aperture plate data smooths across the dispersion +by modeling the spectra. This is a difficult task to do accurately because +the true shape of the spectra is not known and the counts vary greatly +and rapidly in this dimension. This approach has the further difficulty +that it is not possible to average several quartz exposures directly. +.PP +The alternate approach to modeling is statistical averaging. +Averaging across the dispersion requires very high order polynomials +because of the rapid variations; +the spectra are typically spaced about 8 pixels apart and there are on +the order of 50 spectra. On the other hand, variations along the dispersion +are much slower even if the spectra are slightly skewed; a bad case would +have two peaks in 800 pixels along the y dimension. This kind +of variation is tractable with relatively simple averaging polynomials +and is the one adopted for the multi-aperture plate data. +.PP +The flat fields are produced by a quadratic moving average along the +y direction. This means that the region centered at a given pixel +is fitted by a least-squares quadratic polynomial and the value of the +polynomial at that point is the appropriate statistical average. +The width of the moving average is an adjustable parameter. +At the edges of the frame where it is not possible to center a region of +the specified width about the desired pixel the polynomial fit is used to +extrapolate the average value to the edge. +.PP +Because the quadratic fit will +be influenced by bad pixels an attempt is made to detect and smooth over +the bad pixels. This is accomplished by comparing the smoothed values to +the observed values and ignoring pixels with a value of + +.EQ (1) + chi = | observed - smoothed | / sqrt smoothed +.EN + +greater than a specified value. Then the smoothing is recalculated and tested +again for bad pixels. This iteration continues until no further pixels +are rejected. +.PP +Following the smoothing the flat field is produced by ratioing the raw quartz +to the smoothed quartz. Pixels of low signal (specified by the +parameter \fIconstant\fR ) +are treated by the equation + +.EQ + r = (data + (constant - smoothed) ) / constant . +.EN + +The resultant flat field image is then divided into the object frames in +the manner described in the next section. +.PP +Experience with data from the Cryogenic Camera has proved very good. +The flat field which is produced can be examined on a display. It +shows fringing at red wavelengths and is not too strongly affected +by bad pixels. Some further effort, however, could go into smoothing +over the bad pixels. +.PP +The smoothing operation on data from the Cryogenic Camera actually +consists of four steps. The quartz exposures are first averaged. +The average quartz is rotated so that the dispersion +direction is the most rapidly varying or x dimension. Then the +smoothing is performed along x followed by another rotation to return +the flat field image to its original orientation. The reason for the +rotations is that they can be done quickly and efficiently whereas +smoothing along the y dimension is very slow and coding an efficient +version is much more complicated than doing a single line at a time. +.NH 2 +FLAT_DIVIDE +.PP +The Echelle data has quartz frames which can be used directly as flat fields. +One just has to divide the object frames by the quartz or average of several +quartz. However, in image division consideration has to be given the +problem of division by zero or very small numbers. In direct imaging this +may not be much of a problem but in multi-spectra data the region between +the spectra and near the edges of the spectra will have very low counts. +Another aspect of image division for making flat field corrections is the +scaling of the result. The flat field integer image data must be large +to give accurate relative response values. However, one wants to divide +an object frame by values near unity. +This section describes a special image division operator allowing the user +to specify how to handle these cases. +.PP +The parameters are a \fIdivision threshold\fR +(default of zero) and a \fIthreshold violation value\fR. Values of the +denominator above the \fIthreshold\fR are treated separatedly from those +below the \fIthreshold\fR. The denominator image is scaled to have an +average of one for pixels above the \fIthreshold\fR. The pixel by pixel +division is then performed for those points for which the denominator +is above the \fIthreshold\fR. Pixels for which the denominator is below the +\fIthreshold\fR are set to the \fIthreshold violation value\fR in the resultant +image if the \fIviolation value\fR is specified. If the value is not +specified then the numerator value is taken as the resultant value. +The divisions can be done in place or the result put into a new image file. +.PP +For the multi-spectra situation where the object spectra have a +smaller width than the quartz, as in the Echelle, one can either +set the \fIthreshold +violation value\fR to zero or not set it at all resulting in either +exactly zero or background values between the spectra while still flattening +the spectra. This allows looking at the flattened spectra without the +annoying "grass" between the spectra caused by dividing by small +values. +.NH +Extraction +.NH 2 +MULTIAP_EXTRACT +.PP +The extraction of spectra from multi-aperture plate images consists of +a series of steps. The steps are executed from a script. +The command + +.FX +ms> multiap_extract "ap165.*", "", 165, 50 +.EX + +will take the flattened images, ap165.*, from aperture plate 165 with 50 +spectra and automatically locate the spectra, model the profiles, and +extract the one dimensional spectra. The script consists of +a number of steps as described below. +.PP +\fBFind_spectra\fR (section 6) initializes the \fBmultispec\fR data file +and does a peak search to determine the initial positions of the +spectra. +\fBFind_bckgrnd\fR fits a polynomial of order 1 (or more) for the pixels which +are not near the spectra as defined by \fBfind_spectra\fR. +.PP +The spectra are then modeled in bands of 32 lines by the model profiles +described in section 8.1. The first \fBmodel_fit\fR uses three Gaussian +parameters for +each spectra measuring the peak intensity, peak position, and width. +The second \fBmodel_fit\fR adds a fourth parameter to modify the wings of the +profile. +.PP +The \fBmodel_extract\fR program extracts the spectra line by line and also +detects and removes cosmic ray events which do not fit the model +profiles (see section 9). +In outline, the extraction of blended spectral data uses the +model profiles to determine the fraction of light +from each of the neighboring spectra at the pixel in question. The +appropriate fraction of the +.ul +observed +pixel intensity (minus the background) is +assigned to the luminosities of the spectra. There are two versions +of the \fBmodel_extract\fR extraction. The first simultaneously fits the +peak intensity of all the spectra and the second uses the +data value at the peak of each spectra to normalize the model. The +first method is slow and accurate and the second is fast and approximate. +Because the models are used in extraction only to define the relative +contributions of neighboring spectra to the total observed pixel luminosity +the speed of the approximate method far outweighs the need for +accuracy. However, cleaning the spectra of cosmic rays is a different +matter and is discussed further in section 12. +.PP +After the extraction the spectra are correlated with the aperture plate +description using \fBap_plate\fR (see Section 10) to determine the +relative wavelength offsets and assign identification information to +the spectra. +.PP +For successive frames it is not necessary to resort to the initial +steps of finding the spectra and fitting from scratch. The \fBcopy_params\fR +routine makes a new copy of the fitting database. Small shifts in positions +of the spectra and the peak intensities are determined by doing a two +parameter fit for the peak and position using the previously determined +shape parameters. +Changes in the shape of the spectra are then determined by the three +and four parmater fits. Because the solution is likely to be close to +the previously determined shape the transfering of one solution from a +previously solved image is faster than starting from scratch. +Note that the shapes as well as the positions and peak intensities +of all frames including the object exposures are allowed to change. +.PP +The spectra are then extracted from the image by \fBmodel_extract\fR and the +process repeats for the succeeding images. +.PP +One useful feature is the ability to specify the bands or lines to be +modeled or extracted. +This feature is useful for diagnosising the programs quickly. +The default is all bands or lines. +.NH 2 +ECHELLE_EXTRACT +.PP +The extraction of the unblended Echelle spectra is performed +begins in a similar way with \fBfind_spectra\fR and \fBfind_bckgrnd\fR. +The extraction and cleaning, however, uses \fBstrip_extract\fR which +adds up the instrumental counts for each unblended spectra at each +wavelength to get the total luminosity. +.NH +FIND_SPECTRA -- Finding the Spectra +.PP +The first step in the extraction and processing of multi-spectra data is +to locate the spectra. This can be done interactively by +the user but it is far preferable to automate the process; +particularly since multi-spectra data can have a large number of +spectra and frames. The approach is to find the peaks in a line, or +average of lines, sort the peaks found in some manner, such as by +strength, and select the expected number of peaks from the top of the +list. +Beyond this simple outline are several algorithmic details such as how +to define and locate valid peaks and how to sort the list of peaks. +Peak finding is a general problem and a subroutine for peak finding is +described below. The \fBfind_spectra\fR program provides an +interface between the \fBmultispec\fR data file and the +general peak finding algorithm. +.PP +The \fBpeaks\fR function takes arrays of x (position) and y (value) points +and the number of +points in the arrays and returns the number of peaks found. It also +returns the estimated positions of the peaks in the x array and the +extimated peak values in the y array in order of peak likelihood. +There is one user parameter, the smoothing \fIwidth\fR. +The choice of the \fIwidth\fR parameter is dicatated by how closely and how +wide the peaks are to be expected. +The algorithm takes a region of \fIwidth\fR points +centered on each x point and fits a quadratic; + +.EQ +y sub fit = a + b x + c x sup 2~. +.EN + +A peak is defined +when the slopes, $b sub 1$ and $b sub 2$, of two neighboring points +$x sub 1$ and $x sub 2$ change +sign from positive to negative and the curvatures, $c sub 1$ and $c +sub 2$, are less than -0.001 for both points. +The quadratic polynomials define two estimated peak positions + +.EQ +x sub 1 sub peak = x sub 1 - b sub 1 / (2 * c sub 1 ),~~ +x sub 2 sub peak = x sub 2 - b sub 2 / (2 * c sub 2 )~. +.EN + +The offsets are then normalized to give a linear interpolation +fraction +$f = ( x sub 1 sub peak - x sub 1 ) / ( x sub 2 sub peak - x sub 1 sub +peak )$ in the interval between the two points. +The estimated position of the peak is then + +.EQ +x sub peak = f * ( x sub 1 - x sub 2 ) +.EN + +and the estimated peak value is the average value of the two quadratic +polynomials at $x sub peak$. The curvature at the peak is +estimated by $c sub peak = c sub 1 + f * (c sub 1 - c sub 2 )$. +Finally, the peaks are sorted by the magnitude of the peak curvature. +.PP +This peak finding algorithm works quite well. I have also used it to +automatically locate peaks in the extracted one dimensional spectra +and then do peak correlations between spectra to find a relative +wavelength solution. Some such use of this program may be implemented +in either future additions to the Multi-Spectra Extraction Package or +the Spectral Reduction Package. +.PP +In \fBfind_spectra\fR the number of spectra to be found is specified by +the user. The user should have previously looked at an image +on a display or done a profile plot across the +dispersion to count the observed spectra. +Additional parameters specify the columns in which the spectra +are to be found and the minimum separation and width of the spectra. +The column specification allows the elimination of problems with defective +areas of the detector such as the LED in the Cryogenic Camera. The minimum +width and separation provide algorithmic constraints to the spectra finding +procedure. +.PP +The peaks are found at two or more points in the +multi-spectra image for a band of 32 lines using a +\fBpeaks\fR \fIwidth\fR parameter of 5. After the peaks are found +at a number of bands in the image a linear fit is made to determine any small +slope of the spectra relative to the columns. +The reason for specifying only a few bands is that the process of +finding the peaks is moderately slow and only two bands are needed for +determining the initial position angle of the spectra to the y +dimension. Furthermore, some bands do not give a satisfactory result +because of extraneous data such as the LED in the CRYOCAM or bad +focus. Another possibility is that a spectrum may go off the edge +and in order to "find" the spectrum for partial extraction bands that +include the on image part of the spectrum must be specified. +.NH +FIND_BCKGRND -- Background +.PP +The background on a multi-spectra image is the result of very broad +scattering as opposed to the narrower scattering which produces +distinguishable wings on individual spectra. +Modeling of the background in a Cryogenic Camera multi-aperture plate +image shows that the background is well explained by a broad +scattering function. +It is not reasonable, however, to model the scattering to this detail +in actual extractions. +Instead a smooth polynomial is fitted to the pixels not covered by +spectra. The order of the polynomial is a specified parameter. +For the CRYOCAM MAP data a quadratic is appropriate. +.PP +The algorithm is the same for all multi-spectra data except for the +choice of parameters. First, the location of the spectra must be +determined. This is done by the \fBfind_spectra\fR program. There +are two principle parameters, a buffer distance and the order of the +fitting polynomial. Each line, or average of several lines, is fitted +by least-squares for the points lying farther than the buffer +distance from any spectra. If there are no points which completely +stradle the spectra, i.e. located on each side of the spectra, then +the order of the fitting polynomial is ignored and a constant, or +first order polynomial, is determined. +A hidden parameter specifying the columns allowed for searching for +background points is available so that bad parts of the image can be +ignored. +.PP +A difference in philosophy with the Cyber programs is that the +determined background is not subtracted from the image data. It is +instead kept in the database for the image. Generally, it is better to +modify the basic image data as little as possible. This is the approach +used in the Multi-Spectra Extraction Package. +.NH +Spectra Profiles +.NH 2 +MODEL_FIT -- Models for Multi-Spectra Images +.PP +The object of modeling is to separate blended spectra for extraction +and to remove artifacts, such as cosmic rays, which do not fit +the model. The models should have the minimum number of parameters +which give residuals approaching the detector statistics, they +should incorporate constraints based on the physics of the +detector/camera system, and the models must be ammenable to a +statistical fitting algorithm which is stable. +There are a large number of possibilities. +.PP +An important point to bear in mind during the following discussion is +the necessary accuracy of the model fitting. In the design proposed +here the model fitting is not used for determining the smooth quartz. +Use of a model for making a flat field would require a very accurate +model and using an average quartz is not possible. However, for +extraction the model is used only to indicate the +relative fraction of light for each spectrum when the spectra are +blended. The cleaning application is more critical but not nearly so +much as in the flat field modeling. Thus, though we do a good job of +model fitting (better the the Cyber modeling) some additional features +such as smoothing along the spectra are not included. +Also, though some improvement can be gained by the additional shape +parameters in the fit, they are not necessary for the required purpose +and can be left out leading to a faster extraction. +.PP +During the course of my investigation I tried more than one hundred +models and combinations of constraints. Some general results of this +study follow. +The model which I find gives the best results has six parameters not +counting the background. The model is defined by the following +equations where x is the cross dimension. + +.EQ (1) +I = I sub 0 exp (-s * ( DELTA x sup 2 )) +.EN +.EQ +DELTA x = (x - x sub 0 ) +.EN +.EQ +s = s sub 0 + s sub 1 y sup 2 + s sub 2 y sup 3 +.EN +.EQ +y = DELTA x / sqrt { DELTA x sup 2 + x sub 1 sup 2 } +.EN + +The model consists of a intensity scale parameter, $I sub 0$, +and a profile which is +written in a Gaussian form. The center of the profile is given by +the parameter $x sub 0$. The profile is not exactly Gaussian because the +scale, $s$, is not a constant but depends on $DELTA x$. The scale +function has three terms; a constant term, $s sub 0$, which is the scale +near the center of the profile, and even and odd terms, $s sub 1$ +and $s sub 2$, +which change the scale in the wings of the profile. +.PP +The characteristic of the profile which must be satisfied is that at +large distances from the profile center the scale is positive. This +requirement means that the profile will be monotonically decreasing at +large distances and will have a finite luminosity. This point was +crucial in determining the form of the scale function. A straight +power series in $DELTA x$ does not work because power series diverge. +Instead, the scale function is defined in terms of a separation +variable $y$ which is bounded by -1 and 1 at infinite separation and is +zero at zero separation. The parameter $x sub 1$ defines a characteristic +distance where the character of $y$ changes from going as $DELTA x$ to +asymptotic to 1. The parameters are, thus, $I sub 0$, $x sub 0$, $s sub 0$, +$s sub 1$, $s sub 2$, $x sub 1$. +.PP +An important property of this model is that the terms have a physical +interpretation. The profile scale and profile center are obvious and +any model must include them. It is the remaining terms, $s sub 0$, +$s sub 1$, $s sub 2$, +and $x sub 1$, which are called the shape parameters, which are interesting. +In an ideal aperture plate system the shape of a profile would be +given by the projection of the circular aperture into the cross dimension: + +.EQ +P( DELTA x ) = sqrt {1 - a DELTA x sup 2} +.EN + +where the constant a is related to the size of the hole by + +.EQ +a = 1 / r sup 2 +.EN + +For small $DELTA x$ the profile can be expressed in the Gaussian form with +a scale + +.EQ +s = a( 1/2 + a DELTA x sup 2 + ...) +.EN + +Thus, even in a perfect aperture plate system a Gaussian form shows the +scale increasing from a central value determined by the size of the hole. +In other words, the profile decreases more sharply than a Gaussian. +.PP +However, no aperture plate system is ideal because the thickness of +the aperture plate is finite and there is scattering and changes in +the focus of the system. One must +convolve the profile above with a scattering/focus function. One can show +that for reasonable functions, exponential and Gaussian, +with some scale b the final profile is a function of the ratio b/a. +If the ratio is less than 1 then the profile will be more like that of +the hole and the profile will be sharper than a Gaussian in the wings. +If the ratio is much greater than 1 then the profile will become the +scattering profile at large separations. Simulations using Gaussian +and exponential scattering profiles show behaviors very much like the +profile (1) with $s sub 1$ greater than zero when b/a < 1 +meaning the profile becomes sharper (than a Gaussian) in the wings +and $s sub 1$ < 0 when b/a > 1. +Thus, $s sub 1$ defines the scale of the scattering profile relative +to the hole size. +The size of the hole is incorporated into the parameter $x sub 1$. +The parameter $s sub 2$ allows an asymmetry in the profile. +.PP +An interesting property of the scale function is that it is all right +for it to be negative at small distances from the profile center. This +occurs when $s sub 0$ is negative. The effect of this, provided $s$ +becomes positive at large distances, is to give a two horned profile. +This, in fact, is observed when the focus of the system becomes very +poor. +.PP +The best fits (least chi-square or rms residual) are +obtained when each spectrum at each wavelength has independent +parameters. However, this sometimes gives rise to unphysical results. +If left entirely unconstrained the parameter fitting algorithm can +make one line broad and dominant and a neighboring line weak and +sharp. +This is not, of course, a property of the camera or detector. +Thus, constraints based on the physics of the +camera/detector are used. This means that the shape +parameters $s sub 0$, $s sub 1$, $s sub 2$, and $x sub 1$ +are coupled locally by making them vary as a polynomial of position +across the dispersion. One might also +constrain the variation of the shape along the spectrum as is done in +the Cyber. This is not needed because there are no drastic differences +between the fitted parameters at neighboring points along the spectra. +.PP +My experience with the Cyrogenic Camera system has shown the +following. The focus ripples twice across the CCD with the +propagation angle being approximately 30 degrees from the long dimension. +The change in focus is partly just a scale change. This is seen in +the correlation of $s sub 0$ with the image scale found by \fBap_plate\fR. +The shape parameter $s sub 1$ changes sign from positive to +negative indicating that when the focus is good the profile +decreases faster than a Gaussian and when the focus is bad it decreases +slower. Occassionally the focus is very bad and $s sub +0$ is negative and $s sub 1$ is small and positive causing a broad two +horned profile. The +assymetry parameter, $s sub 2$, is useful only when the signal is strong near +the peak of a quartz exposure. It is not really necessary to include +it in the model fits. The assymetry parameter was dominant, however, +in some Echelle data which were clearly asymmetric. The value of +$x sub 1$ is +not highly sensitive and can be fixed for a given hole size. Large +changes in the hole size would require resetting $x sub 1$. +The use of the four parameters, $I sub 0$, $x sub 0$, $s sub 0$, +and $s sub 1$, allow good fits +to all the data I've examined including those in which the peak/valley +intensity ratio across the spectra is about 1.1. It is the importance +of the parameter $s sub 1$ which improves the fitting dramatically over the +Cyber three parameter fitting (in addition to a different fitting +algorithm). +.PP +The heart of profile fitting is the solution of the multi-parameter +least-squares problem. In a blended multi-spectra image the profile +parameters of one spectra are affected by its neighbors which are, +in turn, affected by their neighbors and so forth. The key to this +type of problem is to realize that only nearest neighbors affect the +profile parameters and this leads to a "banded" least-squares matrix. +A banded matrix is one in which cross terms far from the diagonal are +zero. Solution of banded matrices is much more efficient than solving +the entire matrix. This allows solution for more than 100 parameters +simultaneously in a short time. +.PP +Use of the banded multi-parameter solution has the restriction, however, +that there can be no parameters in the model which are not local to +the profiles. This affects the way +global constraints are applied to the parameters. In particular, +the way the shape parameters are constrained to vary smoothly across the +detector. +The shape parameters are first found as independent parameters by the +banded matrix solution and then smoothed by a polynomial in x. +.PP +An area which was extensively investigated was the appropriate +weighting to use for the model fitting. The most likely choices are +weighting by $1 / sqrt data$ and unit weight corresponding to +$chi sup 2$ +and least squares fitting. It was found that the two methods +agreed fairly closely but that the least squares fitting was more +appropriate because the blending correction depends largely on the +value of the peak intensity and less on the exact fit of the wings. +With $chi sup 2$ the peak is fit with less accuracy in order to improve +the fit in the wings of the profile. In some cases this gave clear +errors in estimating the peak intensity and, hence, the proper contributions +between the blended spectra were not made. +.PP +Now follows the details of the fitting algorithm. +The algorithm is a series of script steps in \fBmultiap_extract\fR +which call the model fitting program \fBmodel_fit\fR with different +parameters. In the script all bands are fit, $x sub 1$ is fixed, +and the asymmetry shape parameter $s sub 2$ is ignored. +The four parameter fit is applied to bands of 32 lines. The band +solutions are linearly interpolated to the full image and then only +the intensity scale parameter is calculated for each line during the +extraction of the spectra with \fBmodel_extract\fR. +.PP +The general fitting scheme proceeds as follows: +.LP +1. Fit the three parameters $I sub 0$, $x sub 0$, $s sub 0$ with +$x sub 1$ fixed and $s sub 1$ and $s sub 2$ +zero. This is precisely a Gaussian fit. The three parameters are +determined simultaneously for all the lines at once using the banded +matrix method. Thus for 50 lines the solution has 150 variables. +After each fit the scale +parameter $s sub 0$ is smoothed by a polynomial in x. The polynomial is +taken with seven terms. +.LP +2. Once the improvement in each iteration becomes less than a +specified amount (2% in rms residual) the next parameter $s sub 1$ is added. +The solution has two steps: fit for $s sub 0$ and $s sub 1$ with $I sub 0$ +and $x sub 0$ fixed and +then fit $I sub 0$ and $x sub 0$ with $s sub 0$ and $s sub 1$ fixed. As before the scale terms +are smoothed by a seventh order polynomial. Attempts to solve for all +four parameters a once gave unstable results for reasons I don't +understand. +.LP +3. If desired, the last shape parameter $s sub 2$ can be added by solving +for $s sub 0$, $s sub 1$, and $s sub 2$ while holding $I sub 0$ and +$x sub 0$ fixed and then solving for +$I sub 0$ and $x sub 0$. This provides some improvement when the signal is very +strong but is generally not needed in the multi-aperture plate data. +It can be an important term in the Echelle data. +.LP +4. It is possible to then adjust $x sub 1$ followed by steps 2 or 3. +However, this gives very little improvement and $x sub 1$ should be fixed for +each type of data. +.LP +5. During the final extraction when individual lines are evaluated a one +parameter fit is used to find $I sub 0$ for each spectra. This is +rather slow, however, on the order of 3 hours per frame. By using +the pixel value near $x sub 0$ as the value for $I sub 0$ the extraction is reduced +to 13 minutes per frame (see section 12). +.PP +In addition to the preceeding steps the fitting algorithm applies some +heuristic constraints. These constraints limit how far the peak positions can +shift in each iteration, require the peak intensity to remain positive, and +limit the scale function to be positive at large values of y. +.NH 2 +STRIP_EXTRACT -- Unblended Profiles +.PP +For unblended multi-spectra data the profiles can be anything. The profiles +are obtained by averaging a number of lines (say 32) and normalizing +at some point like the peak value. These profiles are then used for +detecting bad pixels, such as cosmic rays, and correcting for them as +discussed in the section on cleaning. Modeling using the \fBmodel_fit\fR +program is only used on Echelle data to find peak positions +accurately in order to follow any curvature of the spectra. +.NH +Extraction and Cleaning +.PP +The extraction of spectra are done separately from the modeling. It is +possible to extract spectra without any modeling at all using +\fBstrip_extract\fR. The extraction step also allows the user to specify +if cleaning of the spectra for cosmic rays is desired. Also modifying +the image is an option. +.NH 2 +MODEL_EXTRACT +.PP +Extraction and cleaning using a model fit is described here. +First the $I sub 0$ values for the model profiles are determined for +all the spectra in a line either by multi-parameter fitting or by +taking the peak value. The pixel values are then compared to the +model in a chi-squared way: + +.EQ +r = (data - model) / sqrt model +.EN + +If the value of r is larger than a set amount, say 5, then the pixel +value is set to that of the model. Since the "bad" pixel may affect +the intensity scale $I sub 0$ the cleaning is iterated until no further +pixels are changed. +.PP +The fitting of the data from an individual line of data to the model profiles +is the key element in this scheme. The best method is to use all the +data in a multi-parameter least square fit. This minimizes the effect +of bad pixels on the estimated profile which is the essence of this +cleaning method. However, while the time required to do this for one +line is not great, it adds up to nearly three hours for the 800 lines +in a CRYOCAM frame. A quick alternative is to scale the model profile +by the data value at the peak position. This is +quite fast. However, if the peak has a cosmic ray event or is +otherwise bad then the estimated profile will not correspond closely +to the data profile and the cleaning procedure will make gross errors. +The limited experience I've had with the Echelle and MAP data +has worked well with using the peak estimate. However, the possible +problems make me nervous and some compromise based on using more than +the peak to estimate the intensity scale of the profile to the data +needs to be found. This is important because much of the feedback on +the \fBmultispec\fR package from Paul Hintzen and Caty Pilachowski +have dealt with +the particular usefulness of a good cosmic ray cleaning algorithm in +extracting multi-spectra data. +.NH 2 +STRIP_EXTRACT +.PP +Removing cosmic rays is the major part of Echelle extraction. +Because these are unblended spectra of arbitrary shape a strip +extraction is all that is needed. +The cleaning is done by the same algorithm used for the multi-aperture +plates except that the profiles are found, as described earlier, by +averaging a number of lines. +The intensity scaling is determined from either a least-square fit +or the peak value. +The same question about the appropriate way to +determine the fit of the profiles to the data discussed previously +applies here except since the spectra are not blended the spectra +can be treated separately in any least square fitting. +.NH +AP_PLATE -- Aperture Plate Correlation +.PP +The final step in the extraction of a multi-aperture plate image is to +correlate the spectra with the on-line database description of the +drilled hole positions. This allows for estimates of relative wavelength +offsets and the identification of the spectra with the ID, RA, and DEC +parameters. +.PP +The spectra are fitted to the known aperture plate drilled positions, given in +millimeters, to find an \fIangle\fR for the aperture plate relative to the +detector x dimension and the image \fIscale\fR in pixels / millimeter, + +.EQ +x sub fit = a + scale (x sub drill cos (angle) + y sub drill sin (angle))~. +.EN + +If the number of spectra is less than that given by the aperture plate drilled +positions then a correlation is done leaving out sequences of +consecutive holes until the fit residual is minimized. If the number of +spectra is greater than that supposedly drilled then sequences of +consecutive peaks are left out of the fit to minimize the residual. +The missing holes or extra peaks are printed out and, if allowed, the aperture +plate description file is modified, otherwise the program terminates. +In all cases if the final fit residual is greater than 1 +pixel the program will terminate. +The program prints out the \fIangle\fR of the aperture plate and the \fIscale\fR +which is also stored in the database. +.PP +An indication that a large part of the focus variation is purely a +scale change is that the derived image \fIscale\fR correlates very well with +the width of the spectra as derived from the profile fitting. I +estimate that at least 50% of the focus variation is a scale +variation. This is good news in the sense that a scale variation will +be taken out in the dispersion solution and lines in different parts +of the detector will become more similiar after the solution. +However, the scale variation does not account for all the profile +shape changes and there is indeed a change in the point spread function +across the detector. +.NH +Problems +.PP +There a few problems which I have not been able to resolve or have not +had the time to consider. The problems which are largely intractable +without a great deal of effort are the unexplained background +variations and deconvolving the spectra for the variation in the +point-spread-function. The background variations are abrupt increases +in the background in parts of the CRYOCAM detector. The step edge sometimes +occurs under the spectra and so any smooth polynomial fit to the +background will not be very good. The modeling of the multi-aperture +plate profiles provides information about the point-spread function +but a deconvolution of the variation in the PSF is a difficult problem +and not warrented at this time. +.PP +I had expected that the large scale response of the CRYOCAM could be +corrected by determining an overall average quartz spectrum from all the +extracted quartz spectra and then dividing the object spectra in each +hole by the ratio of the average quartz spectra from that hole to the +overall average quartz spectrum. This was attempted and it was found +to work only partially. Specifically, while there might be a 20% +difference between a spectrum on the edge and one near the center of +the detector the quartz correction left a 10% difference in the object +spectra. This is apparently due to a poor illumination by the quartz +light source which does not correspond to the telescope illumination. +This quartz correction technique may be made available to users if +desired. +.NH +Comparison with the Cyber Extraction Package +.PP +The discussion of this section must be qualified by the fact that I +have not used the Cyber Extraction Package and I base my understanding on the +algorithms from the Multi-Aperture Plate Data Reduction Manual and +conversations with knowledgable people. There are many differences +both major and minor and this section only seeks to mention the +some of the important differences. In the Cyber package: + +The background is subtracted from the images as a preliminary process. + +The background is either constant or linear across the spectra. + +The flat fields are produced by modeling the quartz and data from +several quartz exposures cannot be easily combined. + +The initial peak finding and aperture plate correlation algorithm is less +automated in determining missing or additional holes. + +The model fitting uses only a three parameter Gaussian model +and the algorithms do not yield results when the focus becomes poor. + +The fitting algorithm is neighbor subtraction rather than full +simultaneous solution for all the profiles. + +The model fitting is applied only to a quartz and the model is transfered to +object exposures. This does not allow the shape of the profiles to +change with time as the telescope moves. + +The modelling does not couple solutions for neighboring spectra +across the dispersion as is suggested in this design and it does smooth +along the spectra which is not done in this proposal. + +The extraction is only to some specified sigma in the model profile and +there is no attempt to correct for blending. + +There is no cleaning of the spectra. +.NH +Discussion +.PP +The only data which has passed beyond the extraction phase using the +algorithms described here was that of Paul Hintzen. +Comparison of data reduced by the TV package for +spectra extracted by both the Cyber package and the techniques of the +suggested \fBmultispec\fR package were quite comparable. To the level he +examined +the spectra there was no clear increase in accuracy though the \fBmultispec\fR +extractions generally had higher counts due to the full extraction of +the blended spectra. The big advantages found were +the ability to extract all the data even when the focus +became very poor and the success of the cosmic ray cleaning +algorithm. Thus, Hintzen feels that the need for speed in the extraction +(primarily dependent on the cleaning algorithm) +is modified significantly by the difficulty of dealing with cosmic +rays in the TV spectral analysis programs. More exploration +of techniques for determining the profile intensity scale from the +model without the full multi-parameter solution is warrented for this +reason. +.PP +I have extracted some Echelle data including field flattening. The +data had a considerable number of cosmic rays which were removed +quite well. The extracted spectra were put into a CAMERA format +for further analysis. +.PP +The programs were recently applied to a long slit analysis problem +being studied by Vesa Junkkarinen. The image was already flat fielded. +The data had two closely spaced and very faint diffuse objects and scattered +light from a nearby QSO. +The three spectra were so weak and closely spaced +that the automatic finding was not used. However, the rest of the modeling +and extraction were applied directly. +The \fBfind_bckgrnd\fR program, whose original purpose was to correct for +scattered light, worked well to extrapolate the sky across the +image. The model fitting accurately followed +the peaks of the spectra but the shape fitting was only moderately accurate +since the model shape parameters are not suited to modeling galaxies. +It successfully extracted spectra with a minimum of effort on my part. +Analysis of the extracted spectra and comparison with other techniques +must still be done. The conclusions to be drawn from this experiment are +that with sufficiently general multi-spectra tools multiple objects in +long slit spectroscopy can be handled. +.PP +One area in which I do not have practical experience is +the extraction of HGVS data. I believe +the proposed design will work on this type of data. +.PP +A point which needs to be considered in the final design are the +formats of the data files. The currently used one dimensional spectra +formats are an IIDS format and a CAMERA image format. +The formating of data files for the current spectral analysis packages by +\fBto_iids\fR starts from the \fBmultispec\fR database and throws away a lot +of information about the spectra. +Some refinement of this database should focus on the format +to be used by a new \fBIRAF\fR spectral analysis package. +.PP +It should be pointed out that many of the operations can have +alternate algorithms substituted. In particular, the smoothing +algorithm for the multi-aperture plate flat fields can be replaced by +some other scheme. The links between the multi-parameter fitting +program and the model have been made very general for investigating +a broad range of models. Thus, it is also possible to substitute +additional model profiles with relative ease. +.PP +Estimates of excution time are taken from the experimental C programs +implementing the algorithms of this design and they are only +approximate estimates. The steps corresponding +to \fBdebias\fR, \fBmultispec_flat\fR, and \fBflat_divide\fR for +the multi-aperture data from the CRYOCAM take +about 1 hour for a typical set of frames, say 5 to 15. This includes +debiasing, triming, computing a flat field from several quartz frames +and dividing the quartz into the object frames. +.PP +The CRYOCAM \fBmultiap_extract\fR phase takes about 40 minutes for the modeling of a frame using 32 lines per band and either 3 hours for an extraction +using the profile fitting +method or 14 minutes for extraction using the peak profile scaling +method. +.PP +Finally, the \fBto_iids\fR takes about 3 minutes per frame. It takes +this long because it has to convert the \fBmultispec\fR database organized across +the dispersion into formats in which the data is stored as consecutive +spectra; i.e. a type of rotation operation. diff --git a/noao/twodspec/multispec/doc/MSalgo_c.doc b/noao/twodspec/multispec/doc/MSalgo_c.doc new file mode 100644 index 00000000..b3322dff --- /dev/null +++ b/noao/twodspec/multispec/doc/MSalgo_c.doc @@ -0,0 +1,522 @@ +MULTISPEC (Dec83) Multispec Algorithms MULTISPEC (Dec83) + + + + Algorithms for the Multi-Spectra Extraction Package + Analysis and Discussion + December 2, 1983 + + + +1. Disclaimer + + This should not be taken as a statement of how the algorithms of +the final package should function; this is merely an analysis and +discussion of the algorithms, and should be followed by further +discussion before we decide what course to follow in the final +package. We may very well decide that the level of effort required to +implement rigorously correct nonlinear fitting algorithms is not +justified by the expected scientific usage of the package. Before we +can decide that, though, we need an accurate estimate of the level of +effort required. + +In attacking nonlinear surface fitting problems it is important to +recognize that almost any techniques can be made to yield a result +without the program crashing. Production of a result (extraction of a +spectrum) does not mean that the algorithm converged, that the +solution is unique, that the model is accurate, or that the +uncertainties in the computed coefficients have been minimized. + + + +2. Multispec Flat (pg. 4) + + This sounds like a classical high pass filter and might be best +implemented via convolution. Using a convolution operator with a +numerical kernel has the advantage that the filter can be easily +modifed by resampling the kernel or by changing the size of the +kernel. It is also quite efficient. The boundary extension feature +of IMIO makes it easy to deal with the problem of the kernel +overlapping the edge of the image in a convolution. Since the +convolution is one-dimensional (the image is only filtered in Y), it +will always be desirable to transpose the image. + +The method used to detect and reject bad pixels (eqn 1) is not correct. +The rejection criteria should be invariant with respect to a scaling +of the pixel values. If the data has gone through very much +processing (i.e., dtoi on photographic data), the relation between +photon counts and pixel value may be linear, but the scale is +unknown. Rejection by comparison of a data value to a "smoothed" +value is more commonly done as follows: + + reject if: abs (observed - smoothed) > (K * sigma) + +where sigma is the noise sigma of the data, generally a function of +the signal. + +It is often desirable in rejection algorithms to be able to specify, + + + -1- +MULTISPEC (Dec83) Multispec Algorithms MULTISPEC (Dec83) + + + +as an option, that all pixels within a specified radius of a bad pixel +be rejected, rather than just the pixel which was detected. This is +only unnecessary if the bad pixels are single pixel events (no +wings). Region rejection makes an iterative rejection scheme converge +faster, as well as rejecting the faint wings of the contaminated +region. + + + +2.1 Dividing by the Flat (pg. 5) + + There is no mention of any need for registering the flat with the +data field. Is it safe to assume that the quartz and the object +frames are precisely registered? What if the user does in fact +average several quartz frames taken over a period of time? (Image +registration is a general problem that is probably best left until +solved in IMAGES). + + + +3. Multiap Extraction (pg. 5-6, 8-13) + + The thing that bothers me most about the modeling and extraction +process is that the high signal to noize quartz information is not +used to full advantage, and the background is not fitted very +accurately. The present algorithms will work well for high signal to +noise data, but will result in large (percentage) errors for faint +spectra. + +Basically, it seems to me that the high signal to noise quartz spectra +should, in many cases, be used to determine the position and shape of +the spectral lines. This is especially attractive since the quartz +and spectra appear to be closely registered. Furthermore, if the +position-shape solution and extraction procedures are separate +procedures, there is nothing to prevent one from applying both to the +object spectum if necessary for some reason (i.e., poor registration, +better signal to noise in the object spectrum in the region of +interest, signal dependent distortions, lack of a quartz image, etc., +would all justify use of the object frame). It should be possible to +model either the quartz or the object frame, and to reuse a model for +more than one extraction. + +Let us divide the process up into two steps, "modeling", and +"extraction" (as it is now). The "calibration frame" may be the +quartz, an averaged quartz, or the object frame. Ideally it will have +a high signal to noise ratio and any errors in the background should +be negligible compared to the signal. + +We do not solve for the background while modeling the calibration +frame; we assume that the background has been fitted by any of a +variety of techniques and a background frame written before the +calibration frame is modeled. A "swath" is the average of several +image lines, where an image line runs across the dispersion, and a + + + -2- +MULTISPEC (Dec83) Multispec Algorithms MULTISPEC (Dec83) + + + +column along the dispersion. + + + +3.1 Modeling + + I would set the thing up to start fitting at any arbitrary swath, +rather than the first swath, because it not much harder, and there is +no guarantee that the calibration frame will have adequate signal to +noise in the first swath (indeed often the lowest signal to noise will +be found there). We define the "center" swath as the first swath to +be fitted, corresponding to the highest signal to noise region of the +calibration frame. By default the center swath should be the swath +used by find_spectra, especially if there is significant curvature in +the spectra. + +algorithm model_calibration_frame + +begin + extract center swath + initialize coeff using centers from find_spectra + model center swath (nonlinear) + + for (successive swaths upward to top of frame) { + extract swath + initialize coeff to values from last fit + model swath (nonlinear) + save coeff in datafile + } + + set last-fit coeff to values for center swath + for (successive swaths downward to bottom of frame) { + extract swath + initialize coeff to values from last fit + model swath (nonlinear) + save coeff in datafile + } + + smooth model coeff (excluding intensity) along the dispersion + [high freq variations in spectra center and shape from line] + [to line are nonphysical] + variance of a coeff at line-Y from the smoothed model value is + a measure of the uncertainty in that coeff. +end + + +I would have the background fitting routine write as output a +background frame, the name of which would be saved in the datafile, +rather than saving the coeff of the bkg fit in the datafile. The +background frame may then be produced by any of a number of +techniques; storing the coefficients of the bkg fit in the datafile +limits the technique used to a particular model. For similar reasons, +the standard bkg fitting routine should be broken up into a module + + + -3- +MULTISPEC (Dec83) Multispec Algorithms MULTISPEC (Dec83) + + + +which determines the region to be fitted, and a module which fits the +bkg pixels and writes the bkg image. + +For example, if the default background fitting routine is a line by +line routine, the output frame could be smoothed to remove the +(nonphysical) fluctuations in the background from line to line. A +true two dimensional background fitting routine may be added later +without requiring modifications to the datafile. Second order +corrections could be made to the background by repeating the solution +using the background fitted by the extraction procedure. + + +procedure extract_swath + +begin + extract raw swath from calibration frame + extract raw swath from background frame + return (calib swath minus bkg swath) +end + + +The algorithm used to simultaneously model all spectra in a swath from +across the dispersion is probably the most difficult and time consuming +part of the problem. The problem is nonlinear in all but one of the +four or more parameters for each spectra. You have spent a lot of +time on this and we are probably not going to be able to improve on +your algorithms significantly, though the generation of the matrix in +each step can probably be optimized significantly. + +The analytic line-profile model is the most general and should work +for most instruments with small circular apertures, even in the +presence of severe distortions. It should be possible, however, to +fit a simpler model given by a lookup table, solving only for the +position and height of each spectra. This model may be adequate for +many instruments, should be must faster to fit, and may produce more +accurate results since there are fewer parameters in the fit. The +disadvantage of an empirical model is that it must be accurately +interpolated (including the derivatives), requiring use of spline +interpolation or a similar technique (I have tried linear and it is +not good enough). Vesa has implemented procedures for fitting splines +and evaluating their derivatives. + +Fitting the empirical model simultaneously to any number of spectra +should be straightforward provided the signal to noise is reasonable, +since there are few parameters in the fit and the matrix is banded +(the Marquardt algorithm would work fine). However, if you ever have +to deal with data where a very faint or nonexistent spectra is next to +a bright one, it may be difficult to constrain the fit. I doubt if +the present approach of smoothing the coeff across the dispersion and +iterating would work in such a case. The best approach might be to +fix the center of the faint spectra relative to the bright one once +the signal drops below a certain level, or to drop it from the fit +entirely. This requires that the matrix be able to change size during + + + -4- +MULTISPEC (Dec83) Multispec Algorithms MULTISPEC (Dec83) + + + +the fit. + +algorithm fit_empirical_model + +begin + [upon entry, we already have an initial estimate of the coeff] + + # Marquardt (gradient expansion) algorithm. Make 2nd order + # Taylor's expansion to chisquare near minimum and solve for + # correction vector which puts us at minimum (subject to + # Taylor's approx). Taylor's approximation rapidly becomes + # better as we near the minimum of the multidimensional + # chisquare, hence convergence is extremely rapid given a good + # starting estimate. + + repeat { + evaluate curvature matrix using current coeff. + solve banded curvature matrix + + compute error matrix + for (each spectra) + if (uncertainty in center coeff > tol) { + fix center by estimation given relative spacing + in higher signal region + remove spectra center from solution + } + + if (no center coeff were rejected) + tweak correction vector to accelerate convergence + new coeff vector = old coeff vector + correction vector + compute norm of correction vector + } until (no more center coeff rejected and norm < tolerance) + + compute final uncertainties +end + + +The following is close to what is currently done to fit the analytic +model, as far as I can remember (I have modified it slightly to +stimulate discussion). The solution is broken up into two parts to +reduce the number of free parameters and increase stability. If the +uncertainty in a free parameter becomes large it is best to fix the +parameter (it is particularly easy for this data to estimate all but +the intensity parameter). A fixed parameter is used in the model and +affects the solution but is not solved for (i.e., like the background). + +The analytic fit will be rather slow, even if the outer loop is +constrained to one iteration. If it takes (very rough estimates) .5 +sec to set up the banded matrix and .3 sec to solve it, 3 iterations +to convergence, we have 5 sec per swath. If we have an 800 lines +broken into swaths of 32 lines, the total is 125 sec per image (to +within a factor of 5). + + + + -5- +MULTISPEC (Dec83) Multispec Algorithms MULTISPEC (Dec83) + + + +algorithm fit_analytic_model + +begin + [upon entry, we already have an initial estimate of the coeff] + + repeat { + save coeff + solve for center,height,width of each line with second + order terms fixed (but not necessarily zero) + apply constraints on line centers and widths + repeat solution adding second order coeff (shape terms) + + compute error matrix + for (each coeff) + if (uncertainty in coeff > tol) { + fix coeff value to reasonable estimate + remove coeff from solution + } + + compute total correction vector given saved coeff + if (no coeff were rejected) + tweak correction vector to accelerate convergence + compute norm of correction vector + } until (no additional coeff rejected and norm < tolerance) + + compute final uncertainties +end + + + +3.2 Extraction + + The purpose of extraction is to compute the integral of the spectra +across the dispersion, producing I(y) for each spectra. An estimate of +the uncertainty U(y) should also be produced. The basic extraction +techniques are summarized below. The number of spectra, spectra +centers, spectra width and shape parameters are taken from the model +fitted to the calibration frame as outlined above. We make a +simultaneous solution for the profile heights and the background (a +linear problem), repeating the solution independently for each line in +the image. For a faint spectrum, it is essential to determine the +background accurately, and we can do that safely here since the matrix +will be very well behaved. + + (1) Aperture sum. All of the pixels within a specified radius of + the spectra are summed to produce the raw integral. The + background image is also summed and subtracted to yield the + final integral. The radius may be a constant or a function of + the width of the profile. Fractional pixel techniques should + be used to minimize sampling effects at the boundaries of the + aperture. Pixel rejection is not possible since there is no + fitted surface. The model is used only to get the spectra + center and width. This technique is fastest and may be best + + + -6- +MULTISPEC (Dec83) Multispec Algorithms MULTISPEC (Dec83) + + + + if the profile is difficult to model, provided the spectra are + not crowded. + + (2) Weighted aperture sum. Like (1), except that a weighting + function is applied to correct for the effects of crowding. + The model is fitted to each object line, solving for I + (height) and B (background) with all other parameters fixed. + This is a linear solution of a banded matrix and should be + quite fast provided the model can be sampled efficiently to + produce the matrix. It is possible to iterate to reject bad + pixels. The weight for a spectra at a data pixel is the + fractional contribution of that spectra to the integral of the + contributions of all spectra. + + (3) Fit and integrate the model. The model is fitted as in (2) to + the data pixels but the final integral is produced by + integrating the model. This technique should be more + resistant to noise in the data than is (2), because we are + using the high signal to noise information in the model to + constrain the integral. More accurate photometric results + should therefore be possible. + + +Method (2) has the advantage that the integral is invariant with +respect to scale errors in the fitted models, provided the same error +is made in each model. Of course, the same error is unlikely to be +made in all models contributing to a point; it is more likely that an +error will put more energy into one spectra at the expense of its +neighbors. In the limit as the spectra become less crowded, however, +the effects of errors in neighboring spectra become small and the +weighted average technique looks good; it becomes quite insensitive to +errors in the model and in the fit. For crowded spectra there seems +no alternative to a good multiparameter fit. For faint spectra method +(3) is probably best, and fitting the background accurately becomes +crucial. + +In both (2) and (3), subtraction of the scaled models yields a residual +image which can be used to evaluate at a glance the quality of the fit. +Since most all of the effort in (2) and (3) is in the least squares +solution and the pixel rejection, it might be desirable to produce two +integrals (output spectra), one for each algorithm, as well as the +uncertainty vector (computed from the covariance matrix, not the +residual). + + + +3.3 Smoothing Coefficient Arrays + + In several places we have seen the need for smoothing coefficient +arrays. The use of polynomials for smoothing is questionable unless +the order of the polynomial is low (3 or less). High order +polynomials are notoriously bad near the endpoints of the fitted +array, unless the data curve happens to be a noisy low order + + + -7- +MULTISPEC (Dec83) Multispec Algorithms MULTISPEC (Dec83) + + + +polynomial (rare, to say the least). Convolution or piecewise +polynomial functions (i.e., the natural cubic smoothing spline) should +be considered if there is any reason to believe that the coefficient +array being smoothed may have high frequency components which are +physical and must be followed (i.e., a bend or kink). + + + +3.4 Weighting (pg. 11) + + The first weighting scheme (1 / sqrt (data)) seems inverted to me. +The noise goes up as with the signal, to be sure, but the signal to +noise usually goes up faster. Seems to me the weight estimate should +be sqrt(data). It also make more sense to weight the least blended +(peak) areas most. + + + +3.5 Rejection criteria (pg. 13) + + The same comments apply to this rejection criterium as in section +2. I assume that "(data - model)" is supposed to be "abs (data - +model"). + + + +3.6 Uncertainties and Convergence Criteria + + I got the impression that you were using the residual of the data +minus the fitted surface both as the convergence criterium and as a +measure of the errors in the fit. It is neither; assuming a perfect +model, the residual gives only a measure of the noise in the data. + +Using the residual to establish a convergence criterium seems +reasonable except that it is hard to reliably say what the criterium +should be. Assuming that the algorithm converges, the value of the +residual when convergence is acheived is in general hard to predict, +so it seems to me to be difficult to establish a convergence +criterium. The conventional way to establish when a nonlinear fit +converges is by measuring the norm of the correction vector. When the +norm becomes less than some small number the algorithm is said to have +converged. The multidimensional chisquare surface is parabolic near +the minimum and a good nonlinear algorithm will converge very rapidly +once it gets near the minimum. + +The residual is a measure of the overall goodness of fit, but tells us +nothing about the uncertainties in the individual coefficients of the +model. The uncertainties in the coefficients are given by the +covariance or error matrix (see Bevington pg. 242). It is ok to push +forward and produce an extraction if the algorithm fails to converge, +but ONLY provided the code gives a reliable estimate of the +uncertainty. + + + + -8- +MULTISPEC (Dec83) Multispec Algorithms MULTISPEC (Dec83) + + + +3.6 Evaluating the Curvature Matrix Efficiently + + The most expensive part of the reduction process is probably +evaluating the model to form the curvature matrix at each iteration in +the nonlinear solution. The most efficient way to do this is to use +lookup tables. If the profile shape does not change, the profile can +be sampled, fitted with a spline, and the spline evaluated to get the +zero through second derivatives for the curvature matrix. This can be +done even if the width of the profile changes by adding a linear +term. If the shape of the profile has to change, it is still possible +to sample either the gaussian or the exponential function with major +savings in computation time. + + + +3.7 Efficient Extraction (pg. 12) + + The reported time of 3 cpu hours to extract the spectra from an +800 line image is excessive for a linear solution. I would estimate +the time required for the 800 linear banded matrix solutions at 4-8 +minutes, with a comparable time required for matrix setup if it is +done efficiently. I suspect that the present code is not setting up +the linear banded matrix efficiently (not sampling the model +efficiently). Pixel rejection should not seriously affect the timings +assuming that bad pixels are not detected in most image lines. + + + +4. Correcting for Variations in the PSF + + For all low signal to noise data it is desirable to correct for +variations in the point spread function, caused by variable focus, +scattering, or whatever. This does not seem such a difficult problem +since the width of the line profile is directly correlated with the +width of the PSF and the information is provided by the current model +at each point in each extracted spectrum. The extracted spectra can +be corrected for the variation in the PSF by convolution with a spread +function the width of which varies along the spectrum. diff --git a/noao/twodspec/multispec/doc/MSalgo_c.hlp b/noao/twodspec/multispec/doc/MSalgo_c.hlp new file mode 100644 index 00000000..4b9c3356 --- /dev/null +++ b/noao/twodspec/multispec/doc/MSalgo_c.hlp @@ -0,0 +1,449 @@ +.help multispec Dec83 "Multispec Algorithms" +.ce +Algorithms for the Multi-Spectra Extraction Package +.ce +Analysis and Discussion +.ce +December 2, 1983 + +.sh +1. Disclaimer + + This should not be taken as a statement of how the algorithms of the +final package should function; this is merely an analysis and discussion +of the algorithms, and should be followed by further discussion before we +decide what course to follow in the final package. We may very well decide +that the level of effort required to implement rigorously correct nonlinear +fitting algorithms is not justified by the expected scientific usage of +the package. Before we can decide that, though, we need an accurate estimate +of the level of effort required. + +In attacking nonlinear surface fitting problems it is important to recognize +that almost any techniques can be made to yield a result without the program +crashing. Production of a result (extraction of a spectrum) does not mean +that the algorithm converged, that the solution is unique, that the model +is accurate, or that the uncertainties in the computed coefficients have +been minimized. + +.sh +2. Multispec Flat (pg. 4) + + This sounds like a classical high pass filter and might be best implemented +via convolution. Using a convolution operator with a numerical kernel has +the advantage that the filter can be easily modifed by resampling the kernel +or by changing the size of the kernel. It is also quite efficient. The +boundary extension feature of IMIO makes it easy to deal with the problem of +the kernel overlapping the edge of the image in a convolution. Since the +convolution is one-dimensional (the image is only filtered in Y), it will +always be desirable to transpose the image. + +The method used to detect and reject bad pixels (eqn 1) is not correct. +The rejection criteria should be invariant with respect to a scaling of the +pixel values. If the data has gone through very much processing (i.e., +dtoi on photographic data), the relation between photon counts and pixel value +may be linear, but the scale is unknown. Rejection by comparison of a data +value to a "smoothed" value is more commonly done as follows: + + reject if: abs (observed - smoothed) > (K * sigma) + +where sigma is the noise sigma of the data, generally a function of the signal. + +It is often desirable in rejection algorithms to be able to specify, +as an option, that all pixels within a specified radius of a bad pixel +be rejected, rather than just the pixel which was detected. This is only +unnecessary if the bad pixels are single pixel events (no wings). Region +rejection makes an iterative rejection scheme converge faster, as well as +rejecting the faint wings of the contaminated region. + +.sh +2.1 Dividing by the Flat (pg. 5) + + There is no mention of any need for registering the flat with the data +field. Is it safe to assume that the quartz and the object frames are +precisely registered? What if the user does in fact average several quartz +frames taken over a period of time? (Image registration is a general +problem that is probably best left until solved in IMAGES). + +.sh +3. Multiap Extraction (pg. 5-6, 8-13) + + The thing that bothers me most about the modeling and extraction +process is that the high signal to noize quartz information is not used to +full advantage, and the background is not fitted very accurately. The +present algorithms will work well for high signal to noise data, but +will result in large (percentage) errors for faint spectra. + +Basically, it seems to me that the high signal to noise quartz spectra +should, in many cases, be used to determine the position and shape of the +spectral lines. This is especially attractive since the quartz and spectra +appear to be closely registered. Furthermore, if the position-shape solution +and extraction procedures are separate procedures, there is nothing to prevent +one from applying both to the object spectum if necessary for some reason +(i.e., poor registration, better signal to noise in the object spectrum in +the region of interest, signal dependent distortions, lack of a quartz image, +etc., would all justify use of the object frame). It should be possible to +model either the quartz or the object frame, and to reuse a model for more +than one extraction. + +Let us divide the process up into two steps, "modeling", and "extraction" +(as it is now). The "calibration frame" may be the quartz, an averaged +quartz, or the object frame. Ideally it will have a high signal to noise +ratio and any errors in the background should be negligible compared to +the signal. + +We do not solve for the background while modeling the calibration frame; +we assume that the background has been fitted by any of a variety of +techniques and a background frame written before the calibration frame +is modeled. A "swath" is the average of several image lines, where an +image line runs across the dispersion, and a column along the dispersion. + +.sh +3.1 Modeling + + I would set the thing up to start fitting at any arbitrary swath, rather +than the first swath, because it not much harder, and there is no guarantee +that the calibration frame will have adequate signal to noise in the first +swath (indeed often the lowest signal to noise will be found there). +We define the "center" swath as the first swath to be fitted, corresponding +to the highest signal to noise region of the calibration frame. By default +the center swath should be the swath used by find_spectra, especially if +there is significant curvature in the spectra. + +.ks +.nf +algorithm model_calibration_frame + +begin + extract center swath + initialize coeff using centers from find_spectra + model center swath (nonlinear) + + for (successive swaths upward to top of frame) { + extract swath + initialize coeff to values from last fit + model swath (nonlinear) + save coeff in datafile + } + + set last-fit coeff to values for center swath + for (successive swaths downward to bottom of frame) { + extract swath + initialize coeff to values from last fit + model swath (nonlinear) + save coeff in datafile + } + + smooth model coeff (excluding intensity) along the dispersion + [high freq variations in spectra center and shape from line] + [to line are nonphysical] + variance of a coeff at line-Y from the smoothed model value is + a measure of the uncertainty in that coeff. +end +.fi +.ke + + +I would have the background fitting routine write as output a background +frame, the name of which would be saved in the datafile, rather than saving +the coeff of the bkg fit in the datafile. The background frame may then +be produced by any of a number of techniques; storing the coefficients of +the bkg fit in the datafile limits the technique used to a particular model. +For similar reasons, the standard bkg fitting routine should be broken up +into a module which determines the region to be fitted, and a module which +fits the bkg pixels and writes the bkg image. + +For example, if the default background fitting routine is a line by line +routine, the output frame could be smoothed to remove the (nonphysical) +fluctuations in the background from line to line. A true two dimensional +background fitting routine may be added later without requiring modifications +to the datafile. Second order corrections could be made to the background +by repeating the solution using the background fitted by the extraction +procedure. + + +.ks +.nf +procedure extract_swath + +begin + extract raw swath from calibration frame + extract raw swath from background frame + return (calib swath minus bkg swath) +end +.fi +.ke + + +The algorithm used to simultaneously model all spectra in a swath from +across the dispersion is probably the most difficult and time consuming +part of the problem. The problem is nonlinear in all but one of the four +or more parameters for each spectra. You have spent a lot of time on this +and we are probably not going to be able to improve on your algorithms +significantly, though the generation of the matrix in each step can +probably be optimized significantly. + +The analytic line-profile model is the most general and should work for most +instruments with small circular apertures, even in the presence of severe +distortions. It should be possible, however, to fit a simpler model given +by a lookup table, solving only for the position and height of each spectra. +This model may be adequate for many instruments, should be must faster to +fit, and may produce more accurate results since there are fewer parameters +in the fit. The disadvantage of an empirical model is that it must be +accurately interpolated (including the derivatives), requiring use of spline +interpolation or a similar technique (I have tried linear and it is not good +enough). Vesa has implemented procedures for fitting splines and evaluating +their derivatives. + +Fitting the empirical model simultaneously to any number of spectra should +be straightforward provided the signal to noise is reasonable, since there +are few parameters in the fit and the matrix is banded (the Marquardt +algorithm would work fine). However, if you ever have to deal with data +where a very faint or nonexistent spectra is next to a bright one, it may +be difficult to constrain the fit. I doubt if the present approach of +smoothing the coeff across the dispersion and iterating would work in such +a case. The best approach might be to fix the center of the faint spectra +relative to the bright one once the signal drops below a certain level, +or to drop it from the fit entirely. This requires that the matrix be able +to change size during the fit. + +.ks +.nf +algorithm fit_empirical_model + +begin + [upon entry, we already have an initial estimate of the coeff] + + # Marquardt (gradient expansion) algorithm. Make 2nd order + # Taylor's expansion to chisquare near minimum and solve for + # correction vector which puts us at minimum (subject to + # Taylor's approx). Taylor's approximation rapidly becomes + # better as we near the minimum of the multidimensional + # chisquare, hence convergence is extremely rapid given a good + # starting estimate. + + repeat { + evaluate curvature matrix using current coeff. + solve banded curvature matrix + + compute error matrix + for (each spectra) + if (uncertainty in center coeff > tol) { + fix center by estimation given relative spacing + in higher signal region + remove spectra center from solution + } + + if (no center coeff were rejected) + tweak correction vector to accelerate convergence + new coeff vector = old coeff vector + correction vector + compute norm of correction vector + } until (no more center coeff rejected and norm < tolerance) + + compute final uncertainties +end +.fi +.ke + + +The following is close to what is currently done to fit the analytic +model, as far as I can remember (I have modified it slightly to stimulate +discussion). The solution is broken up into two parts to reduce the number +of free parameters and increase stability. If the uncertainty in a free +parameter becomes large it is best to fix the parameter (it is particularly +easy for this data to estimate all but the intensity parameter). A fixed +parameter is used in the model and affects the solution but is not solved +for (i.e., like the background). + +The analytic fit will be rather slow, even if the outer loop is constrained +to one iteration. If it takes (very rough estimates) .5 sec to set up the +banded matrix and .3 sec to solve it, 3 iterations to convergence, we have +5 sec per swath. If we have an 800 lines broken into swaths of 32 lines, +the total is 125 sec per image (to within a factor of 5). + + +.ks +.nf +algorithm fit_analytic_model + +begin + [upon entry, we already have an initial estimate of the coeff] + + repeat { + save coeff + solve for center,height,width of each line with second + order terms fixed (but not necessarily zero) + apply constraints on line centers and widths + repeat solution adding second order coeff (shape terms) + + compute error matrix + for (each coeff) + if (uncertainty in coeff > tol) { + fix coeff value to reasonable estimate + remove coeff from solution + } + + compute total correction vector given saved coeff + if (no coeff were rejected) + tweak correction vector to accelerate convergence + compute norm of correction vector + } until (no additional coeff rejected and norm < tolerance) + + compute final uncertainties +end +.fi +.ke + +.sh +3.2 Extraction + + The purpose of extraction is to compute the integral of the spectra +across the dispersion, producing I(y) for each spectra. An estimate of +the uncertainty U(y) should also be produced. The basic extraction techniques +are summarized below. The number of spectra, spectra centers, spectra width +and shape parameters are taken from the model fitted to the calibration +frame as outlined above. We make a simultaneous solution for the profile +heights and the background (a linear problem), repeating the solution +independently for each line in the image. For a faint spectrum, it is +essential to determine the background accurately, and we can do that safely +here since the matrix will be very well behaved. +.ls 4 +.ls (1) +Aperture sum. All of the pixels within a specified radius of the spectra +are summed to produce the raw integral. The background image is also summed +and subtracted to yield the final integral. The radius may be a constant or a +function of the width of the profile. Fractional pixel techniques should +be used to minimize sampling effects at the boundaries of the aperture. +Pixel rejection is not possible since there is no fitted surface. The model +is used only to get the spectra center and width. This technique is fastest +and may be best if the profile is difficult to model, provided the spectra +are not crowded. +.le +.ls (2) +Weighted aperture sum. Like (1), except that a weighting function is +applied to correct for the effects of crowding. The model is fitted +to each object line, solving for I (height) and B (background) with all +other parameters fixed. This is a linear solution of a banded matrix and +should be quite fast provided the model can be sampled efficiently to +produce the matrix. It is possible to iterate to reject bad pixels. +The weight for a spectra at a data pixel is the fractional contribution +of that spectra to the integral of the contributions of all spectra. +.le +.ls (3) +Fit and integrate the model. The model is fitted as in (2) to the data +pixels but the final integral is produced by integrating the model. +This technique should be more resistant to noise in the data than is (2), +because we are using the high signal to noise information in the model to +constrain the integral. More accurate photometric results should therefore +be possible. +.le +.le + + +Method (2) has the advantage that the integral is invariant with respect +to scale errors in the fitted models, provided the same error is made in +each model. Of course, the same error is unlikely to be made in all +models contributing to a point; it is more likely that an error will put +more energy into one spectra at the expense of its neighbors. In the limit +as the spectra become less crowded, however, the effects of errors in +neighboring spectra become small and the weighted average technique looks +good; it becomes quite insensitive to errors in the model and in the fit. +For crowded spectra there seems no alternative to a good multiparameter +fit. For faint spectra method (3) is probably best, and fitting the +background accurately becomes crucial. + +In both (2) and (3), subtraction of the scaled models yields a residual +image which can be used to evaluate at a glance the quality of the fit. +Since most all of the effort in (2) and (3) is in the least squares solution +and the pixel rejection, it might be desirable to produce two integrals +(output spectra), one for each algorithm, as well as the uncertainty vector +(computed from the covariance matrix, not the residual). + +.sh +3.3 Smoothing Coefficient Arrays + + In several places we have seen the need for smoothing coefficient arrays. +The use of polynomials for smoothing is questionable unless the order of +the polynomial is low (3 or less). High order polynomials are notoriously +bad near the endpoints of the fitted array, unless the data curve happens +to be a noisy low order polynomial (rare, to say the least). Convolution or +piecewise polynomial functions (i.e., the natural cubic smoothing spline) +should be considered if there is any reason to believe that the coefficient +array being smoothed may have high frequency components which are physical and +must be followed (i.e., a bend or kink). + +.sh +3.4 Weighting (pg. 11) + + The first weighting scheme (1 / sqrt (data)) seems inverted to me. +The noise goes up as with the signal, to be sure, but the signal to noise +usually goes up faster. Seems to me the weight estimate should be sqrt(data). +It also make more sense to weight the least blended (peak) areas most. + +.sh +3.5 Rejection criteria (pg. 13) + + The same comments apply to this rejection criterium as in section 2. +I assume that "(data - model)" is supposed to be "abs (data - model"). + +.sh +3.6 Uncertainties and Convergence Criteria + + I got the impression that you were using the residual of the data minus +the fitted surface both as the convergence criterium and as a measure of the +errors in the fit. It is neither; assuming a perfect model, the residual gives +only a measure of the noise in the data. + +Using the residual to establish a convergence criterium seems reasonable +except that it is hard to reliably say what the criterium should be. +Assuming that the algorithm converges, the value of the residual when +convergence is achieved is in general hard to predict, so it seems to me to +be difficult to establish a convergence criterium. The conventional way +to establish when a nonlinear fit converges is by measuring the norm of +the correction vector. When the norm becomes less than some small number +the algorithm is said to have converged. The multidimensional chisquare +surface is parabolic near the minimum and a good nonlinear algorithm will +converge very rapidly once it gets near the minimum. + +The residual is a measure of the overall goodness of fit, but tells us +nothing about the uncertainties in the individual coefficients of the model. +The uncertainties in the coefficients are given by the covariance or error +matrix (see Bevington pg. 242). It is ok to push forward and produce an +extraction if the algorithm fails to converge, but ONLY provided the code +gives a reliable estimate of the uncertainty. + +.sh +3.6 Evaluating the Curvature Matrix Efficiently + + The most expensive part of the reduction process is probably evaluating +the model to form the curvature matrix at each iteration in the nonlinear +solution. The most efficient way to do this is to use lookup tables. +If the profile shape does not change, the profile can be sampled, fitted +with a spline, and the spline evaluated to get the zero through second +derivatives for the curvature matrix. This can be done even if the width +of the profile changes by adding a linear term. If the shape of the profile +has to change, it is still possible to sample either the gaussian or the +exponential function with major savings in computation time. + +.sh +3.7 Efficient Extraction (pg. 12) + + The reported time of 3 cpu hours to extract the spectra from an 800 line +image is excessive for a linear solution. I would estimate the time required +for the 800 linear banded matrix solutions at 4-8 minutes, with a comparable +time required for matrix setup if it is done efficiently. I suspect that the +present code is not setting up the linear banded matrix efficiently (not +sampling the model efficiently). Pixel rejection should not seriously affect +the timings assuming that bad pixels are not detected in most image lines. + +.sh +4. Correcting for Variations in the PSF + + For all low signal to noise data it is desirable to correct for variations +in the point spread function, caused by variable focus, scattering, or +whatever. This does not seem such a difficult problem since the width of +the line profile is directly correlated with the width of the PSF and the +information is provided by the current model at each point in each extracted +spectrum. The extracted spectra can be corrected for the variation in the +PSF by convolution with a spread function the width of which varies along +the spectrum. +.endhelp diff --git a/noao/twodspec/multispec/doc/MSspecs.doc b/noao/twodspec/multispec/doc/MSspecs.doc new file mode 100644 index 00000000..09955e9c --- /dev/null +++ b/noao/twodspec/multispec/doc/MSspecs.doc @@ -0,0 +1,698 @@ +MULTISPEC (Oct83) Multi-Spectra Extraction Package MULTISPEC (Oct83) + + + + Detailed Specifications for the Multi-Spectra Extraction Package + F. Valdes + December 8, 1983 + + +1. Introduction + + The multi-spectra extraction package (MULTISPEC) provides the +basic tools for modeling, cleaning, and extracting spectra from images +containing multiple aperture spectra running roughly parallel. These +tools will generally be combined in reduction script tasks but may +also be used directly for non-standard analysis. + + This design presents the requirements and specifications for the +MULTISPEC package. Details concerning the algorithms are given in a +separate document, Algorithms for the Multi-Spectra Extraction Package. + + +2. Input Data Requirements + + The input data for the MULTISPEC package consists of image files +containing one or more aperture spectra. The spectra are required to +run roughly parallel to each other and parallel to the second +digitization axis. The latter requirement may require a general +rotation and interpolation image operator. The images are assumed to +be corrected to linear relative intensity. Thus, the steps of +correcting digital detector images for dark current, bias, and +pixel-to-pixel sensitivity variations must be performed before using +the MULTISPEC tasks. + + Because the the MULTISPEC package is being developed concurrently +with the IRAF standard image processing tools this document specifies +the requirements for the preliminary image processing needed to +prepare digital detector images for the MULTISPEC package. + + +2.1 Basic Digital Detector Reduction Tasks + + The prelimary reduction of multi-spectra images uses CL scripts +based on general image operators. Some of the scripts are for +specific instruments or specific reduction applications and some are +generally useful image processing tasks. The scripts allow the +specification of many images for which the operations will be +repetitively applied. + + The following CL scripts are required to reduce multi-spectra +images from digital detectors. + + + debias multispec_flat flat_divide + + + + + + -1- +MULTISPEC (Oct83) Multi-Spectra Extraction Package MULTISPEC (Oct83) + + + +debias + The files in a list of filenames are automatically debiased and + trimmed. This routine will be instrument specific but used by + other reduction tasks beyond MULTISPEC. + +multispec_flat + The files in a list of quartz multi-spectra filenames are added, + the result is smoothed along the dispersion dimension, and then + the original image is divided by the smoothed image to produce a + flat field image. The unsmoothed to smoothed ratio is computed + only if the value of the smoothed pixel is greater than a + specified amount. Otherwise, the ratio is set to unity. This + routine is not instrument specific but is used only for MULTISPEC + reductions. + +flat_divide + The files in a list of filenames are each divided by a specified + flat field image. This routine is not instrument or application + specific. + + The required general image processing programs needed to implement +these scripts are specified below. + + +(1) A routine to compute the average value from a specified area of the + image. Used to determine the average bias value from a bias strip. + +(2) A routine to trim a specified portion of an image. Used to trim + the bias strip. + +(3) Routines to multiply and subtract images by a constant. Used to + scale images such as dark exposures and to remove the average bias + value as obtained by (1) above. + +(4) Routines to subtract, add, and divide images. Used to subtract + dark current and bias exposures, to add several exposures to + increase the signal-to-noise, and to divide by a flat field image. + The divide routine must give the user the option to substitute a + constant or ignore any divisions in which the denominator is less + than a specified value. + +(5) A routine to rotate or transpose an image. Used to align the + spectra along lines or columns. + +(6) A routine to apply a filter to lines of the image. For + multi-spectra images a smooth quartz is produced by using a + running quadratic filter along each line of the dispersion + dimension. The filter must be able to recognize bad pixels + (specified by a user defined threshold) and remove them from the + filtering operation. + + + + + + -2- +MULTISPEC (Oct83) Multi-Spectra Extraction Package MULTISPEC (Oct83) + + + +3. Requirements for the MULTSPEC Package + + The MULTISPEC package shall satisfy the following requirements. + +(1) The component programs shall be CL callable. + +(2) The programs shall interact only through image files and MULTISPEC + data files. + +(3) It shall be possible to extract spectra without modeling. + +(4) The entire image shall be extracted and not limited by failures in + the algorithms. + +(5) It shall be possible to specify specific lines or swaths in the + image on which to operate. + +(6) CL scripts shall be provided for the common data sources. These + scripts will work automatically. + +The follow functions shall be provided: + +o Make an initial rough but automated identification of the spectra + locations. + +o Provide for a user identification list for the spectra locations. + This list shall be of the standard image cursor type to allow + generation of the list with the standard image cursor programs. + +o Determine and correct for a slowly varying background. + +o Reliably and accurately trace spectra in the presence of geometric + distortions (pincushion, s, shear, etc.). + +o Extract spectra by one of: + + a. Strips of constant width about the located spectra. The width + may be specified to fractions of a pixel and the extraction + will use fractional pixel interpolation. l + + b. Strips of width proportional to a Gaussian width parameter. + + c. Modeling to obtain estimates of the total luminosity. The + estimate will be the integral of the model. + + d. Summation of the data pixel values with fractional + contributions of the pixel value to the spectra based on + modeling. + +o An option shall be available to specify whether to ignore blank + pixels or use interpolated values. + + o Programs shall be provided to produce data files which can be + + + -3- +MULTISPEC (Oct83) Multi-Spectra Extraction Package MULTISPEC (Oct83) + + + + accessed by one dimensional spectroscopic reduction routines. + At a minimum these formats shall include: + + a. Reduction to an image file consisting of one line per + extracted spectrum + + b. The standard IIDS format available with the CYBER + Multi-Aperture Plate programs + + +3.2 Modeling Requirements + + The modeling of multi-spectra images, particularly in the case of +blended spectra, shall: + +(1) Model blended spectra with sufficient reliability and robustness + that a reasonable solution is always obtained, though of possibly + limited usefulness. + +(2) The modeling shall provide estimates for the uncertainties in the + fitted parameters as a function of position along the spectrum. + +(3) Remove cosmic rays and other defective pixels by reference to the + model. + +(4) Allow the transfer of a model solution for one image to another + image. + +(5) Display numerically and graphically the data, the fitted model, and + the residuals. + + +4. Program Specifications + + +4.1 Basic Programs + + The basic programs of the package are general purpose tools which +initialize a MULTISPEC data file and perform a single fundamental +operation on the data in the MULTISPEC data file. There is one data +file associated with each image. The data file is hidden from the +user and so the user need not be aware of the data file. The data +files are referenced only the image filename specified in the program +parameters. The data files contain such information as a processing +history, the spectra positions and extracted luminosities, the model +parameters (one set for each spectra for each modelled image line (or +swath), etc. The programs generally are allowed to specify specific +lines, columns, and/or spectra on which to operate. The line, column +and spectra specifications are given as strings which contain numbers +separated by whitespace, commas, and the range indicator "-". The +script tasks of section 4.2 will combine these basic programs to +perform a general multi-spectra extraction. + + + + -4- +MULTISPEC (Oct83) Multi-Spectra Extraction Package MULTISPEC (Oct83) + + + + ap_plate copy_params find_spectra convolve + fit_bckgrnd find_bckgrnd line_list model_extrac + model_fit model_image model_list sigma_extract + strip_extract to_iids to_image to_onedspec + +ap_plate + The information from an on-line data file containing descriptions + of all the aperture plates prepared at Kitt Peak is read to find a + specified aperture plate. The drilled aperture positions are + correlated with the spectra in the image to deduce relative + wavelength offsets. The identifications for the spectra as well + as other auxiliary information is recorded in the data file. If + no image file is specified then only the aperture plate + information is printed. This program is used in the + MULTIAP_EXTRACT program. This program is not essential to the + operation of the MULTISPEC package. + + Multi-Spectra image image = + Aperture plate plate = + (mode = ql) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -5- +MULTISPEC (Oct83) Multi-Spectra Extraction Package MULTISPEC (Oct83) + + + +The Background + The are two possibilities for dealing with the background. In the + first case, FIT_BCKGRND, the background will be fitted by + polynomials and the coefficients stored in the MULTISPEC data + file. These coefficients are then used by the other programs to + estimate the background at the spectra. The second option, + FIND_BCKGRND, generates a background image in which the spectra + and other selected areas are set to blank pixels. Then a general + image interpolator is used fill in the blank pixels with background + estimates. The other MULTISPEC programs will then access this + background frame. The background frame image name will be stored + in the MULTISPEC data file and the image header. + + + fit_bckgrnd + Fit a background in a MULTISPEC image by a polynomial using + pixels not near the spectra and in the user specified swaths + and columns. The buffer distance is in pixels and refers to a + minimum distance from the center of any spectrum beyond which + the background pixels are found. Blank pixels are ignored in + the background fit. Deviant pixels will be rejected. + + Multi-Spectra image image = + Buffer from spectra buffer = 12 + Polynomial order order = 3 + Lines per swath (lines_per_swath = 32) + Swaths to fit (swaths = 1-1000) + Columns to fit (columns = 1-1000) + Rejection threshold (threshold = 5) + Print general diagnostics (verbose = no) + (mode = ql) + + find_bckgrnd + The spectra within a buffer distance and specified areas are + set to blank pixels and the remaining pixels copied to a + background image file. + + Multi-Spectra image image = + Background image background = + Buffer from spectra buffer = 12 + Lines to ignore (lines = ) + Columns to ignore (columns = ) + (mode = ql) + +convolve + A program will be provided to reduce either the extracted spectrum + or the modeled image to a common point-spread function. + + + + + + + + + -6- +MULTISPEC (Oct83) Multi-Spectra Extraction Package MULTISPEC (Oct83) + + + +copy_params + Create a MULTISPEC data file for a new image using appropriate + MULTISPEC parameters from an old image. The old image must have + been processed to find the spectra using FIND_SPECTRA and possibly + model fit. + + Old Multi-Spectra image old_image = + New Multi-Spectra image new_image = + (mode = ql) + +find_spectra + Initially locate the spectra in a MULTISPEC image. The positions + of the spectra within the range of columns are determined for the + starting line and then the spectra are tracked within the range of + lines. The minimum separation and minimum width would generally + be set for a particular instrument. If the automatic search is + not used then a list of cursor positions is read from the standard + input. + + Multi-Spectra image image = + Automatic search auto = yes + Starting line start_line = + Minimum separation (min_sep = 1) + Minimum width (min_width = 1) + Averaging width (average = 32) + Lines to search (lines = 1-1000) + Columns to search (columns = 1-1000) + Print general diagnostics (verbose = no) + (mode = ql) + +line_list + For the specified lines in the image print the image column + number, data value (possibly as a swath average), the model value + at that point (i.e. the sum of the model contributions from all + the spectra), the background value, and the residual. Plotting + scripts may be written using this routine to show the quality of a + model fit. + + Multi-Spectra image image = + Lines to list (lines = 1-1000) + (mode = ql) + + + + + + + + + + + + + + + -7- +MULTISPEC (Oct83) Multi-Spectra Extraction Package MULTISPEC (Oct83) + + + +model_extract + A previously fitted model is used to extract the spectra total + luminosity by apportioning the data values to spectra in the ratio + indicated by the model. If the clean option is specified then the + model is used to detect pixels which deviate from the model by a + specified amount. The model value replaces the deviant pixel in + the extraction and, if specified, also in the image file. + + Multi-Spectra image image = + Lines to extract (lines = 1-1000) + Clean spectra (clean = yes) + Cleaning threshold (threshold = 5) + Modify image (modify = yes) + Print general diagnostics (verbose = no) + (mode = ql) + +model_fit + A specified model is iteratively fitted to the data in each of the + specified lines (or swaths) until the RMS residual fails to + decrease. The models are selected by a string. The possible + values are + + (null string) - initialize the model + i - fit only the intensity scale + ip - fit the intensity scale and the position + ips1 - fit the intensity scale, position, and one parameter shape + ips2 - fit the intensity scale, position, and two parameter shape + ips3 - fit the intensity scale, position, and three parameter shape + ips4 - fit the intensity scale, position, and four parameter shape + These models will be combined in a script to search for the best + fit. + + The initial shape parameters will generally be set by scripts for a + particular data reduction. + + Multi-Spectra image image = + Model type model = + Lines per swath (lines_per_swath = 32) + Swaths to model (swaths = 1-1000) + Initial shape1 (shape1 = .1 ) + Initial shape2 (shape2 = 0 ) + Initial shape3 (shape3 = 0 ) + Initial shape4 (shape4 = 5 ) + Print general diagnostics (verbose = no) + (mode = ql) + + + + + + + + + + + -8- +MULTISPEC (Oct83) Multi-Spectra Extraction Package MULTISPEC (Oct83) + + + +model_image + An image file of the fitted model is created. This image may then + be displayed or a residual image may be calculated and displayed. + + Multi-Spectra image image = + Model image model = + (mode = ql) + .nf + .le + .ls model_list + For the specified lines and spectra the model is listed. + The listing gives, for each spectra, + the spectrum number, the line number, the fitted position, + the estimated wavelength, the + extracted luminosity, the intensity scale, model width parameters, and + the background polynomial coefficients. This routine can be used in scripts + to plot the extracted spectra, the trend of width with wavelength, and so + forth. + + .nf + Multi-Spectra image image = + Lines to list (lines = 1-1000) + Spectra to list (spectra = 1-1000) + (mode = ql) + +sigma_extract + A previously fitted model is used to extract the spectra luminosity + within a specified sigma of the peak. Because the model is not + necessarily a Gaussian the sigma is used to compute the intensity + ratio of the cutoff to the peak assumining a Gaussian profile and + then the data is extracted to the point the model intensity falls + below that cutoff. If the clean option is specified then the + model is used to detect pixels which deviate from the model by a + specified amount. The model value replaces the deviant pixel in + the extraction and, if specified, also in the image file. + + Multi-Spectra image image = + Sigma extraction width width = 1. + Lines to extract (lines = 1-1000) + Clean spectra (clean = yes) + Cleaning threshold (threshold = 5) + Modify image (modify = yes) + Print general diagnostics (verbose = no) + (mode = ql) + + + + + + + + + + + + -9- +MULTISPEC (Oct83) Multi-Spectra Extraction Package MULTISPEC (Oct83) + + + +strip_extract + A strip of constant width about the spectra positions is extracted. + If cleanning is desired a smoothed estimate of the profile is + obtained by averaging a number of lines about the line to be + cleaned. After fitting for the intensity scale pixels are found + which deviate from the profile by a specified amount. The profile + value replaces the deviant pixel in the extraction and, if + specified, also in the image file. No prior modeling is required + to use this extraction routine. + + Multi-Spectra image image = + Strip extraction width width = 1. + Lines to extract (lines = 1-1000) + Clean spectra (clean = yes) + Cleaning threshold (threshold = 5) + Lines per profile average (averge_lines = 32) + Modify image (modify = yes) + Print general diagnostics (verbose = no) + (mode = ql) + +to_iids + For a specified prefix, files of the form prefix.nn, where nn is a + specified spectra number, are created containing the extracted + spectra for all the specified image files. The format of the + files is the IIDS format developed for the CYBER Multi-Aperture + Plate Extractions. + + Multi-Spectra image images = + IIDS filename prefix iids_file = + Spectra to format (spectra = 1-1000) + (mode = ql) + +to_image + An image file containing one line of the extracted luminosities + for each specified spectra in the specified MULTISPEC image. + + Multi-Spectra image in_image = + Extracted spectra image out_image = + Spectra (spectra = 1-1000) + (mode = ql) + +to_onedspec + The extractions are converted to an as yet to be specified format + for use in the ONEDSPEC reduction package. + + Multi-Spectra images images = + ONEDSPEC data file onedspec_file = + Spectra (spectra = 1-1000) + (mode = ql) + + + + + + + -10- +MULTISPEC (Oct83) Multi-Spectra Extraction Package MULTISPEC (Oct83) + + + +4.2 General MULTISPEC CL Scripts + + The general MULTISPEC CL scripts perform a series of steps needed +to extract the spectra from a specified list of image files. These +steps have been found to generally perform the desired extraction task +fully. + + + multiap_extract echelle_extract + +multiap_extract + The specified multi-aperture plate images are extracted. If no + starting solution image, one which has previously been extracted, + is specified then the script performs an automatic search for the + specified number of spectra. Otherwise the solution from the + starting image is used as the initial model. The background is + then determined. This is followed by a series of fitting steps on + swaths of data. (For further details on the fitting steps see the + Algorithms paper). A MODEL_EXTRACT and cleaning follows. + Finally, the extraction is correlated with the specified aperture + plate using AP_PLATE. If there was no starting image then this + extraction becomes the initial solution image. Subsequent images + are extracted starting from the initial solution image. + + Multi-Aperture images images = + Initial solution image initial = + Aperture plate number plate = + Number of spectra nspectra = + (mode = ql) + +echelle_extract + The specified echelle images are extracted. If no starting + solution image, one which has previously been extracted, is + specified then the script performs an automatic search for the + specified number of orders. Otherwise the solution from the + starting image is used as the initial starting point. The + background is then determined. Finally a STRIP_EXTRACT and + cleaning is performed. If there was no starting image then this + extraction becomes the initial solution image. Subsequent images + are extracted starting from the initial solution image. + + Echelle images images = + Initial solution image initial = + Number of orders norders = + Extraction width width = + (mode = ql) + + +5. Outline of a MULTISPEC Reduction + + The following outline is for the reduction of a cryogenic camera +multi-aperture plate. All the programmer supplied default values are +used. + + + -11- +MULTISPEC (Oct83) Multi-Spectra Extraction Package MULTISPEC (Oct83) + + + + (1) rcamera mtb, "ap165.", "s", "3-9" + (2) debias "ap165.*" + (3) multispec_flat "ap165.[36]", "ap165.flat" + (4) flat_divide "ap165.*", "ap165.flat" + (5) multiap_extract "ap165.*", "", 165, 50 + (6) to_onedspec "ap165.*", oned165 + + +(1) The data is read from the observing tape(s) using RCAMERA. The + image files created are ap165.3, ap165.4, ..., ap165.9. This is + easily accomplished by using the filename prefix "ap165." in the + RCAMERA program. The raw images may be examined at this point on + a display. + +(2) The images are debiased using DEBIAS with all the "ap165." files + specified. The debias program knows about the location of the + bias strip for the cryogenic camera. + +(3) A a flat field is created using MULTISPEC_FLAT in which the + desired quartz frames are specified and a flat field image + filename is defined. The created flat field image may be examined + on an image display if desired. + +(4) All the debiased images are divided by the flat field using + FLAT_DIVIDE. + +(5) The script MULTIAP_EXTRACT is run in which the aperture plate + number, the number of spectra, and the image files to be extracted + are specified. The number of spectra is found by examining an + image on an image display or by plotting a cut across the spectra + using a general image profile program. + +(6) Finally, the extracted spectra are formatted for the ONEDSPEC + package using TO_ONEDSPEC with the extracted images specified. diff --git a/noao/twodspec/multispec/doc/MSspecs.hlp b/noao/twodspec/multispec/doc/MSspecs.hlp new file mode 100644 index 00000000..92f285ed --- /dev/null +++ b/noao/twodspec/multispec/doc/MSspecs.hlp @@ -0,0 +1,659 @@ +.help multispec Oct83 "Multi-Spectra Extraction Package" +.sp 3 +.ce +Detailed Specifications for the Multi-Spectra Extraction Package +.ce +F. Valdes +.ce +December 8, 1983 +.sh +1. Introduction + + The multi-spectra extraction package (MULTISPEC) provides the basic tools +for modeling, cleaning, and extracting spectra from images +containing multiple aperture spectra running roughly parallel. +These tools will generally be combined in reduction script tasks +but may also be used directly for non-standard analysis. + + This design presents the requirements and specifications +for the MULTISPEC package. Details concerning the +algorithms are given in a separate document, Algorithms for the +Multi-Spectra Extraction Package. +.sh +2. Input Data Requirements + + The input data for the MULTISPEC package consists of image +files containing one or more aperture spectra. The spectra are +required to run roughly parallel to each other and parallel to the +second digitization axis. The latter requirement may require a +general rotation and interpolation image operator. The images are +assumed to be corrected to linear relative intensity. Thus, the +steps of correcting digital detector images for dark current, bias, and +pixel-to-pixel sensitivity variations must be performed before using +the MULTISPEC tasks. + + Because the MULTISPEC package is being developed +concurrently with the IRAF standard image processing +tools this document specifies the requirements for the preliminary +image processing needed to prepare digital detector images for the MULTISPEC +package. +.sh +2.1 Basic Digital Detector Reduction Tasks + + The prelimary reduction of multi-spectra images uses CL scripts +based on general image operators. +Some of the scripts are for specific instruments or specific +reduction applications and some are generally useful image processing +tasks. The scripts allow the specification of many images for which +the operations will be repetitively applied. + + The following CL scripts are required to reduce multi-spectra images +from digital detectors. + + +.nf + debias multispec_flat flat_divide +.fi +.ke +.ks +.ls 4 debias +The files in a list of filenames are automatically debiased and trimmed. +This routine will be instrument specific but used by other reduction +tasks beyond MULTISPEC. +.le +.ke +.ks +.ls multispec_flat +The files in a list of quartz multi-spectra filenames are added, +the result is smoothed +along the dispersion dimension, and then the original image is divided +by the smoothed image to produce a flat field image. The unsmoothed +to smoothed ratio is computed only if the value of the smoothed +pixel is greater than a specified amount. Otherwise, the ratio is set +to unity. This routine is not instrument specific but is used only +for MULTISPEC reductions. +.le +.ke +.ks +.ls flat_divide +The files in a list of filenames are each divided by a specified flat +field image. This routine is not instrument or application specific. +.le +.ke + + The required general image processing programs needed to implement these +scripts are specified below. + +.ls (1) +A routine to compute the average value from a specified area of the +image. Used to determine the average bias value from a bias strip. +.le +.ls (2) +A routine to trim a specified portion of an image. Used to trim the +bias strip. +.le +.ls (3) +Routines to multiply and subtract images by a constant. Used to scale +images such as dark exposures and to remove the average bias value as +obtained by (1) above. +.le +.ls (4) +Routines to subtract, add, and divide images. Used to subtract dark +current and bias exposures, to add several exposures to increase the +signal-to-noise, and to divide by a flat field image. +The divide routine must give the user the option to substitute a constant or +ignore any divisions in which the denominator is less than a specified value. +.le +.ls (5) +A routine to rotate or transpose an image. Used to align the spectra +along lines or columns. +.le +.ls (6) +A routine to apply a filter to lines of the image. For multi-spectra images +a smooth quartz is produced by using a running quadratic filter along each +line of the dispersion dimension. The filter must be able to recognize +bad pixels (specified by a user defined threshold) and remove them from the +filtering operation. +.le +.sh +3. Requirements for the MULTSPEC Package + + The MULTISPEC package shall satisfy the following requirements. +.ls (1) +The component programs shall be CL callable. +.le +.ls (2) +The programs shall interact only through image files and MULTISPEC data files. +.le +.ls (3) +It shall be possible to extract spectra without modeling. +.le +.ls (4) +The entire image shall be extracted and not limited by failures in the +algorithms. +.le +.ls (5) +It shall be possible to specify specific lines or swaths in the image +on which to operate. +.le +.ls (6) +CL scripts shall be provided for the common data sources. These scripts +will work automatically. +.le + +The follow functions shall be provided: +.ls o +Make an initial rough but automated identification of the spectra +locations. +.le +.ls o +Provide for a user identification list for the spectra locations. +This list shall be of the standard image cursor type to allow generation +of the list with the standard image cursor programs. +.le +.ls o +Determine and correct for a slowly varying background. +.le +.ls o +Reliably and accurately trace spectra in the presence of geometric +distortions (pincushion, s, shear, etc.). +.le + +Extract spectra by one of: +.ls a. +Strips of constant width about the located spectra. The width may be specified +to fractions of a pixel and the extraction will use fractional pixel +interpolation. +l +.le +.ls b. +Strips of width proportional to a Gaussian width parameter. +.le +.ls c. +Modeling to obtain estimates of the total luminosity. The estimate will +be the integral of the model. +.le +.ls d. +Summation of the data pixel values with fractional contributions of the +pixel value to the spectra based on modeling. +.le +.le +.ls o +An option shall be available to specify whether to ignore blank pixels +or use interpolated values. +.ls o +Programs shall be provided to produce data files which can be accessed +by one dimensional spectroscopic reduction routines. At a minimum +these formats shall include: +.ls a. +Reduction to an image file consisting of one line per extracted +spectrum +.le +.ls b. +The standard IIDS format available with the CYBER Multi-Aperture Plate +programs +.le +.le +.sh +3.2 Modeling Requirements + + The modeling of multi-spectra images, particularly in the case of +blended spectra, shall: +.ls (1) +Model blended spectra with sufficient reliability and robustness that +a reasonable solution is always obtained, though of possibly limited +usefulness. +.le +.ls (2) +The modeling shall provide estimates for the uncertainties in the fitted +parameters as a function of position along the spectrum. +.le +.ls (3) +Remove cosmic rays and other defective pixels by reference to the model. +.le +.ls (4) +Allow the transfer of a model solution for one image to another image. +.le +.ls (5) +Display numerically and graphically the data, the fitted model, and +the residuals. +.le +.sh +4. Program Specifications +.sh +4.1 Basic Programs + + The basic programs of the package are general purpose tools which +initialize a MULTISPEC data file and perform a single fundamental operation +on the data in the MULTISPEC data file. There is one data file associated +with each image. The data file is hidden from the user and so the user +need not be aware of the data file. +The data files are referenced only the image filename specified in the +program parameters. +The data files contain such information as a processing history, the +spectra positions and extracted luminosities, the model parameters (one +set for each spectra for each modelled image line (or swath), etc. +The programs generally are allowed to specify specific +lines, columns, and/or spectra on which to operate. +The line, column and spectra specifications are given as strings which +contain numbers separated by whitespace, commas, and the range indicator +"-". The script tasks +of section 4.2 will combine these basic programs to perform a general +multi-spectra extraction. + +.ks +.nf + ap_plate copy_params find_spectra convolve + fit_bckgrnd find_bckgrnd line_list model_extrac + model_fit model_image model_list sigma_extract + strip_extract to_iids to_image to_onedspec +.fi +.ke +.ks +.ls ap_plate +The information from an on-line data file containing descriptions of all +the aperture plates prepared at Kitt Peak is read to find a specified +aperture plate. The drilled aperture positions are correlated with the +spectra in the image to deduce relative wavelength offsets. The +identifications for the spectra as well as other auxiliary information +is recorded in the data file. +If no image file is specified then only the aperture +plate information is printed. This program is used in the MULTIAP_EXTRACT +program. This program is not essential to the operation of the MULTISPEC +package. + +.nf + Multi-Spectra image image = + Aperture plate plate = + (mode = ql) +.fi +.le +.ke +.ks +.ls The Background +The are two possibilities for dealing with the background. In the first +case, FIT_BCKGRND, the background will be fitted by polynomials and +the coefficients stored in the MULTISPEC data file. These coefficients +are then used by the other programs to estimate the background at the +spectra. The second option, FIND_BCKGRND, generates a background image in which +the spectra and other selected areas are set to blank pixels. Then a +general image interpolator is used fill in the blank pixels with background +estimates. The other MULTISPEC programs will then access this background +frame. The background frame image name will be stored in the MULTISPEC +data file and the image header. + +.ls fit_bckgrnd +Fit a background in a MULTISPEC image by a polynomial using pixels +not near the spectra and in the user specified swaths and columns. +The buffer distance is in pixels and refers to a minimum distance from +the center of any spectrum beyond which the background pixels are found. +Blank pixels are ignored in the background fit. Deviant pixels will be +rejected. + +.nf + Multi-Spectra image image = + Buffer from spectra buffer = 12 + Polynomial order order = 3 + Lines per swath (lines_per_swath = 32) + Swaths to fit (swaths = 1-1000) + Columns to fit (columns = 1-1000) + Rejection threshold (threshold = 5) + Print general diagnostics (verbose = no) + (mode = ql) +.fi +.le +.ls find_bckgrnd +The spectra within a buffer distance and specified areas are set to blank +pixels and the remaining pixels copied to a background image file. + +.nf + Multi-Spectra image image = + Background image background = + Buffer from spectra buffer = 12 + Lines to ignore (lines = ) + Columns to ignore (columns = ) + (mode = ql) +.fi +.le +.le +.ke +.ks +.ls convolve +A program will be provided to reduce either the extracted spectrum or +the modeled image to a common point-spread function. +.le +.ke +.ks +.ls copy_params +Create a MULTISPEC data file for a new image using +appropriate MULTISPEC parameters from an old image. +The old image must have been processed to find the spectra using FIND_SPECTRA +and possibly model fit. + +.nf + Old Multi-Spectra image old_image = + New Multi-Spectra image new_image = + (mode = ql) +.fi +.le +.ke +.ks +.ls find_spectra +Initially locate the spectra in a MULTISPEC image. +The positions of the spectra within the range of columns are determined +for the starting line and then the spectra are tracked within the +range of lines. The minimum separation +and minimum width would generally be set for a particular instrument. +If the automatic search is not used then a list of cursor positions is +read from the standard input. + +.nf + Multi-Spectra image image = + Automatic search auto = yes + Starting line start_line = + Minimum separation (min_sep = 1) + Minimum width (min_width = 1) + Averaging width (average = 32) + Lines to search (lines = 1-1000) + Columns to search (columns = 1-1000) + Print general diagnostics (verbose = no) + (mode = ql) +.fi +.le +.ke +.ks +.ls line_list +For the specified lines in the image print the image column +number, data value (possibly as a swath average), the model value at that +point (i.e. the sum of the model contributions from all the spectra), +the background value, and the residual. +Plotting scripts may be written using this routine to +show the quality of a model fit. + +.nf + Multi-Spectra image image = + Lines to list (lines = 1-1000) + (mode = ql) +.fi +.le +.ke +.ks +.ls model_extract +A previously fitted model is used to extract the spectra total luminosity +by apportioning the data values to spectra in the ratio indicated by the +model. If the clean option is specified then the model is used to detect +pixels which deviate from the model by a specified amount. +The model value replaces the deviant pixel in the extraction and, if specified, +also in the image file. + +.nf + Multi-Spectra image image = + Lines to extract (lines = 1-1000) + Clean spectra (clean = yes) + Cleaning threshold (threshold = 5) + Modify image (modify = yes) + Print general diagnostics (verbose = no) + (mode = ql) +.fi +.le +.ke +.ks +.ls model_fit +A specified model is iteratively fitted to the data in each of the specified +lines (or swaths) until the RMS residual fails to decrease. The models +are selected by a string. The possible values are + +.nf + (null string) - initialize the model + i - fit only the intensity scale + ip - fit the intensity scale and the position + ips1 - fit the intensity scale, position, and one parameter shape + ips2 - fit the intensity scale, position, and two parameter shape + ips3 - fit the intensity scale, position, and three parameter shape + ips4 - fit the intensity scale, position, and four parameter shape +.fi +These models will be combined in a script to search for the best fit. + +The initial shape parameters will generally be set by scripts for a +particular data reduction. + +.nf + Multi-Spectra image image = + Model type model = + Lines per swath (lines_per_swath = 32) + Swaths to model (swaths = 1-1000) + Initial shape1 (shape1 = .1 ) + Initial shape2 (shape2 = 0 ) + Initial shape3 (shape3 = 0 ) + Initial shape4 (shape4 = 5 ) + Print general diagnostics (verbose = no) + (mode = ql) +.fi +.le +.ke +.ks +.ls model_image +An image file of the fitted model is created. This image may then be displayed +or a residual image may be calculated and displayed. + +.nf + Multi-Spectra image image = + Model image model = + (mode = ql) +.fi +.le +.ke +.ks +.ls model_list +For the specified lines and spectra the model is listed. +The listing gives, for each spectra, +the spectrum number, the line number, the fitted position, +the estimated wavelength, the +extracted luminosity, the intensity scale, model width parameters, and +the background polynomial coefficients. This routine can be used in scripts +to plot the extracted spectra, the trend of width with wavelength, and so +forth. + +.nf + Multi-Spectra image image = + Lines to list (lines = 1-1000) + Spectra to list (spectra = 1-1000) + (mode = ql) +.fi +.le +.ke +.ks +.ls sigma_extract +A previously fitted model is used to extract the spectra luminosity +within a specified sigma of the peak. Because the model is not necessarily +a Gaussian the sigma is used to compute +the intensity ratio of the cutoff to the peak assuming a Gaussian profile +and then the data is extracted to the point the model intensity falls below that +cutoff. If the clean option is specified then the model is used to detect +pixels which deviate from the model by a specified amount. +The model value replaces the deviant pixel in the extraction and, if specified, +also in the image file. + +.nf + Multi-Spectra image image = + Sigma extraction width width = 1. + Lines to extract (lines = 1-1000) + Clean spectra (clean = yes) + Cleaning threshold (threshold = 5) + Modify image (modify = yes) + Print general diagnostics (verbose = no) + (mode = ql) +.fi +.le +.ke +.ks +.ls strip_extract +A strip of constant width about the spectra positions is extracted. +If cleanning is desired a smoothed estimate of the profile is obtained +by averaging a number of lines about the line to be cleaned. After fitting +for the intensity scale pixels are found which deviate from the profile by +a specified amount. +The profile value replaces the deviant pixel in the extraction and, +if specified, also in the image file. No prior modeling is required +to use this extraction routine. + +.nf + Multi-Spectra image image = + Strip extraction width width = 1. + Lines to extract (lines = 1-1000) + Clean spectra (clean = yes) + Cleaning threshold (threshold = 5) + Lines per profile average (averge_lines = 32) + Modify image (modify = yes) + Print general diagnostics (verbose = no) + (mode = ql) +.fi +.le +.ke +.ks +.ls to_iids +For a specified prefix, files of the form prefix.nn, where nn is a specified +spectra number, are created containing the extracted spectra for all +the specified image files. The format of the files is the IIDS format +developed for the CYBER Multi-Aperture Plate Extractions. + +.nf + Multi-Spectra image images = + IIDS filename prefix iids_file = + Spectra to format (spectra = 1-1000) + (mode = ql) +.fi +.le +.ke +.ks +.ls to_image +An image file containing one line of the extracted luminosities for each +specified spectra in the specified MULTISPEC image. + +.nf + Multi-Spectra image in_image = + Extracted spectra image out_image = + Spectra (spectra = 1-1000) + (mode = ql) +.fi +.le +.ke +.ks +.ls to_onedspec +The extractions are converted to an as yet to be specified format for +use in the ONEDSPEC reduction package. + +.nf + Multi-Spectra images images = + ONEDSPEC data file onedspec_file = + Spectra (spectra = 1-1000) + (mode = ql) +.fi +.le +.ke +.sh +4.2 General MULTISPEC CL Scripts + + The general MULTISPEC CL scripts perform a series of steps needed to +extract the spectra from a specified list of image files. These steps have +been found to generally perform the desired extraction task fully. + + +.nf + multiap_extract echelle_extract +.fi +.ks +.ls multiap_extract +The specified multi-aperture plate images are extracted. +If no starting solution image, one which has previously been extracted, +is specified then the script performs an automatic search for the +specified number of spectra. +Otherwise the solution from the starting image is used as the initial +model. The background is then determined. +This is followed by a series of fitting steps on swaths of data. +(For further details on the fitting steps see the Algorithms paper). +A MODEL_EXTRACT and cleaning follows. +Finally, the extraction is correlated with the specified aperture plate +using AP_PLATE. +If there was no starting image then this extraction becomes the +initial solution image. +Subsequent images are extracted starting from the initial solution image. + +.nf + Multi-Aperture images images = + Initial solution image initial = + Aperture plate number plate = + Number of spectra nspectra = + (mode = ql) +.fi +.le +.ke +.ks +.ls echelle_extract +The specified echelle images are extracted. +If no starting solution image, one which has previously been extracted, +is specified then the script performs an automatic search for the +specified number of orders. +Otherwise the solution from the starting image is used as the initial +starting point. The background is then determined. +Finally a STRIP_EXTRACT and cleaning is performed. +If there was no starting image then this extraction becomes the +initial solution image. +Subsequent images are extracted starting from the initial solution image. + +.nf + Echelle images images = + Initial solution image initial = + Number of orders norders = + Extraction width width = + (mode = ql) +.fi +.le +.sh +5. Outline of a MULTISPEC Reduction + + The following outline is for the reduction of a cryogenic camera +multi-aperture plate. All the programmer supplied default values are +used. + +.nf + (1) rcamera mtb, "ap165.", "s", "3-9" + (2) debias "ap165.*" + (3) multispec_flat "ap165.[36]", "ap165.flat" + (4) flat_divide "ap165.*", "ap165.flat" + (5) multiap_extract "ap165.*", "", 165, 50 + (6) to_onedspec "ap165.*", oned165 +.fi + +.ls (1) +The data is read from the observing tape(s) using RCAMERA. +The image files created are ap165.3, ap165.4, ..., ap165.9. This is +easily accomplished by using the filename prefix "ap165." in the RCAMERA +program. The raw images may be examined at this point on a display. +.le +.ls (2) +The images are debiased using DEBIAS with all the "ap165." files specified. +The debias program knows about the location of the bias strip for the +cryogenic camera. +.le +.ls (3) +A a flat field is created +using MULTISPEC_FLAT in which the desired quartz frames are specified +and a flat field image filename is defined. The created flat field +image may be examined on an image display if desired. +.le +.ls (4) +All the debiased images are divided by the flat field using FLAT_DIVIDE. +.le +.ls (5) +The script MULTIAP_EXTRACT is run in which the aperture plate number, +the number of spectra, and the image files to be extracted are specified. +The number of spectra is found by examining an image on an image display +or by plotting a cut across the spectra using a general image profile +program. +.le +.ls (6) +Finally, the extracted spectra are formatted for the ONEDSPEC package +using TO_ONEDSPEC with the extracted images specified. +.le +.endhelp diff --git a/noao/twodspec/multispec/doc/MSspecs_c.hlp b/noao/twodspec/multispec/doc/MSspecs_c.hlp new file mode 100644 index 00000000..848d589d --- /dev/null +++ b/noao/twodspec/multispec/doc/MSspecs_c.hlp @@ -0,0 +1,243 @@ + +.help multispec Nov82 "Multispec Specifications" +.ce +Comments on Multispec Package Specifications +.ce +November 8, 1983 + + + + The basic package structure and the decomposition of the package into +tasks looks good. The requirements for both general operators and canned +procedures are addressed well. I got the impression that you have a pretty +clear idea of what you want to do (which is the thing I am most looking for +when I read a specs document), but I confess to having to reread the document +several times to figure out what you have in mind. Your writing style is +very terse and leaves much up to the reader! + +Most of my comments have to do with details. These are presented in the +order in which they occurred while reading the document. These comments +apply only to the specs document. I have started going over the algorithms +paper, mostly when I could not understand a section of the specs document, +but I have not finished it yet. + +.sh +General Comments +.ls 4 +.ls (1) +When eventually we write the user documentation, the nomenclature +should be carefully explained up front. Users will tend to confuse +image lines and spectral lines, but there is little we can do about +that other than to make the distinction clear. The term "band" is +confusing because it normally refers to the third dimension of an +image and that is not how it is used here. A better term might be +"swath". In what follows I will continue to use the term band, but +it is definitely not too late to change. +.le +.ls (2) +It seems to me that the concept of a band or swath is a detail of how +the algorithm works and should not have such a prominent place in the +user interface to the package. Several of the routines require that +image coordinates be entered in units of band number and column. +This introduces an unnecessary coupling between two input parameters +and forces the user to convert from line number to band number. The +result will be that the user will be reluctant to change the number +of lines per band (I'll bet that you have kept this a constant in +using the prototype). My inclination would be to have the user enter +all coordinates in units of lines and columns, and have the program +select the nearest band depending on the band width parameter. +The band width could then be easily changed depending on the data, +without need to respecify the region of the image to be processed. +.le +.ls (3) +Routines all over the system will have an option for printing extra +information, i.e., a verbose mode of execution. I think we should +standardize on the name of this parameter. "Verbose" seems to me +more descriptive than "print", and is consistent with UNIX terminology. +.le +.le + +.sh +Pages 3,4 +.ls +.ls (1) +Functions for extracting spectra. I assume "strips of constant +width" means aperture sum out to a specified x-radius from the +center of a spectra. Can the radius be specified in fractional +pixels, and if so, does the routine do fractional pixel interpolation. +What happens if there are blank pixels in the aperture? + +If extraction is based on the model, I gather that you are still +summing data pixel values, using a weight for each spectra based +on the modeled contribution of each spectra to the data pixel. In +other words we are still taking an aperture sum, but with allowances +for crowding. This has the disadvantage that if we sum way out into +the wings, we will be adding noise to the aperture sum, degrading signal +to noise. + +Extraction based on integration of the model rather than +the data should be available as another extraction procedure; this may +yield better photometric results. I would eventually like to compare +the two approaches with artificial data. Also by integrating the model +there is no need to "clean" (I assume that deviant pixels are detected +and rejected when the model is fitted, or the model will not be +accurate). Blank pixels should be recognized and ignored when fitting +the model. +.le + +.ls (2) +I gather that all extracted spectra for an image are put into a single +imagefile. This is fine, even desirable, as long as it is ok if all +spectra share the same header, and as long as all we want to output +is intensity versus wavelength. If it is desired to also output the +signal to noise or whatever than another scheme may be needed. +.le +.ls (3) +The text file output form ('c'pg.4) should be engineered with the idea +that the user will take the data away in cardimage form. From the +description it sounds like there is one pixel (wavelength bin) per +line in the text file. This has its advantages, but is not what one +wants for a cardimage file, which always writes 80 chars per line. +Also, the detailed technical specs should give some details about +such a format; it is a major part of the user interface and people +will want to know what this format is going to look like. In a way +it is more important to specify formats like this than the calling +sequences of the tasks, because it is harder to change after the +package is released, and other program are written to read the +text format spectra. +.le +.ls (4) +To item 3.2 (2) (on uncertainty estimates) I would add "as a function +of position along the spectrum". +.le +.le + +.sh +4.1 Basic Programs +.ls +.ls (1) +Evidently there is a datafile associated with each image. What is +the function of the datafile? Is it transparent to the user? How +much is stored in the image header and how much in the datafile? +.le +.ls (2) +The distinction between "line_list" and "model_list" is confusing. +Does "line_list" print the sum of the models for all the spectra +a each column? Please specify the form of the output for this +procedure in more detail. The line_list and model_list procedures +are natural candidates for use with the "lists" utilities for +extracting columns, plotting one column against another, etc. I +could not tell whether or not this would work well from the info +given. +.le +.ls (3) +"ap_plate": "The identifications for the spectra ... is recorded." +Is recorded where? In the datafile? Is this information essential +to the operation of multispec, or is it merely passed on through +multispec? +.le +.ls (4) +"find_background": Might be more aptly named "fit_background". +I would expect "find" to mean find which regions of the image are +background and which are spectra. Find is spatial, fit is grayscale. + +We need to decide whether we want to specify polynomials in IRAF by +the order (0,1,2, etc.) or by the number of coefficients or terms. +It seems to me that people are most used to talking about second, +third, fifth etc. order polynomials and that we might better specify +polynomials with an "order" parameter rather than a "terms" param. + +Buffer radius or diameter? I would assume radius, but it is not +clear from the docs. What is being "searched"? Shouldn't that read +"bands to be fitted". The "colummns" parameter should permit a list +of ranges of columns; I couldn't tell whether this was the case +from the specs. Cursor input may be desirable here. + +Blank pixels should be detected and ignored when fitting the +background. Are deviant pixels detected and rejected? This is +generally a desirable option in a bkg fit. You may be able to +decompose this routine (internally) into a find_background and +a fit_background, making use of the Images background fitting +routines, though these generate an image as output rather than the +coeff of the fitted functions. I wuld guess that you are storing +the bkg coeff for each band in the datafile from the description, +and that the fit is strictly one-dimensional. + +If only a limited number of bands are fitted, what do you do about +the other bands if the bkg fit is one-dimensional? Is the user +req'd to use the same bands range when they do the extraction? +.le + +.ls (5) +"find_spectra". It is not clear how this routine uses cursor input. +Perhaps you should have a gcur type parameter. Reading cursor +coordinates from the standard input may be the way to go, but you +should explain how this is going to work. +.le +.ls (6) +"line_list". One output line per image line? One or more spectra +per output line? Output should be suitable for further processing +with the LISTS package utilities (i.e., getcol, and the graphics +utility which will plot or overplot lists). The specs should +specify the form of the output. +.le +.ls (7) +I assume that the extraction procedures extract spectra which +are put somewhere. Where, in the datafile? If the image is +to be cleaned, it would be safer to write a new output image, +or at least to rename the original. It is strange to have these +two quite different functions in the same module. +.le +.ls (8) +"model_fit". The range of modeling options is impressive, good +stuff. However, there must be something better than magic integer +numbers for specifying the model to be fitted. Perhaps the +strings "i, ip, ipw, ipw2, ipw3, ipw4", where 'i' is for intensity, +'p' for position, and 'w' for width. + +How are the "initial parameters" specified? +.le +.ls (9) +"model_list". Again, I can only guess from the description what the +output will look like. It sounds like it might be best to have +this routine print data for only one spectra at a time, particularly +if the lists package is to be used for analysis. It might be good +to have the line number in the output somewhere, especially if the +wavelength information is not available. +.le +.le + +.sh +4.2 Scripts +.ls +.ls (1) +It sounds like there is no easy alternative to an automatic search +for the line centers. This is best as long as it works, but the +users will want easy way to use the cursor available as an option. +A script such as this can easily use the line plot routine Images +to make a plot and generate a list of line centers, without even +requiring find_spectra to be able to access the cursor (and perhaps +it should not if the script can do it). The graphics cursor should +be used here rather than the image cursor. +.le +.le + +.sh +5. Example +.ls +.ls (1) +The rcamera example is in error. Rcamera, as implemented, has only +three query mode params, while you show four in the example. +I believe the ranges string should be quoted and should be the second +argument. + +The last command should be "to_onedspec", not "onedspec". +.le +.ls (2) +5.(5): It seems strange to make the user manually count 50 spectra +by examining a plot. If the program automatically finds centers, +this should not be necessary; if the user interactively marks centers, +it is not necessary. +.le +.le +.endhelp diff --git a/noao/twodspec/multispec/doc/findpeaks.hlp b/noao/twodspec/multispec/doc/findpeaks.hlp new file mode 100644 index 00000000..f6118281 --- /dev/null +++ b/noao/twodspec/multispec/doc/findpeaks.hlp @@ -0,0 +1,88 @@ +.help findpeaks Jul84 noao.twodspec.multispec +.ih +NAME +findpeaks -- Find peaks in a multi-spectra image +.ih +USAGE +findpeaks image lines contrast +.ih +PARAMETERS +.ls image +Image to be searched. +.le +.ls lines +Sample image lines in which the peaks are to be found. +.le +.ls contrast +Maximum contrast between the highest peak and the lowest peak. +.le +.ls separation = 5 +Minimum separation in pixels between acceptable peaks. +.le +.ls edge = 0 +Minimum distance in pixels to the edge of the image for acceptable peaks. +.le +.ls threshold = 0. +The minimum acceptable peak pixel value. +.le +.ls min_npeaks = 1 +Minimum number of peaks to be found. It is an error for fewer than +this number of peaks to be found. +.le +.ls max_npeaks = 1000 +Maximum number of peaks to be found. If more than this number of peaks +is found then only the those with the highest peak values are accepted. +.le +.ls columns = '*' +Columns to be searched. +.le +.ls naverage = 20 +Number of image lines around the sample line to be averaged before +finding the peaks. +.le +.ls debug = no +Print detailed information on the progress of the peak finding algorithm. +.le +.ih +DESCRIPTION +For each specified sample image line the number of peaks and their column +positions in the image are determined. +The number of peaks and their positions are assumed to correspond to points +along the spectra. This information is entered in the MULTISPEC database. + +The \fInaverage\fR image lines about the specified sample line are first +averaged. The local maxima in the average line are then located +in the specified columns more than the minimum distance from the edge of the +image. A minimum peak pixel value cutoff is determined as the maximum of +the specified \fIthreshold\fR and \fIcontrast\fR times the largest peak pixel +value. All local maxima with pixel values below the cutoff are rejected. +Next all peaks with separations less than \fIseparation\fR from a stronger +peak are rejected. Finally, if there are more than \fImax_npeaks\fR remaining +only the \fImax_npeaks\fR strongest peaks are accepted. If fewer +than \fImin_npeaks\fR are found then the task quits with an error. + +If the number of spectra has been previously determined, such as by an earlier +use of \fBfindpeaks\fR, then it is an error if a different number of +peaks is found. +.ih +EXAMPLES +The parameters of this task provide a great deal of flexibility in +automatically determining the number and positions of the peaks. +The most automatic method just uses the contrast to limit the acceptable +peaks: + + cl> findpeaks image.db 1 .1 + +However, if the number of spectra in the image is known: + + cl> findpeaks image.db 1 0 min=10 max=10 + +or if a threshold is known: + + cl> findpeaks image.db 1 0 threshold = 1000 + +For a noisy image the separation parameter can be set to eliminate spurious +noise peaks near the peaks to be found: + + cl> findpeaks image.db 1 .1 sep=20 +.endhelp diff --git a/noao/twodspec/multispec/doc/fitfunc.hlp b/noao/twodspec/multispec/doc/fitfunc.hlp new file mode 100644 index 00000000..09510bb7 --- /dev/null +++ b/noao/twodspec/multispec/doc/fitfunc.hlp @@ -0,0 +1,73 @@ +.help fitfunction Jul84 noao.twodspec.multispec +.ih +NAME +fitfunction -- Fit a function to the spectra parameter values +.ih +USAGE +fitfunction image +.ih +PARAMETERS +.ls image +Image in which the parameter values are to be fitted. +.le +.ls parameter = "x0" +Parameter to be fit. The legal minimum match abbreviated parameters +are x0, s0, s1, s2. +.le +.ls lines = "*" +Sample image lines to be used in the function fit. +.le +.ls spectra = "*" +Spectra for which the parameters are to be fit. +.le +.ls function = "interpolation spline" +Fitting function to be used. The function is specified as a string +which may be minimum match abbreviated. The functions currently available +are: +.ls interpolation spline +Interpolation spline of specified order. +.le +.ls smoothing spline +Smoothing spline of specified order and number of polynomial pieces. +.le +.le +.ls spline_order = 4 +Order of the fitting spline. The order must be even. +The minimum value is 2 and maximum value is determined from the number of +sample lines in the fit. +.le +.ls spline_pieces = 1 +The number of polynomial pieces in a smoothing spline. +The minimum value is 1 and the maximum value is determined from the number of +sample lines in the fit. +.le +.ih +DESCRIPTION +A function is fit to the parameter values previously determined at the sample +lines for each spectrum. The function coefficients are stored in the +database and the fitted values replace the original values at all the sample +lines (not just the sample lines used in the fit). The type of function, +the parameter to be fitted, the sample lines used in the fit, and the +spectra to be fitted are all selected by the user. The function is +extrapolated to cover all image lines. + +The values of the function fit at arbitrary image lines may be listed +with \fBmslist\fR. +.ih +EXAMPLES +The extraction of the spectra requires that a fitting function be +determined for the spectra positions. This is done by: + + cl> fitfunction image + +To smooth the parameter "s0" in model \fIgauss5\fR with a cubic spline +and leave out a bad point at sample line 7: + +.nf + cl> fitfunction image parmeter=s0 function=smooth \ + >>> lines="1-6,8-" +.fi +.ih +SEE ALSO +mslist +.endhelp diff --git a/noao/twodspec/multispec/doc/fitgauss5.hlp b/noao/twodspec/multispec/doc/fitgauss5.hlp new file mode 100644 index 00000000..bcb37276 --- /dev/null +++ b/noao/twodspec/multispec/doc/fitgauss5.hlp @@ -0,0 +1,148 @@ +.help fitgauss5 Jul84 noao.twodspec.multispec +.ih +NAME +fitgauss5 -- Fit spectra profiles with five parameter Gaussian model +.ih +USAGE +fitgauss5 image start +.ih +PARAMETERS +.ls image +Image to be modeled. +.le +.ls start +Starting sample line containing the initial model parameters. +.le +.ls lower = -10 +Lower limit for the profile fit relative to each spectrum position. +.le +.ls upper = 10 +Upper limit for the profile fit relative to each spectrum position. +.le +.ls lines = "*" +Sample image lines to be fit. +.le +.ls spectra = "*" +Spectra to be fit. +.le +.ls naverage = 20 +Number of data lines to be averaged about each sample image line before +model fitting. +.le +.ls factor = 0.05 +The model fit to each line is iterated until the RMS error between the +model line and the data line improves by less than this factor. +.le +.ls track = yes +Track the model solution from the starting line to the other sample lines? +.le +.ls algorithm = 1 +Parameter fitting algorithm to use. Legal values are 1 and 2. +.le +.ls fit_i0 = yes +Fit the profile scale parameters i0? +.le +.ls fit_x0 = yes +Fit the spectra position parameters x0? +.le +.ls fit_s0 = yes +Fit the spectra shape parameters s0? +.le +.ls fit_s1 = no +Fit the spectra shape parameters s1? +.le +.ls fit_s2 = no +Fit the spectra shape parameters s2? +.le +.ls smooth_s0 = yes +Fit a smoothing spline to the shape parameters s0 after each iteration? +.le +.ls smooth_s1 = yes +Fit a smoothing spline to the shape parameters s1 after each iteration? +.le +.ls smooth_s2 = yes +Fit a smoothing spline to the shape parameters s2 after each iteration? +.le +.ls spline_order = 4 +Order of the smoothing spline to be fit to the shape parameters. +.le +.ls spline_pieces = 3 +Number of polynomial pieces for the smoothing spline. +.le +.ls verbose = no +Print general information about the progress of the model fitting. +.le +.ih +DESCRIPTION +The spectra profiles in the interval (\fIlower, upper\fR) about each +spectrum position are fit with a five parameter Gaussian model for +the specified sample lines of the image. For a description of +the model see \fBgauss5\fR. The model fitting is performed using +simultaneous linearized least squares on the selected model profile +parameters as determined by the \fIalgorithm\fR for the specified +\fIspectra\fR. The parameter fitting technique computes correction +vectors for the parameters until the RMS error of the model image line +to the data image line, which is an average of \fInaverage\fR lines +about the sample line, improves by less than \fIfactor\fR. +A solution which increases the RMS error of the model is not allowed. + +If the parameter \fItrack\fR is yes then the initial model parameters are +those given in the database for the sample line \fIstart_line\fR. From +this starting point the model parameters are iterated to a best fit at +each specified sample line and then the best fit is used as the starting +point at the next line. The tracking sequence is from the starting line +to the last line and then, starting again from the starting line, to +the first line. Note that the model parameters, including the starting +spectra positions, need be set only at the starting line. + +If \fItrack\fR is no then each specified sample line is fitted independently +from the initial model parameters previously set for that line. This option +is used to add additional parameters to the model after an +initial solution has been obtained or to refit a new image whose database +was created as a copy of the database of a previously fit image. + +The shape parameters s0, s1, and s2 can be smoothed by fitting a spline of +specified \fIorder\fR and number of spline pieces, \fInpp\fR to the +parameters as a function of spectra position. +The smoothing is performed after each iteration and before +computing the next RMS error. The smoothing is a form of local constraint +to keep neighboring spectra from having greatly different shapes. +The possibility of such erroneous solutions being obtained is present in +very blended data. + +In \fIverbose\fR mode the RMS errors of each iteration are printed on the +standard output. + +The selection of the parameters to be fit and the order in which they are +fit is determined by \fIalgorithm\fR. These algorithms are: + +.ls 4 1 +This algorithm fits the selected parameters (\fIfit_i0, fit_x0, +fit_s0, fit_s1, fit_s2\fR) for the selected \fIspectra\fR simultaneously. +.le +.ls 4 2 +This algorithm begins by fitting the parameters i0, x0, and s0 +simultaneously. Note that the values of s1 and s2 are used but are +kept fixed. Next the parameters s0 and s1 (the shape) are fit simultaneously +keeping i0, x0, and s2 fixed followed by fitting i0 and x0 while +keeping s0, s1, and s2 (the shape) fixed. If either of these fits +fails to improve the RMS then the algorithm terminates. +Also, if after the two steps (the fit of s0 and s1 followed by the fit +of i0 and x0), the RMS of the fit has not improved by more than the +user specified factor the algorithm also terminates. This algorithm has been +found to be the best way to fit highly blended spectra. +.le +.ih +EXAMPLES +The default action is to fit Gaussian profiles to the spectra and trace +the fit from the starting line. An example of this is: + + cl> fitgauss5 image 1 + +To fit heavily blended spectra with the four parameter model (i0, x0, s0, s1): + + cl> fitgauss5 image 1 algorithm=2 +.ih +SEE ALSO +findspectra +.endhelp diff --git a/noao/twodspec/multispec/doc/modellist.hlp b/noao/twodspec/multispec/doc/modellist.hlp new file mode 100644 index 00000000..70e95ce4 --- /dev/null +++ b/noao/twodspec/multispec/doc/modellist.hlp @@ -0,0 +1,52 @@ +.help modellist Jul84 noao.twodspec.multispec +.ih +NAME +modellist -- List data and model pixel values +.ih +USAGE +modellist image lines +.ih +PARAMETERS +.ls image +Image whose model is to be listed. +.le +.ls lines +Sample lines to be listed. +.le +.ls model = "gauss5" +Profile model to be used to create the model line. +The only model currently defined is \fIgauss5\fR. +.le +.ls columns = "*" +Image columns to be listed. +.le +.ls naverage = 20 +The number of image lines to be averaged to form the data values. +.le +.ls lower = -10 +Lower limit of model profiles measured in pixels from the spectra centers. +.le +.ls upper = 10 +Upper limit of model profiles measured in pixels from the spectra centers. +.le +.ih +DESCRIPTION +The model of the image for the selected sample \fIlines\fR +are used to generate model image lines. Only the model \fIgauss5\fR is +currently available. The output format is column, sample line, image pixel +value, and model pixel value. The image pixel data are formed by averaging +\fInaverage\fR lines about the sample lines. +.ih +EXAMPLES +To list the image and model pixel values for the first sample line after +fitting the \fIgauss5\fR model with \fBfitgauss5\fR: + + cl> modellist image 1 >outputlist + +The list file \fIoutputlist\fR can be used with the \fBlists\fR and +\fBplot\fR packages to graph the image and model lines or to compute +and graph residuals. +.ih +SEE ALSO +newimage +.endhelp diff --git a/noao/twodspec/multispec/doc/msextract.hlp b/noao/twodspec/multispec/doc/msextract.hlp new file mode 100644 index 00000000..fa361b38 --- /dev/null +++ b/noao/twodspec/multispec/doc/msextract.hlp @@ -0,0 +1,172 @@ +.help msextract Jul84 noao.twodspec.multispec +.ih +NAME +msextract -- Extract spectra from a multi-spectra image +.ih +USAGE +msextract image output +.ih +PARAMETERS +.ls image +Image to be extracted. +.le +.ls output +Filename for the three dimensional image to be created containing the +extracted spectra. +.le +.ls lower = -10 +Lower limit of the integral for integrated spectra or the first column of the +strip spectra. It is measured in pixels from the spectrum center +defined by the position function in the MULTISPEC database. +.le +.ls upper = 10 +Upper limit of the integral for integrated spectra or (approximately) the +last column of the strip spectra. It is measured in pixels from the +spectrum center defined by the position function in the MULTISPEC database. +.le +.ls spectra = "*" +Spectra to be extracted. +.le +.ls lines = "*" +Image lines to be extracted. +.le +.ls ex_model = no +Extract model spectra fit to the image spectra? +.le +.ls integrated = yes +Extract integrated spectra? +.le +.ls unblend = no +Correct for blending in the extracted spectra? +.le +.ls clean = yes +Replace bad pixels with model values? The following parameters are used: +.ls nreplace = 1000. +Maximum number of pixels to be replaced per image line when cleaning with +model \fIgauss5\fR or maximum number of pixels to be replaced per spectrum when +cleaning with model \fIsmooth\fR. +.le +.ls sigma_cut = 4. +Cleaning threshold in terms of sigma of the fit. +.le +.ls niterate = 1 +Maximum number of cleaning iterations per line when cleaning with model +\fIgauss5\fR. +.le +.le +.ls model = "smooth" +Choice of \fIgauss5\fR or \fIsmooth\fR. Minimum match abbreviation is +allowed. This parameter is required only if \fIex_model\fR = yes +or \fIclean\fR = yes. +.le +.ls naverage = 20 +Number of lines to be averaged in model \fIsmooth\fR. +.le +.ls fit_type = 2 +Model fitting algorithm for model \fIgauss5\fR. +.le +.ls interpolator = "spline3" +Type of image interpolation function to be used. +The choices are "nearest", "linear", "poly3", "poly5", and "spline3". +Minimum match abbreviation is allowed. +.le +.ls verbose = no +Print verbose output? +.le +.ih +DESCRIPTION +The MULTISPEC database describing the spectra positions and shapes +is used to guide the extraction of the spectra in the multi-spectra image. +The user selects the \fIspectra\fR and image +\fIlines\fR to be extracted and whether to extract integrated or strip spectra. +In addition options are available to extract model spectra, replace bad +pixels by model spectra values, and correct for blending of the spectra. +The \fIoutput_file\fR three dimensional +image consists of one band (the third dimension) per extracted spectrum, +the extracted lines (the second dimension) and either one column for +the integrated luminosity or the number of columns in the extracted strip. + +Integrated spectra (\fIintegrated\fR = yes) are extracted by summing +the pixel or model values over the specified limits \fIlower\fR and \fIupper\fR +measured relative to the spectra centers defined by the position functions in +the database. Partial pixel sums are used at the endpoints. + +Strip spectra (\fIintegrated\fR = no) are extracted by image interpolation +of the image line or model profiles to obtain a line of values for +each spectrum and for each image line. The length of the strip is the +smallest integer containing the interval between \fIlower\fR and \fIupper\fR. +The strips for each spectrum are aligned so that the first column is a distance +\fIlower\fR from the spectrum center as given by the position function in the +database. + +If \fIex_model\fR = yes, \fIunblend\fR = yes, or \fIclean\fR = yes model +spectra are fit to the spectra in the image. There are two models: +a five parameter Gaussian profile called \fIgauss5\fR and profiles obtained +by averaging \fInaverage\fR image lines surrounding the image line being +modeled called \fIsmooth\fR. The model is selected either when the parameter +\fIunblend\fR = yes or with the parameter \fImodel\fR. If \fIunblend\fR = yes +then the model is \fIgauss5\fR regardless of the value of \fImodel\fR. + +When \fIex_model\fR = yes the effect is to substitute model spectra for the +image spectra in the output extraction image. + +When \fIclean\fR = yes pixels with large residuals from the model are +detected and removed from the model fit. The selected model is +fit to the pixels which are not in the bad pixel list (not yet implemented) +and which have not been removed from the model fit. The sigma of the fit +is computed. Deviant pixels are detected by comparing them to the model +to determine if they differ by more than \fIsigma_cut\fR times the sigma. +The model fit is iterated, removing deviant pixels at each iteration, until +no more pixels are found deviant or \fInreplace\fR pixels have been found. +The pixels removed or in the bad pixel list are then replaced with +model values. (To clean an image with this algorithm see \fBnewimage\fR.) + +There are some technical differences in the model fitting and cleaning +algorithms for the two models. In model \fIsmooth\fR +the fit for the profile scale factors is done independently for each spectrum +and automatically corrected when a bad pixel is detected. This fitting process +is fast and rigorous. The parameter \fInreplace\fR in this model refers to +the maximum number of pixels replaced \fIper spectrum\fR. + +In model \fIgauss5\fR, however, the profile scale factors are fit +to the entire image line (hence its ability to fit blended spectra). +There are two fitting algorithms; a rigorous simultaneous fit +and an approximate method. The simultaneous fit is selected when +\fIfit_type\fR = 1. This step is relatively slow. The +alternative method of \fIfit_type\fR = 2 sets the scale factor for each +spectrum by taking the median scale, where scale = data / model profile, +for the three pixels nearest the center of the profile. The median +minimizes the chance of a large error due to a single bad pixel. This +scale may be greatly in error in the case of extreme blending but is also +quite fast; the extraction time is reduced by at least 40%. +The steps of profile fitting and deviant pixel detection are alternated +and the maximum number of iterations through these two steps is +set by \fIniterate\fR. The default of 1 means that the model fitting is not +repeated after detecting deviant pixels. + +When \fIunblend\fR = yes the \fIgauss5\fR model +is fitted to the image spectra (including possible cleaning). +The relative contributions to the total image pixel value from each of the +blended spectra are determined from the model and applied toward either the +integrated or strip spectra. If \fIex_model\fR = yes then this option has +no effect other than to force the selection of model \fIgauss5\fR. + +The option \fIverbose\fR is used to print the image lines being extracted +and the number of pixels replaced by the cleaning process. +.ih +EXAMPLES +To extract all the integrated spectra from all the image lines: + + cl> msextract image image.ms + +To extract model strip spectra: + + cl> msextract image image.ms ex_model=yes int=no + +To extract integrated spectra without any modeling: + + cl> msextract image image.ms clean=no +.ih +SEE ALSO +newimage +.endhelp diff --git a/noao/twodspec/multispec/doc/mslist.hlp b/noao/twodspec/multispec/doc/mslist.hlp new file mode 100644 index 00000000..461b52b4 --- /dev/null +++ b/noao/twodspec/multispec/doc/mslist.hlp @@ -0,0 +1,77 @@ +.help mslist Jul84 noao.twodspec.multispec +.ih +NAME +mslist -- List entries in a MULTISPEC database +.ih +USAGE +mslist image keyword lines spectra +.ih +PARAMETERS +.ls image +Image whose MULTISPEC database entries are to be listed. +.le +.ls keyword +Keyword for the database entry to be listed. The keywords are: +.ls header +List general header information. +.le +.ls comments +List the comments. +.le +.ls samples +List the sample image lines. +.le +.ls x0 +List the spectra positions for the specified sample lines and spectra. +.le +.ls i0 +List the model profile scales for the specified sample lines and spectra. +.le +.ls s0, s1, or s2 +List the gauss5 model shape parameter s0, s1, or s2 for the specified sample +lines and spectra. +.le +.ls gauss5 +List the gauss5 model parameters x0, i0, s0, s1, and s2 for the specified +sample lines and spectra. +.le +.ls x0 spline +List the spline evaluation of the spectra positions for the specified +image lines and spectra. +.le +.ls s0 spline, s1 spline, or s2 spline +List the spline evaluation of the gauss5 model shape parameters s0, s1, or s2 +for the specified image lines and spectra. +.le +.le +.ls lines +Lines to be listed. For the entries x0, i0, s0, s1, s2, and gauss5 the +lines refer only to the sample image lines. For the spline entries the +lines refer to the image lines at which the spline is to be evaluated. +.le +.ls spectra +Spectra to be listed. +.le +.ls titles = no +Print additional titles? +.le +.ih +DESCRIPTION +This task is a general MULTISPEC database listing tool. A keyword is selected +and the referenced data is listed. Some entries require the specification of +the desired sample or image lines and the desired spectra. +.ih +EXAMPLES +To list the spectra positions for spectrum 3 at all the sample lines: + + cl> mslist image x0 "*" 3 + +To list the model profile scale parameter for sample line 1: + + cl> mslist image i0 1 "*" + +To list the gauss5 model parameters for spectra 2 and 3 and sample lines 5 +and 7: + + cl> mslist image gauss5 "5,7" "2-3" titles+ +.endhelp diff --git a/noao/twodspec/multispec/doc/msplot.hlp b/noao/twodspec/multispec/doc/msplot.hlp new file mode 100644 index 00000000..f08eac1b --- /dev/null +++ b/noao/twodspec/multispec/doc/msplot.hlp @@ -0,0 +1,44 @@ +.help msplot Oct85 noao.twodspec.multispec +.ih +NAME +msplot -- Plot data and model image line +.ih +USAGE +msplot image line +.ih +PARAMETERS +.ls image +Image to be plotted. +.le +.ls line +The image line to be plotted. Actually the nearest sample line will be +plotted. +.le +.ls naverage = 20 +Number of image lines to average about the specified line. +.le +.ls lower = -10., upper = 10. +Limits of the model profiles relative to the center of each profile. +.le +.ls graphics = "stdgraph" +Graphics output device. +.le +.ls cursor = "" +Graphics cursor input. If a file is given then the cursor input is taken +from the file. If no file is given then the standard graphics cursor will +be used. +.le +.ih +DESCRIPTION +A line of image data and the profile model for the line is graphed. +The model is graphed with a dashed line. The graph may be then expanded, +manipulated, and printed with the standard cursor mode commands. +.ih +EXAMPLES +To plot the model fit for image sample for image line 400: + + cl> msplot sample 400 +.ih +SEE ALSO +modellist +.endhelp diff --git a/noao/twodspec/multispec/doc/msset.hlp b/noao/twodspec/multispec/doc/msset.hlp new file mode 100644 index 00000000..689e525a --- /dev/null +++ b/noao/twodspec/multispec/doc/msset.hlp @@ -0,0 +1,104 @@ +.help msset Jul84 noao.twodspec.multispec +.ih +NAME +msset -- Set entries in a MULTISPEC database +.ih +USAGE +msset image keyword value +.ih +PARAMETERS +.ls image +Image in which the MULTISPEC database entries are to be modified or initialized. +.le +.ls keyword +Keyword for the database entry to be set. The keywords are: +.ls nspectra +Set the number of spectra in the header. +.le +.ls comments +Add comments lines to the database comment block. +.le +.ls x0 +Set the spectra positions for the specified sample lines and spectra. +.le +.ls i0 +Set the model profile central intensities for the specified sample lines +and spectra. +.le +.ls s0, s1, or s2 +Set the gauss5 model shape parameter s0, s1, or s2 for the specified sample +lines and spectra. +.le +.le +.ls value +Value to be used for value input. +.le +.ls lines = "*" +Sample lines to be affected by value input. +.le +.ls spectra = "*" +Spectra to be affected by value input. +.le +.ls read_list = no +If yes use list input and if no use value input. +.le +.ls list = "" +List for list input. See the description below for the appropriate format. +.le +.ih +DESCRIPTION +The entries in a MULTISPEC database associated with the image +are modified or initialized. +The parameters \fIimage\fR, \fIkeyword\fR, and \fIread_list\fR +determine the database to be operated upon, the database entry to +be set, and the input type. There are two forms of input; +list input and value input. +The input type is selected by the boolean parameter +\fIread_list\fR. For list input the parameter \fIlist\fR +is used and for value input the parameter \fIvalue\fR and +possibly the parameters \fIlines\fR and \fIspectra\fR are used. +The required parameters and input formats for the different keywords +are outlined below. +.ls nspectra +For list input the list format is the number of spectra and +for value input the \fIvalue\fR parameter is the number of spectra. +.le +.ls comments +For list input the list format is lines of comments and for value +input \fIvalue\fR parameter is a comment string. +.le +.ls x0, i0, s0, s1, s2 +For list input the list format is sample line, spectrum number, and +parameter value +and for value input \fIlines\fR is a range string selecting the +sample lines to be affected, \fIspectra\fR is a range string selecting +the spectra to be affected, and \fIvalue\fR is the value to be set for all +the selected lines and spectra. +.le +.ih +EXAMPLES +To add several comments to the database by query: + +.nf + cl> msset image "comments" read_list+ + Input list> First comment here. + Input list> Second comment here. + Input list> <eof> +.fi + +where <eof> is the end of file character terminating the list. +To set the value of s0 to 1 for all the spectra in sample line 1: + + cl> msset image "s0" 1 + +To set the spectra positions from a list: + + cl> msset image "x0" read_list+ list=positionlist + +To add a single comment such as in a script: + + cl> msset image "comments" "Comment here." +.ih +SEE ALSO +findspectra mslist +.endhelp diff --git a/noao/twodspec/multispec/doc/multispec.ms b/noao/twodspec/multispec/doc/multispec.ms new file mode 100644 index 00000000..cc17352e --- /dev/null +++ b/noao/twodspec/multispec/doc/multispec.ms @@ -0,0 +1,532 @@ +.EQ +delim $$ +.EN +.TL +The Multi-Spectra Extraction Package (multispec) +.AU +Francisco Valdes +.AI +IRAF Group +.K2 +October 1984 +.NH +Introduction +.PP +This document provides an introduction and overview of the multi-spectra +extraction package \fBmultispec\fR. Detailed descriptions and usage +information for the tasks of the package are available in the manual +pages. The tasks in the package are: + +.TS +center; +n. +findpeaks \&- Find the peaks +fitfunction \&- Fit a function to the spectra parameter values +fitgauss5 \&- Fit spectra profiles with five parameter Gaussian model +modellist \&- List data and model pixel values +msextract \&- Extract spectra +mslist \&- List entries in a MULTISPEC database +msplot \&- Plot a line of image and model data +msset \&- Set entries in a MULTISPEC database +newextraction \&- Create a new MULTISPEC extraction database +newimage \&- Create a new multi-spectra image +.TE + +.PP +The \fBmultispec\fR package is a subpackage of the \fBtwodspec\fR package. +It provides tools to locate, model, clean, correct for blending, +and extract integrated or strip spectra from two dimensional, multi-spectra +images. These tools may be used directly or combined in scripts to +extract specific types of spectra or spectra from specific instruments. +Examples of the latter usage are the tasks in the image reduction package +\fBcryomap\fR. +.PP +The extraction of spectra consists of locating pixels along each +image line which intersect the spectra and recording either the sum of +the pixels, \fIintegrated spectra\fR (some times referred to as +one-dimensional spectra), or the set of pixels, +\fIstrip spectra\fR, for each line and for each spectrum as output. +The size and limits of the intersection region are specified by the +user relative to the centers of the spectra. +The locations of the spectra in each image line are determined separately +so that the spectra need not be aligned along the columns of the image nor +be perfectly straight. However, since the extraction is done by image line, +if the spectra are not aligned with the columns then the spectral resolution +will be decreased. If the spectra are aligned with the image lines then +the image should be rotated or transposed using \fBimtranspose\fR. +.PP +The \fBmultispec\fR extraction produces three dimensional images with +one image band (the third dimension) for each extracted spectrum +and one line (the second dimension) for each extracted image line. +For integrated spectra there is only one column +while for strip spectra, the number of columns is equal to the extraction +strip width. The strips are aligned to the same positions relative to the +spectra centers by image interpolation. If desired the output extractions can +be reformated in a variety of ways. +.PP +In addition to direct extraction of the image spectra the \fBmultispec\fR +package provides for modeling the spectrum profiles. The model +may be extracted instead of the image spectra as either integrated or +strip spectra. The model may be used to correct for blending of the spectra +and to detect and replace bad pixels. The cleaning replaces data pixels which +are discrepant from the model by the model values. +.PP +The modeling and cleaning features of the \fBmultispec\fR package can also +be used for creating new multi-spectra images. In other words a new +image is created containing cleaned or model spectra for selected +lines. +.PP +Section 2 gives an overview of the \fBmultispec\fR package and the extraction +process. The next section briefly describes the tasks in the package. +This is followed by a description of the extraction database. +The final section defines the model profiles used in the \fBmultispec\fR +package. +.NH +Overview of the Multispec Package and the Extraction Process +.PP +The \fBmultispec\fR package consists of general and flexible tools +for creating and manipulating databases which describe multi-spectra +images. The contents of the databases are described in a later section. +Each database is associated with a particular image and is referenced +through the image name. The first positional argument in all the +\fBmultispec\fR tasks is an image. In the current version of the package each +database exists as a separate binary file with a filename formed by adding +the extension '.db' to the image name. Note, however, that this +need not be the case in the future. +.PP +The organization of the package as a set of tools operating on a database +allows room for the package to evolve. Different algorithms may be +designed for different types of multi-spectra images by using combinations +of the existing tools and by adding new tools. The discussion below +points out areas where new tasks might be added as well as citing the +applicable existing tasks. +.PP +The extraction of spectra from a multi-spectra image consists of two +basic steps; determining the locations of the spectra in the image and +extracting the spectra. The positions of the spectra in a multi-spectra +image are determined at a set of "sample" image lines. These positions +are used to fit an interpolation function defining the spectrum positions +at all the image lines. This function is then used in the extraction of +the spectra. +.PP +The sample image lines are chosen by the user when the database is first +created by the task \fBnewextraction\fR. An exception to this is when +a template image is used (discussed below). However, in this case the +sample image lines are still those chosen by the user when the template +image database was created. The sample image lines may consist of +anywhere from one image line to all the image lines. The purpose +of the sample lines is to sample the image often enough to follow changes +in the positions and shapes of the spectra but to still minimize the +time spent in finding the spectra and the size of the database. The choice +of sample lines also depends on the algorithm used to determine the +positions of the spectra; a large number of sample +lines for a fast, approximate method and a smaller number of lines +for a complex and accurate method. For example, in order to deal with +very blended spectra the task \fBfitgauss5\fR provides a sophisticated +model fitting algorithm. This technique is computationally slow and, so, +the user should not choose too many sample lines. +.PP +After the database has been created the minimum information needed +for extraction is the spectrum positions at the sample lines. There +are many ways in which the positions may be determined. Some +possibilities are listed below. + +.IP (1) +Enter the spectrum positions from a list using \fBmsset\fR. The +list might be generated from a graphics/cursor task. +This is method is very time consuming when the number of spectra and +the number of images are large. +.IP (2) +Determine the spectrum positions automatically by finding the peaks in +each sample image line. The task \fBfindpeaks\fR performs this function. +.IP (3) +Determine the spectrum positions at just one sample image line +using either (1) or (2) and trace the spectra by a fast and refined +peak finding method. Such a task is desirable but is not a part of the +current package. +.IP (4) +Determine the spectrum positions at just one sample image line +using either (1) or (2) and trace the spectra by fitting model +spectrum profiles. The task \fBfitgauss5\fR does this using +the model gauss5 described in section 5. Additional model fitting +tasks can be added as needed. +.IP (5) +Use the positions determined for a previous image and, if necessary, +refine the positions. \fBFitgauss5\fR is used to +refine the spectrum positions at each sample line independently. + +.PP +Several position finding algorithms may be used in stages to achieve +the degree of accuracy required by the user. +Thus, the first position determinations may be relatively crude and +then, if needed, more sophisticated methods may be applied to refine the +positions. The task \fBfindpeaks\fR is a crude peak finder. The positions +are only determined to the nearest pixel. The task \fBfitgauss5\fR is +a sophisticated model fitting techique which is used after \fBfindpeaks\fR +first determines the approximate positions of the spectra. +.PP +The determination of the spectra locations may be performed independently +at each sample line as in (1) and (2) above or the spectra locations may +be traced starting from one sample line as in (3) and (4). The second method +is preferable. Generally, \fBfindpeaks\fR is used at only one sample line +to initially determine the number and approximate locations of the spectra. +\fBFitgauss5\fR then fits model gauss5 to the spectrum profiles and +the model solution is used at the next sample line as the starting +point for the next model fit. In this manner the positions of +the spectra are determined at the other sample image lines. +.PP +The results of the peak finding and profile fitting are improved +by using an average of many image lines about the sample image line rather +than just the sample image line by itself. Both \fBfindpeaks\fR and +\fBfitgauss5\fR have this ablility. +.PP +It is often the case that several multi-spectra images have essentially +the same format; i.e. the same image size, the same number of spectra, +and the same positions (either approximately or identically). +Commonly, one of the images is used for calibrations and has strong, +high signal-to-noise spectra while the other images have weaker spectra. +In this case it is not necessary to repeat the position determinations. +The spectrum positions in one of the images, generally the one with +the strong calibration spectra, are determined first. This image is +then used as a "template" to provide the initial position estimates for +the other images. If the positions are identical no further work is needed, +otherwise, the positions can be refined to correct for small changes in the +positions and shapes of the spectra. +.PP +The task \fBnewextraction\fR creates new databases. If a template image +is specified then a copy is made of the template image database. This means +that the number of spectra and the sample image lines remain the same. +If the spectrum positions are slightly different from the template image +then the task \fBfitgauss5\fR is used to determine the new positions. +.PP +The spectrum positons and possibly any model parameters are interpolated +from the sample lines to the remaining image lines by fitting a function +to values at the sample lines. In addition, the function fits may +leave out poorly determined points and also smooth the values at the +sample lines. The task \fBfitfunction\fR fits selected functions of +specified order to the selected spectra and sample image lines. +.PP +The extraction of the spectra from multi-spectra images is performed by +the task \fBmsextract\fR. The task extracts either integrated or strip +spectra, either data or model values, with or without blending corrections, +and with or without replacing bad pixels by model values. +The user specifies the limits of the extraction +strip as well as the spectra and image lines to be extracted. +.PP +For the simplest type of data extractions (basically strip extraction) +no modeling is required. Other types of extractions, such as model +extractions and/or with cleaning and blending corrections require some +degree of modeling. There are two models which may be used; +"smooth" and "gauss5". These models are described in section 5. +The model parameters for model gauss5 must be set by \fBfitgauss5\fR +before \fBmsextract\fR is used. Additional models may added for +extraction as well as for the spectrum position determinations. +.PP +The model based features of \fBmsextract\fR -- model extractions +and cleaning -- are available in the related task \fBnewimage\fR. +This task creates new images which consist of either model spectra +or cleaned data spectra. +.PP +The models in the \fBmultispec\fR package assume that the profiles +go to zero; i.e. there is no background light. Background light +may be removed using \fBbackground\fR. In the future a task will +be provided create a mask defining the locations of the spectra from +the database which can be used with general surface fitting tasks +to create a background surface to be subtracted from the image. +.PP +The final step in using the \fBmultispec\fR package is to convert the +extraction output to the desired format. This may include graphs, +card image formats, and files for the \fBonedspec\fR and \fBlongslit\fR +packages. Currently, the available formats are images and IIDS +card images. +.NH +The Tasks of the Multispec Package +.PP +Use of the \fBmultispec\fR package begins with \fBnewextraction\fR and +ends, usually, with \fBmsextract\fR. In between there are tasks which +update, refine or change the database and tasks which provide diagnositic +information. The informational tasks can be combined with tasks from +other packages to produce tabular or graphical output. The task +\fBmsplot\fR is an example. In this section a brief description of +each task is given. Further information about the tasks, including usage, +is available in the manual pages. +.SH +findpeaks +.IP +Selected sample image lines are examined to determine the number and +column positions of data peaks in the line. An average of a number of image +lines surrounding the sample lines is formed in which the local maxima +are located. Various criteria are applied to cull the list of local +maxima to the desired peaks. These criteria include a peak threshold, +a maximum peak-to-peak contrast, a minimum peak separation, and a +maximum number of peaks. This task is used to determine crude, initial +estimates for the spectrum positions. It could be used alone for +simple extractions. +.SH +fitfunction +.IP +This task has two roles. It's primary role is to define the +interpolation/extrapolation function for the spectra +positions between the sample lines. The fitting function can be +either purely interpolative or may also provide smoothing of the +parameters from the sample lines. The second role is to provide +smoothing of the model parameters along the dispersion and the +ability to replace bad values by the function fit to the remaining +parameters. In this second role the user may iterate between +smoothing and model fittng. The functions are always defined between +the first and last image lines. +.SH +fitgauss5 +.IP +The model profiles gauss5, described in section 5, are fit to the +selected spectra and sample lines. The parameters to be determined +and the fitting algorithm may also be selected. +The model parameters are recorded in the database. +The model may be tracked from a starting line to other sample image +lines or each sample line may be fitted independently. +This task is used to accurately determine the spectrum positions +and provide an extraction model for heavily blended spectra. +.SH +modellist +.IP +For the selected sample image lines and image columns data +and model values are listed. This task is used to check how well +the model fitting tasks (currently just \fBfitgauss5\fR) have fit +the sample image line. The task \fBmsplot\fR is used to produce +graphical output. +.SH +msextract +.IP +This task does the actual extraction of spectra. It requires that +the spectrum positions are defined by fitting functions in the +database. If model gauss5 is to be used then the database must +also contain the model parameters for the sample image lines. It +extracts integrated or strip spectra, using data or model values, +with or without blending corrections, and with or without cleaning +of bad pixels. +.SH +mslist +.IP +Of the diagnositic or informational tasks \fBmslist\fR is the most +general. The user selects the type of information from the database +which is desired and it is then printed. The types of information +include the database header, the database comments, the spectra +positions and model parameter values for the sample lines, and the +interpolation/smoothing function values for any desired set of +image lines. +.SH +msplot +.IP +This task extracts data and models values and plots them superposed. +This task is used as a diagnositic tool to inspect how well model fitting +represents the image spectra. +.SH +msset +.IP +This task is a general tool for modifying or setting some of the quantities +in the database. The quantity to be changed or set is +selected by a keyword and the values are input in two ways; +with a list structured parameter (such a file containing the list of +values or the standard input) or as a parameter value. This task +is the way a user may enter comments in the database or manually +set the number and positions of the spectra. It is also used to +set the initial values for the gauss5 model parameters s0, s1, and s2 +prior to using \fBfitgauss5\fR. +.SH +newextraction +.IP +This task has three important roles. First it creates the database +associated with the multi-spectra image. Second, it defines the sample +image lines to be used. The user can specify as many or as few sample lines +as desired. It should be kept in mind that the more sample lines used +the larger the database becomes and the longer the processing time when +modeling the spectra. Finally, \fBnewextraction\fR allows +a database from another image (called a template image) to initialize the +database for the new multi-spectra image. The template image is generally +a calibration image with strong, well-defined spectra. +Initializing a database with a template image saves time, reduces problems +with bad pixels, and is more accurate when an image with weak spectra is +to be extracted. +.SH +newimage +.IP +This task is similar to \fBmsextract\fR; it uses the same algorithms +and parameters. It differs in the type output. +Rather than producing extracted integrated or strip spectra this task +produces new image lines. It is particularly useful for extracting +model images to be compared against the original image or to +produce images which have been cleaned. +.NH +The Multispec Database +.PP +The tasks in the \fBmultispec\fR package create and manipulate a database. +The database contains a description of the multi-spectra image which +is modified, refined, examined, or otherwise used by the tasks in the package. +In the current version the database is a separate binary file with a filename +formed by appending ".db" to the image name described by the database. +.PP +The database contains four basic types of data; general information, +comments and history, position parameters, and model parameters. +The data in the database is examined with the task \fBmslist\fR. +The general information section, called the database header, contains the +the name of the image, the size of the image, and the number of spectra in +the image. Once the number of spectra in the image has +been entered in the database it is an error to attempt to change this +number. The database must be deleted and a new database created in order +to change the number of spectra. +.PP +The comment and history section of the database contains text +strings. Each task which modifies the contents of the database places +a dated history line in this section. The user may also add comments +with \fBmsset\fR. Currently this information is not passed on to +the extraction output. +.PP +There are three types of position information in the database. The +first is a set of sample image lines. The sample lines are set when +the database is created by \fBnewextraction\fR. The sample lines select +which image lines from the multi-spectra image are to be examined and used +during the extraction. Information from these sample lines, and only +these sample lines, is entered in the database. The sample lines +may be listed with \fBmslist\fR. +.PP +The second type of position information is the positions of the +spectra (centers) at each sample line. These positions are initially +set by either \fBfindpeaks\fR or, manually, by \fBmsset\fR. The +position information is refined by fitting model profiles. +.PP +The third type of position information is a function fit to the +positions from all the sample lines for each spectrum. +These function fits are produced by \fBfitfunction\fR. +The functions define the positions of the spectra at all the image +lines. The spectra positions at the sample lines or the function +evaluation for any image line may be listed with \fBmslist\fR. +.PP +The finally type of basic data contained in the database are +model parameter values. A model need not be used in the extraction +but if one is used then the parameters determining the model profiles +are recorded in the database. The specific parameters depend on the +model. Currently the only model is \fIgauss5\fR. The model and its +parameters are described in section 5. +.PP +As with the spectra positions the parameters are stored in the database +in two forms; as values for each spectrum at each sample image line +and as function fits to the values at the sample lines which interpolate +them to any image line. The sample line values are +set by the model fitting tasks and the function fits are set by +\fBfitfunction\fR. The parameter values at the sample lines or the +function evaluations for any image lines may be listed with \fBmslist\fR. +.NH +Multispec Spectrum Profile Models +.PP +The spectra profiles in the image are modeled for many reasons: +To provide accurate, subpixel position determinations, to extract model +spectra or model images, to detect and replace bad pixels, and +to estimate and correct for blending between the spectra. +There are currently two models used in the \fBmultispec\fR package, "gauss5" +and "smooth". +.NH 2 +Model Gauss5 +.PP +The gauss5 model profiles are Gaussian but with a scale which varies +smoothly between the center and the edge of the profile. There +are five parameters: + +.RS +.IP x0 +The column position in the image line of the center of the profile. +.IP i0 +The intensity scale of the profile. It corresponds to the intensity +of the center of the profile. +.IP s0 +The zeroth order, constant, term in the Gaussian scale. +.IP s1 +The even first order term in the Gaussian scale. +.IP s2 +The odd first order term in the Gaussian scale. +.RE + +.PP +The mathematical form of the the model is shown in equation (1): +.EQ (1) +roman profile (x)~=~i0 exp~left { -s( DELTA x )~DELTA x sup 2 right } +.EN +where +.EQ +DELTA x ~=~x~-~x0~, +.EN +.EQ +s( DELTA x)~=~s0~+~s1~|y| +~s2~y~, +.EN +and +.EQ +y~=~ DELTA x / ( DELTA x sup 2 + alpha ) sup half ~. +.EN +The profile is defined within the user specified limits \fIlower\fR and +\fIupper\fR measured relative to the the profile center and +$alpha~=~(upper-lower)/4$. The quantity $y$ lies in the range +-1 to 1 over the interval in which the profile is defined. The odd +and even terms, s1 and s2, allow for symmetric and antisymmetric profile +changes relative to a simple Gaussian profile. +.PP +The task \fBfitgauss5\fR fits the gauss5 model to the spectrum profiles in +the sample image lines to determine one or more of the model parameters for +each spectrum. The parameter values are stored in the database for the image. +In \fBmsextract\fR the model profiles for each +image line are obtained by interpolating the profile shapes from the sample +lines (with the model parameters in the database determined by +\fBfitgauss5\fR) and then fitting only the intensity scale "i0". +There are a number of technical details associated with the model fitting +in each of these tasks which are discussed in the manual pages. +.PP +The gauss5 model is used to accurately determine the positions of the +spectrum centers at the sample image lines. Fitting simultaneously +for the model parameters allows the spectra to be blended. +This is the chief advantage of this model. +This model is also used during extraction to correct for blending of +the spectra and to detect and replace bad pixels. +.NH 2 +Model Smooth +.PP +The spectrum profiles from the lines immediately preceeding +the image line in which the spectrum profile is to be fit are shifted +to a common center and averaged to form the model profile. +An intensity scale factor is then determined which best fits the model +profile to the image profile. This is done for each spectrum in the +image. The scale factors are determined by least squares with +possible bad pixel rejection. Rejected pixels are eliminated +when the image line is later used in forming new average model profiles. +.PP +The advantages of this model are that the image spectrum profiles may +have any shape and the least squares fitting with bad pixel rejection +is fast and rigorous. By passing through the image lines sequentially +the image lines need be accessed only once and the profile averages +can be quickly updated for the next image line. +.PP +The disadvantages of this model are that the spectrum profiles cannot +be blended and the model does not measure profile positions. +This means that the spectrum profile positions must be +known. This model is suitable for model extractions and cleaning of +bad pixels in unblended multi-spectra images. It is available in +the task \fBmsextract\fR. +.bp +.SH +Glossary +.LP +\fBmultispec\fR +.IP +Acronym for Multi-Spectra Extraction as in \fBmultispec\fR Package. +.LP +integrated spectra +.IP +The spectra are extracted by integrating the pixel values across the spectrum +to produce a single aperture luminosity value. +.LP +sample image line +.IP +The spectra positions and model profile shapes are determined at a set +of image lines selected when the database is created. +.LP +strip spectra +.IP +The spectra are extracted as a strip of fixed with the spectra shifted by +image interpolation to a common center. diff --git a/noao/twodspec/multispec/doc/newextract.hlp b/noao/twodspec/multispec/doc/newextract.hlp new file mode 100644 index 00000000..37123f28 --- /dev/null +++ b/noao/twodspec/multispec/doc/newextract.hlp @@ -0,0 +1,61 @@ +.help newextraction Jul84 noao.twodspec.multispec +.ih +NAME +newextraction -- Initialize a new MULTISPEC extraction +.ih +USAGE +newextraction image template +.ih +PARAMETERS +.ls image +Image to be extracted. +.le +.ls template +The previously created database for the template image is used to initialize +the new database. If the null string is given then the database is not +initialized. +.le +.ls sample_lines = "10x50" +Sample image lines in which the spectra positions are to be determined and, +optionally, modeled. This parameter is not used if a template image is given. +.le +.ih +DESCRIPTION +To extract the spectra from a multi-spectra image a database must be created +and associated with the image. This task creates the database with a name +formed by adding the extension '.db' and initializes some of the database +entries. + +The sample lines are used to track the spectra positions and, if an analytic +profile model is to be fit to the spectra, to map profile shape changes. +The image lines only need be sampled enough to track \fInon-linear\fR position +distortions and significant profile shape changes since interpolation +is used between the sample lines. Though specifying just one sample +line is allowed using at least two sample lines is recommended to allow for +any slope in the position of the spectra. Specifying all the image lines +will greatly increase the processing time and is never justified. + +Using a previous database to initialize the new database is useful if the +new image is only slightly different in the positions and profiles of the +spectra. In some cases extraction may proceed immediately without any +further position determination and modeling. Further modeling +and spectra position determinations will refine the previously determined +parameters with an increase in execution time. Using a template image is +particularly important if the first image extracted has strong spectra +and subsequent images have much weaker spectra since the automatic spectra +position location and profile modeling may yield poor results for very weak +spectra. +.ih +EXAMPLES +To initialize a MULTISPEC database for extracting the spectra in +the image \fIimage1\fR: + + cl> newextraction image1 "" + +To create a new MULTISPEC database for extracting the spectra in +the image \fIimage2\fR using \fIimage1\fR as a template image: + +.nf + cl> newextraction image2 image1 +.fi +.endhelp diff --git a/noao/twodspec/multispec/doc/newimage.hlp b/noao/twodspec/multispec/doc/newimage.hlp new file mode 100644 index 00000000..1ef7fbe0 --- /dev/null +++ b/noao/twodspec/multispec/doc/newimage.hlp @@ -0,0 +1,130 @@ +.help newimage Jul84 noao.twodspec.multispec +.ih +NAME +newimage -- Create a new multi-spectra image +.ih +USAGE +newimage image output +.ih +PARAMETERS +.ls image +Image to be used to create the new image. +.le +.ls output +Filename for the new multi-spectra image. +.le +.ls lower = -10 +Lower limit for model profiles. It is measured in pixels from the +spectra centers defined by the position functions in the database. +.le +.ls upper = -10 +Upper limit for model profiles. It is measured in pixels from the +spectra centers defined by the position functions in the database. +.le +.ls lines = "*" +Image lines of the multi-spectra image to be in the new multi-spectra image. +.le +.ls ex_model = no +Create a model image? +.le +.ls clean = yes +Replace bad pixels with model values? The following parameters are used: +.ls nreplace = 1000. +Maximum number of pixels to be replaced per image line when cleaning with +model \fIgauss5\fR or maximum number of pixels to be replaced per spectrum when +cleaning with model \fIsmooth\fR. +.le +.ls sigma_cut = 4. +The cleaning threshold in terms of the predicted pixel sigma. +.le +.ls niterate = 1 +Maximum number of cleaning iterations per line when cleaning with model +\fIgauss5\fR. +.le +.le +.ls model = "smooth" +Choice of \fIgauss5\fR or \fIsmooth\fR. Minimum match abbreviation is +allowed. This parameter is required only if \fIex_model\fR = yes +or \fIclean\fR = yes. +.le +.ls fit_type = 2 +Model fitting algorithm for model \fIgauss5\fR. +.le +.ls naverage = 20 +Number of lines to be averaged in model \fIsmooth\fR. +.le +.ls interpolator = "spline3" +Type of image interpolation function to be used. +The choices are "nearest", "linear", "poly3", "poly5", and "spline3". +Minimum match abbreviation is allowed. +.le +.ls verbose = no +Print verbose output? +.le +.ih +DESCRIPTION +A new multi-spectra image is created using the description of the +multi-spectra image in the MULTISPEC database associated with \fIimage\fR. +The user selects the image \fIlines\fR from the original image to be in +the new image. The options allow the creation of model images or images in +which the bad or deviant pixels are replaced by model profile values. + +If \fIex_model\fR = yes or \fIclean\fR = yes model +spectra are fit to the spectra in the image. There are two models: +a five parameter Gaussian profile called \fIgauss5\fR and profiles obtained +by averaging \fInaverage\fR image lines surrounding the image line being +modeled called \fIsmooth\fR. The model is selected with the parameter +\fImodel\fR. + +When \fIex_model\fR = yes an image containing model spectra is produced. + +When \fIclean\fR = yes pixels with large residuals from the model are +detected and removed from the model fit. The selected model is +fit to the pixels which are not in the bad pixel list (not yet implemented) +and which have not been removed from the model fit. The sigma of the fit +is computed. Deviant pixels are detected by comparing them to the model +to determine if they differ by more than \fIsigma_cut\fR times the sigma. +The model fit is iterated, removing deviant pixels at each iteration, until +no more pixels are found deviant or \fInreplace\fR pixels have been found. +The pixels removed or in the bad pixel list are then replaced with +model values. (To clean and extract the spectra with this algorithm see +\fBmsextract\fR.) + +There are some technical differences in the model fitting and cleaning +algorithms for the two models. In model \fIsmooth\fR +the fit for the profile scale factors is done independently for each spectrum +and automatically corrected when a bad pixel is detected. This fitting process +is fast and rigorous. The parameter \fInreplace\fR in this model refers to +the maximum number of pixels replaced \fIper spectrum\fR. + +In model \fIgauss5\fR, however, the profile scale factors are fit +to the entire image line (hence its ability to fit blended spectra). +There are two fitting algorithms; a rigorous simultaneous fit +and an approximate method. The simultaneous fit is selected when +\fIfit_type\fR = 1. This step is relatively slow. The +alternative method of \fIfit_type\fR = 2 sets the scale factor for each +spectrum by taking the median scale, where scale = data / model profile, +for the three pixels nearest the center of the profile. The median +minimizes the chance of a large error due to a single bad pixel. This +scale may be greatly in error in the case of extreme blending but is also +quite fast; the extraction time is reduced by at least 40%. +The steps of profile fitting and deviant pixel detection are alternated +and the maximum number of iterations through these two steps is +set by \fIniterate\fR. The default of 1 means that the model fitting is not +repeated after detecting deviant pixels. + +The option \fIverbose\fR can be used to print the image lines being extracted +and any pixels replaced by the cleaning process. +.ih +EXAMPLES +To create a cleaned version of the image using model \fIsmooth\fR for cleaning: + + cl> newimage image newimage + +To create an model image using model \fIgauss5\fR: + + cl> newimage image newimage ex_model=yes model="gauss5" +.ih +SEE ALSO +msextract +.endhelp diff --git a/noao/twodspec/multispec/exgauss5.x b/noao/twodspec/multispec/exgauss5.x new file mode 100644 index 00000000..5c009239 --- /dev/null +++ b/noao/twodspec/multispec/exgauss5.x @@ -0,0 +1,100 @@ +include <imhdr.h> +include "ms.h" + + +# EX_GAUSS5 -- Extract spectra using the GAUSS5 model. +# +# This procedure is called either by t_extract to extract spectra (either +# integrated or strip) or by t_newimage to extract a new image (either +# model or cleaned data). It is called only if model GAUSS5 must be used +# for cleaning, blending corrections, or model extraction. + +procedure ex_gauss5 (ms, im_in, im_out, spectra, lines, lower, upper, + ex_spectra, ex_model, ex_integral) + +pointer ms # MULTISPEC pointer +pointer im_in # Input image descriptor +pointer im_out # Output image descriptor +int spectra[ARB] # Spectra range list +int lines[ARB] # Line range list +real lower # Lower limit of strip +real upper # Upper limit of strip +bool ex_spectra # Extract spectra or image line +bool ex_model # Extract model or data +bool ex_integral # Extract integrated spectra or strip + +int len_line, len_profile, nspectra, nparams +int line_in, line_out +pointer data, data_in, data_out +pointer sp, model, profiles, ranges, data_profiles + +int get_next_number() +pointer imgl2r(), impl2r() + +begin + # Set array size variables. + len_line = MS_LEN(ms, 1) + nspectra = MS_NSPECTRA(ms) + nparams = MS_NGAUSS5 + len_profile = nint (upper - lower + 2) + + # Allocate and setup necessary arrays. + call smark (sp) + call salloc (model, len_line, TY_REAL) + call salloc (ranges, nspectra * LEN_RANGES * 3, TY_REAL) + call salloc (profiles, len_profile * nspectra * nparams * 3, TY_REAL) + call salloc (data_profiles, len_profile * nspectra, TY_REAL) + + # Initialize ranges arrays. + Memr[ranges] = INDEFR + + # Loop through the input lines and write an output line for each + # input line. + line_in = 0 + line_out = 0 + while (get_next_number (lines, line_in) != EOF) { + line_out = line_out + 1 + call ex_prnt2 (line_in, line_out) + + # Get the multi-spectra image data. + data = imgl2r (im_in, line_in) + + # Get the GAUSS5 model profiles using interpolation between the + # sample lines. + call int_gauss5 (ms, lower, Memr[profiles], Memr[ranges], + len_profile, nspectra, nparams, line_in) + + # Iteratively fit the profile scales to the data and replace + # deviant pixels by model values. + call fit_and_clean (ms, Memr[data], Memr[model], Memr[ranges], + Memr[profiles], len_line, len_profile, nspectra, nparams) + + # Unblend data spectra only if needed. + if (ex_spectra && !ex_model) + call unblend (Memr[data], Memr[data_profiles], Memr[model], + Memr[profiles], Memr[ranges], len_line, len_profile, + nspectra) + + if (!ex_spectra) { + # Output a new model or data image line. + data_out = impl2r (im_out, line_out) + if (ex_model) + data_in = model + else + data_in = data + call amovr (Memr[data_in], Memr[data_out], len_line) + } else { + # Output either model or data extracted spectra. + if (ex_model) + data_in = profiles + else + data_in = data_profiles + call ex_out (im_out, line_out, spectra, lower, upper, + Memr[ranges], Memr[data_in], len_profile, nspectra, + ex_integral) + } + } + + # Free allocated memory. + call sfree (sp) +end diff --git a/noao/twodspec/multispec/exsmooth.x b/noao/twodspec/multispec/exsmooth.x new file mode 100644 index 00000000..f092529a --- /dev/null +++ b/noao/twodspec/multispec/exsmooth.x @@ -0,0 +1,107 @@ +include <imhdr.h> +include <math/interp.h> +include "ms.h" + +# EX_SMOOTH -- Extract spectra using the SMOOTH model. +# FIT_PROFILES -- Get SMOOTH profiles and fit the profiles to the data while +# replacing deviant pixels by model profile values. + + +# EX_SMOOTH -- Extract spectra using the SMOOTH model. +# +# This procedure is called either by t_extract to extract spectra (either +# integrated or strip) or by t_newimage to extract a new image (either +# model or cleaned data). It is called only if model SMOOTH must be used +# for cleaning or model extraction. It outputs the extracted spectra to +# the output image file. Note that this task does CLIO. + +procedure ex_smooth (ms, im_in, im_out, spectra, lines, lower, upper, + ex_spectra, ex_model, ex_integral) + +pointer ms # MULTISPEC pointer +pointer im_in # Input image descriptor +pointer im_out # Output image descriptor +int spectra[ARB] # Spectra range list +int lines[ARB] # Line range list +real lower # Lower limit of strips +real upper # Upper limit of strips +bool ex_spectra # Extract spectra or image line? +bool ex_model # Extract model or data? +bool ex_integral # Extract integrated or strip spectra? + +# User input parameters: +int nlines # Lines to average for smooth model +int interpolator # Line interpolator type + +int len_line, nspectra, len_profile, len_profiles +int line_in, line_out +pointer sp, data, data_in, data_out, model, ranges, profiles, coeff + +int clgeti(), get_next_number(), clginterp() +pointer impl2r() + +begin + # Get parameters for model SMOOTH. + nlines = clgeti ("naverage") + 1 + interpolator = clginterp ("interpolator") + + # Set array lengths. + len_line = IM_LEN(im_in, 1) + nspectra = MS_NSPECTRA(ms) + len_profile = nint (upper - lower + 1) + len_profiles = len_profile * nspectra + + # Allocate working memory. + call smark (sp) + call salloc (data, len_profiles, TY_REAL) + call salloc (model, len_profiles, TY_REAL) + call salloc (ranges, nspectra * LEN_RANGES, TY_REAL) + call salloc (profiles, len_profiles * (nlines + 1), TY_REAL) + call salloc (coeff, 2 * len_line + SZ_ASI, TY_REAL) + + # Initialize ranges and interpolation arrays. + call amovkr (lower, Memr[ranges + (DX_START-1)*nspectra], nspectra) + call asiset (Memr[coeff], interpolator) + + # Get fit position functions from the database. + call msgfits (ms, X0_FIT) + + # Loop through the input image lines and write output line. + line_in = 0 + line_out = 0 + while (get_next_number (lines, line_in) != EOF) { + line_out = line_out + 1 + call ex_prnt2 (line_in, line_out) + + # Get the SMOOTH profiles and the data for the input line. + call set_smooth (ms, im_in, line_in, Memr[ranges], Memr[profiles], + Memr[coeff], len_profile, nspectra, nlines, Memr[data], + Memr[model]) + + # Fit and clean the data and model. + call fit_smooth (line_in, Memr[data], Memr[model], + Memr[profiles], len_profile, nspectra, nlines) + + # Select model or data to be output. + if (ex_model) + data_in = model + else + data_in = data + + if (ex_spectra) { + # Extract model or data spectra. + call ex_out (im_out, line_out, spectra, lower, upper, + Memr[ranges], Memr[data_in], len_profile, nspectra, + ex_integral) + } else { + # Extract model or data image line. + data_out = impl2r(im_out, line_out) + call set_model1 (ms, line_in, Memr[data_in], Memr[coeff], + Memr[ranges], len_line, len_profile, nspectra, + Memr[data_out]) + } + } + + # Free allocated memory. + call sfree (sp) +end diff --git a/noao/twodspec/multispec/exstrip.x b/noao/twodspec/multispec/exstrip.x new file mode 100644 index 00000000..a114b5a8 --- /dev/null +++ b/noao/twodspec/multispec/exstrip.x @@ -0,0 +1,203 @@ +include <imhdr.h> +include <math/interp.h> +include "ms.h" + +# EX_STRIP -- Simple strip extraction of spectra. +# EX_STRIP1 -- Extract integrated spectra. +# EX_STRIP2 -- Extract two dimensional strip spectra. + + +# EX_STRIP -- Simple strip extraction of spectra. +# +# This procedure is called either by t_extract to extract spectra (either +# integrated or strip) or by t_newimage to extract a new image. +# Since there is no modeling only data spectra or image lines are extracted. +# It outputs the extracted spectra or image lines to the output image file. + +procedure ex_strip (ms, im_in, im_out, spectra, lines, lower, upper, + ex_spectra, ex_model, ex_integral) + +pointer ms # MULTISPEC pointer +pointer im_in # Input image descriptor +pointer im_out # Output image descriptor +int spectra[ARB] # Spectra range list +int lines[ARB] # Line range list +real lower # Lower limit of strips +real upper # Upper limit of strips +bool ex_spectra # Extract spectra or image line +bool ex_model # Extract model or data +bool ex_integral # Extract integrated spectra or strip + +int line_in, line_out +pointer data_in, data_out + +int get_next_number() +pointer imgl2r(), impl2r() + +begin + if (ex_model) + call error (MS_ERROR, "Can't extract model") + + if (ex_spectra) { + # Extract spectra using ex_strip1 for integrated spectra and + # ex_strip2 for strip spectra. + if (ex_integral) + call ex_strip1 (ms, im_in, im_out, spectra, lines, lower, + upper) + else + call ex_strip2 (ms, im_in, im_out, spectra, lines, lower, + upper) + } else { + # Create a new multi-spectra image by copying the selected + # input image lines to the output image. + line_in = 0 + line_out = 0 + while (get_next_number (lines, line_in) != EOF) { + line_out = line_out + 1 + data_in = imgl2r (im_in, line_in) + data_out = impl2r (im_out, line_out) + call amovr (Memr[data_in], Memr[data_out], IM_LEN(im_out, 1)) + } + } +end + +# EX_STRIP1 -- Extract integrated spectra. +# +# For each spectrum in the spectra range list and for each line in +# the line range list the pixels between lower and upper (relative +# to the spectrum center) are summed. +# The spectra positions are obtained from the MULTISPEC database. + +procedure ex_strip1 (ms, im_in, im_out, spectra, lines, lower, upper) + +pointer ms # MULTISPEC pointer +pointer im_in # Input image descriptor +pointer im_out # Output image descriptor +int spectra[ARB] # Spectra range list +int lines[ARB] # Line range list +real lower # Lower limit of strips +real upper # Upper limit of strips + +int line_in, line_out, spectrum_in, spectrum_out +real x_center, x_start, x_end +pointer buf_in, buf_out + +real sum_pixels(), cveval() +int get_next_number() +pointer imgl2r(), impl3r() + +begin + # Get fit functions for spectra positions. + call msgfits (ms, X0_FIT) + + # Loop through the input lines and write integrated spectra out. + line_in = 0 + line_out = 0 + while (get_next_number (lines, line_in) != EOF) { + line_out = line_out + 1 + + # Get the input data line. + buf_in = imgl2r (im_in, line_in) + + # Loop the the spectra, calculate the integrated luminosity and + # write it to the output image. + spectrum_in = 0 + spectrum_out = 0 + while (get_next_number (spectra, spectrum_in) != EOF) { + spectrum_out = spectrum_out + 1 + + buf_out = impl3r (im_out, line_out, spectrum_out) + + # Determine the spectrum limits from spectrum center position. + x_center = cveval (CV(ms, X0_FIT, spectrum_in), real (line_in)) + x_start = max (1., x_center + lower) + x_end = min (real (IM_LEN(im_in, 1)), x_center + upper) + Memr[buf_out] = + sum_pixels (Memr[buf_in], x_start, x_end) + } + } +end + +# EX_STRIP2 -- Extract two dimensional strip spectra. +# +# Each line in the range list is fit by an image interpolator and then for +# each spectrum in spectra range list the interpolator values between lower +# and upper (relative to the spectrum center) are written to a three +# dimensional image. There is one band for each spectrum. The spectra +# positions are obtained from the MULTISPEC database. +# The procedure requests the interpolator type using CLIO. + +procedure ex_strip2 (ms, im_in, im_out, spectra, lines, lower, upper) + +pointer ms # MULTISPEC pointer +pointer im_in # Input image descriptor +pointer im_out # Output image descriptor +int spectra[ARB] # Spectra range list +int lines[ARB] # Line range list +real lower # Lower limit of strip +real upper # Upper limit of strip + +int interpolator # Array interpolar type + +int i, len_in, len_out, line_in, line_out, spectrum_in, spectrum_out +real x, x_start +pointer buf_in, buf_out +pointer sp, coeff + +int get_next_number(), clginterp() +real asival(), cveval() +pointer imgl2r(), impl3r() +errchk salloc, imgl2r, impl3r +errchk asiset, asifit, asival, clginterp + +begin + # Get the image interpolator type. + interpolator = clginterp ("interpolator") + + len_in = IM_LEN (im_in, 1) + len_out = nint (upper - lower + 1) + + # Set up the interpolator coefficient array. + call smark (sp) + call salloc (coeff, 2 * len_in + SZ_ASI, TY_REAL) + call asiset (Memr[coeff], interpolator) + + # Get the spectra position functions from the database. + call msgfits (ms, X0_FIT) + + # Loop through the input lines, do the image interpolation and write + # the strip spectra to the output. + line_in = 0 + line_out = 0 + while (get_next_number (lines, line_in) != EOF) { + line_out = line_out + 1 + + # Get the input data and fit an interpolation function. + buf_in = imgl2r (im_in, line_in) + call asifit (Memr[buf_in], len_in, Memr[coeff]) + + # Loop through the spectra writing the strip spectra. + spectrum_in = 0 + spectrum_out = 0 + while (get_next_number (spectra, spectrum_in) != EOF) { + spectrum_out = spectrum_out + 1 + buf_out = impl3r (im_out, line_out, spectrum_out) + + # Determine the starting position for the strips and + # evaluate the interpolation function at each point in + # the strip. + x_start = cveval (CV(ms, X0_FIT, spectrum_in), real (line_in)) + + lower + do i = 1, len_out { + x = x_start + i - 1 + if ((x < 1) || (x > len_in)) + Memr[buf_out + i - 1] = 0. + else + Memr[buf_out + i - 1] = asival (x, Memr[coeff]) + } + } + } + + # Free interpolator memory. + call sfree (sp) +end diff --git a/noao/twodspec/multispec/findpeaks.par b/noao/twodspec/multispec/findpeaks.par new file mode 100644 index 00000000..04d00e1a --- /dev/null +++ b/noao/twodspec/multispec/findpeaks.par @@ -0,0 +1,13 @@ +# FINDPEAKS + +image,f,a,,,,Image to be searched +lines,s,a,,,,Images lines to be searched for peaks +contrast,r,a,,,,Maximum contrast between peak values +separation,i,h,5,,,Minimum separation between peaks +edge,i,h,0,0,,Minimum separation from the image edge +threshold,r,h,0.,,,Minimum peak threshold for selecting peaks +min_npeaks,i,h,1,,,Minimum number of peaks to be found +max_npeaks,i,h,1000,,,Maximum number of peaks to be found +columns,s,h,"*",,,Image columns to be searched for peaks +naverage,i,h,20,,,Number of image lines to average +debug,b,h,no,,,Print debugging information? diff --git a/noao/twodspec/multispec/fitclean.x b/noao/twodspec/multispec/fitclean.x new file mode 100644 index 00000000..548f2cf4 --- /dev/null +++ b/noao/twodspec/multispec/fitclean.x @@ -0,0 +1,257 @@ +include "ms.h" + +# FIT_AND_CLEAN -- Iteratively fit profile scales using banded matrix method +# and remove deviant pixels. +# +# The profile fitting and cleaning are combined in order to minimize +# the calculations in re-evaluating the least squares fit after rejecting +# deviant pixels. +# +# The sigma of the fit is calculated and deviant pixels are those whose +# residual is more than +-sigma_cut * sigma. +# The maximum number of pixels to be replaced is max_replace. +# If max_replace is zero then only the model fitting is performed. +# +# The output of this routine are the cleaned data profiles and the +# least-square fitted model profiles. Return the number of pixels replaced. + + +procedure fit_and_clean (ms, data, model, ranges, profiles, len_line, + len_profile, nspectra, nparams) + +pointer ms # MULTISPEC data structure +real data[len_line] # Input data to be fit +real model[len_line] # Output model line +real ranges[nspectra, LEN_RANGES, 3] # Profile ranges +real profiles[len_profile, nspectra, nparams, 3] # Model profiles +int len_line # Length of data/model line +int len_profile # Length of each profile +int nspectra # Number of spectra +int nparams # Number model parameters + +int max_iterate # Maximum number of iterations +int max_replace # Maximum number of bad pixels +real sigma_cut # Rejection cutoff +int fit_type # Type of I0 fitting +bool ex_model # Extract model? + +bool exmod +int i_max, nmax, option, npts +int i, iteration, n_total, n_reject +real sigma, lower, upper, residual, resid_min, resid_max + +begin + # Initialize the model and I0 parameters to zero. + call aclrr (PARAMETER(ms,I0,1), nspectra) + call aclrr (model, len_line) + + # Loop until no further deviant pixels are found. + n_total = 0 + + do iteration = 1, imax { + # Determine I0 for each profile. + switch (option) { + case 1: + call full_solution (ms, data, model, ranges, profiles, + len_line, len_profile, nspectra, nparams) + case 2: + call quick_solution (ms, data, ranges, profiles, len_line, + len_profile, nspectra) + } + + # Set the model to be used to compare against the data. + call set_model (ms, model, profiles, ranges, len_line, len_profile, + nspectra) + + # If number of pixels to reject is zero then skip below. + n_reject = 0 + if (n_total == nmax) + break + + # Compute sigma of fit. + sigma = 0. + npts = 0 + do i = 1, len_line { + if ((model[i] > 0.) && (!IS_INDEFR (data[i]))) { + sigma = sigma + (data[i] - model[i]) ** 2 + npts = npts + 1 + } + } + sigma = sqrt (sigma / npts) + resid_min = -lower * sigma + resid_max = upper * sigma + + # Compare each pixel against the model and set deviant pixels + # to INDEFR. If the number of pixels replaced is equal to the + # maximum allowed stop cleaning. Ignore points with model <= 0. + # Thus, points outside the spectra will not be cleaned. + # Ignore INDEFR pixels. + do i = 1, len_line { + if (n_total == nmax) + break + if ((model[i] <= 0.) || (IS_INDEFR (data[i]))) + next + + # Determine deviant pixels. + residual = data[i] - model[i] + if ((residual < resid_min) || (residual > resid_max)) { + # Flag deviant pixel. + data[i] = INDEFR + n_total = n_total + 1 + n_reject = n_reject + 1 + } + } + + if (n_reject == 0) + break + } + # Refit model if a model extraction is desired and bad pixels were + # in the last fit. + if (exmod && n_reject != 0) { + switch (option) { + case 1: + call full_solution (ms, data, model, ranges, profiles, + len_line, len_profile, nspectra, nparams) + case 2: + call quick_solution (ms, data, ranges, profiles, len_line, + len_profile, nspectra) + } + } + + # Scale profiles to form model profiles. + do i = 1, nspectra + call amulkr (profiles[1,i,I0_INDEX,1], PARAMETER(ms,I0,i), + profiles[1,i,I0_INDEX,1], len_profile) + + # Replace deviant or INDEF pixels by model values. + # Even if no cleaning was done there may have been some INDEF points + # in the input data line. + + do i = 1, len_line { + if (IS_INDEFR (data[i])) + data[i] = model[i] + } + + # Print the number of pixels replaced and return. + call ex_prnt3 (n_total) + return + +# SET_FIT_AND_CLEAN -- Set the fitting and cleaning parameters. + +entry set_fit_and_clean (max_iterate, max_replace, sigma_cut, fit_type, + ex_model) + + imax = max_iterate + nmax = max_replace + lower = sigma_cut + upper = sigma_cut + option = fit_type + exmod = ex_model + return +end + + +procedure full_solution (ms, data, model, ranges, profiles, len_line, + len_profile, nspectra, nparams) + +pointer ms # MULTISPEC data structure +real data[len_line] # Input data to be fit +real model[len_line] # Output model line +real ranges[nspectra, LEN_RANGES, 3] # Profile ranges +real profiles[len_profile, nspectra, nparams, 3] # Model profiles +int len_line # Length of data/model line +int len_profile # Length of each profile +int nspectra # Number of spectra +int nparams # Number model parameters + +real rnorm +pointer sp, fitparams, solution, offset + +begin + # Initialize fitparams and ranges arrays. + call smark (sp) + call salloc (fitparams, nspectra * nparams, TY_REAL) + call salloc (solution, nspectra * nparams, TY_REAL) + + offset = (I0_INDEX - 1) * nspectra + call amovki (NO, Memr[fitparams], nspectra * nparams) + call amovki (YES, Memr[fitparams + offset], nspectra) + + # Do least squares banded matrix solution for I0 parameters. + # The solution vector contains the least square fit values which + # must be copied to the I0 parameter vector. + call solve (ms, data, model, Memr[fitparams], profiles, ranges, + len_line, len_profile, nspectra, nparams, Memr[solution], rnorm) + call aaddr (PARAMETER(ms, I0, 1), Memr[solution + offset], + PARAMETER(ms, I0, 1), nspectra) + + call sfree (sp) +end + + +# QUICK_SOLUTION -- Quick determination of profile scaling parameters. + +procedure quick_solution (ms, data, ranges, profiles, len_line, len_profile, + nspectra) + +pointer ms # MULTISPEC data structure +real data[len_line] # Input data to be fit +real ranges[nspectra, LEN_RANGES] # Profile ranges +real profiles[len_profile, nspectra, ARB] # Model profiles +int len_line # Length of data/model line +int len_profile # Length of each profile +int nspectra # Number of spectra + +int i, ic, j, n, spectrum, xc +real i0[3] + +begin + ic = len_profile / 2 + + # Determine a value for I0 for each spectrum which is in the image. + do spectrum = 1, nspectra { + n = 0 + + # Check each profile point from ic on until n = 2. + do i = ic, len_profile - 1 { + xc = ranges[spectrum, X_START] + i + if ((xc < 1) || (xc > len_line)) + next + if (IS_INDEFR (data[xc])) + next + j = i + 1 + if (profiles[j, spectrum, I0_INDEX] <= 0) + next + n = n + 1 + i0[n] = data[xc] / profiles[j, spectrum, I0_INDEX] + if (n >= 2) + break + } + + # Check each profile point from ic - 1 and less until n = 3. + do i = ic - 1, 0, -1 { + xc = ranges[spectrum, X_START] + i + if ((xc < 1) || (xc > len_line)) + next + if (IS_INDEFR (data[xc])) + next + j = i + 1 + if (profiles[j, spectrum, I0_INDEX] <= 0) + next + n = n + 1 + i0[n] = data[xc] / profiles[j, spectrum, I0_INDEX] + break + } + + # Determine I0. + switch (n) { + case 3: # Use median I0 + call asrtr (i0, i0, n) + PARAMETER(ms, I0, spectrum) = i0[2] + case 2: # Use mean I0 + PARAMETER(ms, I0, spectrum) = (i0[1] + i0[2]) / 2 + case 1: # Use only value + PARAMETER(ms, I0, spectrum) = i0[1] + } + } +end diff --git a/noao/twodspec/multispec/fitfunction.par b/noao/twodspec/multispec/fitfunction.par new file mode 100644 index 00000000..72e61620 --- /dev/null +++ b/noao/twodspec/multispec/fitfunction.par @@ -0,0 +1,8 @@ +# FITFUNCTION + +image,f,a,,,,Image +parameter,s,h,x0,,,Database parameter to be fitted +lines,s,h,"*",,,Images lines in function fit +spectra,s,h,"*",,,Spectra to be fit +function,s,h,"spline3",,,Fitting function +order,i,h,INDEF,,,Order of spline diff --git a/noao/twodspec/multispec/fitgauss5.com b/noao/twodspec/multispec/fitgauss5.com new file mode 100644 index 00000000..65bd9bb8 --- /dev/null +++ b/noao/twodspec/multispec/fitgauss5.com @@ -0,0 +1,9 @@ +# Common for fitting model GAUSS5. + +real factor # Convergence factor +int spectra[3, MAX_RANGES] # Spectra to fit +int parameters[MS_NGAUSS5] # Parameters to be fit +int smooth[MS_NGAUSS5] # Smooth parameters? +int algorithm # Fitting algorithm + +common /g5_fitcom/ factor, spectra, parameters, smooth, algorithm diff --git a/noao/twodspec/multispec/fitgauss5.par b/noao/twodspec/multispec/fitgauss5.par new file mode 100644 index 00000000..276a3b19 --- /dev/null +++ b/noao/twodspec/multispec/fitgauss5.par @@ -0,0 +1,23 @@ +# FITGAUSS5 + +image,f,a,,,,Image +start,i,a,,,,Starting image line +lower,r,h,-10.,,,Lower limit of model profiles +upper,r,h,10.,,,Upper limit of model profiles +lines,s,h,"*",,,Images lines to be fitted +spectra,s,h,"*",,,Spectra to be fitted +naverage,i,h,20,1,,Number of image lines to average +factor,r,h,.05,0,1,RMS iteration improvement stopping criteria +track,b,h,yes,,,Track solution? +algorithm,i,h,1,1,2,Fitting algorithm +fit_i0,b,h,y,,,Fit spectra central intensities? +fit_x0,b,h,y,,,Fit spectra positions? +fit_s0,b,h,y,,,Fit spectra shape parameter 0? +fit_s1,b,h,n,,,Fit spectra shape parameter 1? +fit_s2,b,h,n,,,Fit spectra shape parameter 2? +smooth_s0,b,h,no,,,Smooth parameter s0 across spectra? +smooth_s1,b,h,no,,,Smooth parameter s1 across spectra? +smooth_s2,b,h,no,,,Smooth parameter s2 across spectra? +function,s,h,"spline3",,,"Smoothing function (legendre,chebyshev,spline3)" +order,i,h,4,,,Order for smoothing function +verbose,b,h,no,,,Print general information about the fitting? diff --git a/noao/twodspec/multispec/fitgauss5.x b/noao/twodspec/multispec/fitgauss5.x new file mode 100644 index 00000000..b1e07b58 --- /dev/null +++ b/noao/twodspec/multispec/fitgauss5.x @@ -0,0 +1,460 @@ +include <fset.h> +include "ms.h" + +# FITGAUSS5 -- Procedures used in fitting the GAUSS5 model. +# +# G5_FIT1 -- Fitting algorithm #1. +# G5_FIT2 -- Fitting algorithm #2. +# G5_FIT -- Fit the selected parameters for the best RMS value. +# SET_VERBOSE -- Verbose output. + +######################################################################## +.helpsys g5fit1 Jul84 MULTISPEC +.ih +NAME +G5_FIT1 -- Fitting algorithm #1. +.ih +DESCRIPTION +This algorithm fits the selected parameters simultaneously. +The parameters are selected by the parameter array (which of the 5 +model parameters in a profile are to be fit) and the spectra range +array defined in fitgauss5.com. These two arrays are used to generate +the fitparms array with the routine set_fitparams. The fitparams array +controls the parameters fit by G5_FIT. +.ih +PARAMETERS +The model parameter values which are part of the MULTISPEC data structure, +the data array, the model array, the model profiles, and the profile +ranges must be initialized. Other parameters for this procedure are +input via the common in file fitgauss5.com. These include the spectra +to be fit and the parameters array. +.ih +OUTPUT +The returned data are the final parameter values, the model and profiles +arrays and the Y/N function value indicating if the RMS fit has been improved. +.endhelp +######################################################################## + +int procedure g5_fit1 (ms, data, model, profiles, ranges, lower, len_profile) + +pointer ms # MULTISPEC database data +real data[ARB] # Line of image pixels +real model[ARB] # Line of model pixels +real profiles[ARB] # Model profiles +real ranges[ARB] # Origins of model profiles +real lower # Profile origin +int len_profile # Length of a model profile + +int improved +real rms +pointer sp, fitparams + +int g5_fit() +real armsrr() + +include "fitgauss5.com" + +begin + # Calculate the initial RMS. The parameter values are only changed + # if the new RMS is less than this value. + rms = armsrr (data, model, MS_LEN(ms, 1)) + call g5_prnt3 (rms) + + # Allocate and set the fitparams array. + call smark (sp) + call salloc (fitparams, MS_NSPECTRA(ms) * MS_NGAUSS5, TY_REAL) + call set_fitparams (spectra, parameters, MS_NSPECTRA(ms), MS_NGAUSS5, + Memr[fitparams]) + + # Call the fitting program once to simultaneously minimize the RMS. + improved = g5_fit (ms, data, model, profiles, ranges, Memr[fitparams], + lower, len_profile, rms) + + call sfree (sp) + return (improved) +end + +############################################################################### +.helpsys g5fit2 Jul84 MULTISPEC +.ih +NAME +G5_FIT2 -- Fitting algorithm #2. +.ih +DESCRIPTION +This algorithm begins by fitting the parameters I0, X0, and S0 +simultaneously. Note that the values of S1 and S2 are used but are +kept fixed. Next the parameters S0 and S1 (the shape) are fit simultaneously +keeping I0, X0, and S2 fixed followed by fitting I0 and X0 while +keeping S0, S1, and S2 (the shape) fixed. If either of these fits +fails to improve the RMS then the algorithm terminates. +Also, if after the two steps (the fit of S0 and S1 followed by the fit +of I0 and X0), the RMS of the fit has not improved by more than the +user specified factor the algorithm also terminates. +.ih +INPUT +The model parameter values which are part of the MULTISPEC data structure, +the data array, the model array, the model profiles, and the profile +ranges must be initialized. Other parameters for this procedure are +input via the common in file fitgauss5.com. These include the spectra +to be fit, the parameters array (used as a working array), and the RMS +stopping factor. +.ih +OUTPUT +The returned data are the final parameter values, the model and profiles +arrays and the Y/N function value indicating if the RMS fit has been improved. +.endhelp +############################################################################## + +int procedure g5_fit2 (ms, data, model, profiles, ranges, lower, len_profile) + +pointer ms # MULTISPEC database data +real data[ARB] # Line of image pixels +real model[ARB] # Line of model pixels +real profiles[ARB] # Model profiles +real ranges[ARB] # Origins of model profiles +real lower # Profile origin +int len_profile # Length of a model profile + +int improved, fit +real rms, rms_old +pointer sp, fitparams + +int g5_fit() +real armsrr() + +include "fitgauss5.com" + +begin + # Calculate the initial RMS. The parameter values are only changed + # if the new RMS is less than this value. + rms = armsrr (data, model, MS_LEN(ms, 1)) + call g5_prnt3 (rms) + + # Allocate the fitparams array. + call smark (sp) + call salloc (fitparams, MS_NSPECTRA(ms) * MS_NGAUSS5, TY_REAL) + + # Fit the parameters I0, X0, and S0. + parameters[I0_INDEX] = YES + parameters[X0_INDEX] = YES + parameters[S0_INDEX] = YES + parameters[S1_INDEX] = NO + parameters[S2_INDEX] = NO + call set_fitparams (spectra, parameters, MS_NSPECTRA(ms), + MS_NGAUSS5, Memr[fitparams]) + + # Call the fitting procedure to minimze the RMS. + improved = g5_fit (ms, data, model, profiles, ranges, + Memr[fitparams], lower, len_profile, rms) + + # Two step fitting algorithm consisting of a fit to S0 and S1 followed + # by a fit to I0 and X0. This loop terminates when either one + # of the fits fails to improve the RMS or the RMS has improved + # by less than factor after the second step (the I0, X0 fit). + repeat { + rms_old = rms + + # Fit S0 and S1. + parameters[I0_INDEX] = NO + parameters[X0_INDEX] = NO + parameters[S0_INDEX] = YES + parameters[S1_INDEX] = YES + call set_fitparams (spectra, parameters, MS_NSPECTRA(ms), + MS_NGAUSS5, Memr[fitparams]) + fit = g5_fit (ms, data, model, profiles, ranges, + Memr[fitparams], lower, len_profile, rms) + if (fit == NO) + break + improved = YES + + # Fit I0 and X0. + parameters[I0_INDEX] = YES + parameters[X0_INDEX] = YES + parameters[S0_INDEX] = NO + parameters[S1_INDEX] = NO + call set_fitparams (spectra, parameters, MS_NSPECTRA(ms), + MS_NGAUSS5, Memr[fitparams]) + fit = g5_fit (ms, data, model, profiles, ranges, + Memr[fitparams], lower, len_profile, rms) + if (fit == NO) + break + + if (rms > (1 - factor) * rms_old) + break + } + + call sfree (sp) + return (improved) +end + + +############################################################################## +.helpsys g5fit Jul84 MULTISPEC +.ih +NAME +G5_FIT -- Basic parameter fitting procedure. +.ih +INPUT +The input data are the data array to be fit and the initial model +parameters (part of the MULTISPEC data structure), the model array +and model profiles (with the profile ranges array) corresponding to the +initial model parameters, and the RMS of the model relative to the data. +The parameters to be fit are selected by the fitparams array. +Parameters controlling the fitting process are input to this procedure +via the common block in the include file fitgauss5.com. These parameters are +the RMS stopping factor and parameters controlling the smoothing of the +shape parameters. +.ih +OUTPUT +The returned data are the final parameter values, the model and profiles +arrays and the Y/N function value indicating if the RMS fit has been improved. +.ih +DESCRIPTION +The best RMS fit is obtained by iteration. Correction vectors for the +parameters being fit are obtained by the simultaneous banded matrix +method in the procedure solve. Heuristic constraints and smoothing +are applied to the solution and then the RMS of the new fit to the +data is calculated. New parameter corrections are computed until the RMS of +the fit fails to improve by the specified factor. +.endhelp +############################################################################ + +int procedure g5_fit (ms, data, model, profiles, ranges, fitparams, lower, + len_profile, rms) + +pointer ms # MULTISPEC data structure +int fitparams[ARB] # Model parameters to be fit +real data[ARB] # Data line to be fit +real model[ARB] # Model line +real profiles[ARB] # Model profiles +real ranges[ARB] # Profile ranges +real lower # Lower limit of profiles +int len_profile # Length of profiles +real rms # RMS of fit + +int improved +int len_line, nspectra, nparams +real rms_next, rnorm +pointer sp, last_i0, last_x0, last_s0, last_s1, last_s2 +pointer solution, sol_i0, sol_x0, sol_s0, sol_s1, sol_s2 + +real armsrr() + +include "fitgauss5.com" + +begin + # Set array lengths. + len_line = MS_LEN(ms, 1) + nspectra = MS_NSPECTRA(ms) + nparams = MS_NGAUSS5 + + # Allocate working memory to temporarily save the previous parameter + # values and to hold the correction vector. + call smark (sp) + call salloc (last_i0, nspectra, TY_REAL) + call salloc (last_x0, nspectra, TY_REAL) + call salloc (last_s0, nspectra, TY_REAL) + call salloc (last_s1, nspectra, TY_REAL) + call salloc (last_s2, nspectra, TY_REAL) + call salloc (solution, nspectra * nparams, TY_REAL) + + # Offsets in the solution array for the various parameters. + sol_i0 = solution + (I0_INDEX - 1) * nspectra + sol_x0 = solution + (X0_INDEX - 1) * nspectra + sol_s0 = solution + (S0_INDEX - 1) * nspectra + sol_s1 = solution + (S1_INDEX - 1) * nspectra + sol_s2 = solution + (S2_INDEX - 1) * nspectra + + improved = NO + repeat { + # Store the last parameter values so that if the parameter values + # determined in the next iteration yield a poorer RMS fit to + # the data the best fit parameter values can be recovered. + + call amovr (PARAMETER(ms,I0,1), Memr[last_i0], nspectra) + call amovr (PARAMETER(ms,X0,1), Memr[last_x0], nspectra) + call amovr (PARAMETER(ms,S0,1), Memr[last_s0], nspectra) + call amovr (PARAMETER(ms,S1,1), Memr[last_s1], nspectra) + call amovr (PARAMETER(ms,S2,1), Memr[last_s2], nspectra) + + # Determine a correction solution vector for the selected + # parameters simultaneously, apply heuristic constraints to the + # solution vector, apply the correction vector to the parameter + # values, and smooth the shape parameters if requested. + + # Find a least squares correction vector. + call solve (ms, data, model, fitparams, profiles, ranges, + len_line, len_profile, nspectra, nparams, Memr[solution], rnorm) + + # Apply constraints to the correction vector. + call constrain_gauss5 (ms, Memr[solution], nspectra, nparams) + + # Add the correction vector to the parameter vector. + call aaddr (PARAMETER(ms,I0,1), Memr[sol_i0], PARAMETER(ms,I0,1), + nspectra) + call aaddr (PARAMETER(ms,X0,1), Memr[sol_x0], PARAMETER(ms,X0,1), + nspectra) + call aaddr (PARAMETER(ms,S0,1), Memr[sol_s0], PARAMETER(ms,S0,1), + nspectra) + call aaddr (PARAMETER(ms,S1,1), Memr[sol_s1], PARAMETER(ms,S1,1), + nspectra) + call aaddr (PARAMETER(ms,S2,1), Memr[sol_s2], PARAMETER(ms,S2,1), + nspectra) + + # Smooth the shape parameters. + if (smooth[S0_INDEX] == YES) + call ms_smooth (PARAMETER(ms, X0, 1), PARAMETER(ms, S0, 1)) + if (smooth[S1_INDEX] == YES) + call ms_smooth (PARAMETER(ms, X0, 1), PARAMETER(ms, S1, 1)) + if (smooth[S2_INDEX] == YES) + call ms_smooth (PARAMETER(ms, X0, 1), PARAMETER(ms, S2, 1)) + + # Calculate new model profiles and new model data line. + # Determine the RMS fit of the new model to the data. + # If the change in the RMS is less than factor times the + # previous RMS the interation is terminated else the improvement + # in the RMS is recorded and the next iteration is begun. + + # Set new model profiles. + call mod_gauss5 (ms, lower, profiles, ranges, len_profile, nspectra) + + # Set new model line from the profiles. + call set_model (ms, model, profiles, ranges, len_line, + len_profile, nspectra) + + # Calculate the RMS of the new model. + rms_next = armsrr (data, model, len_line) + + # Check to see if the RMS is improved enough to continue iteration. + if ((rms - rms_next) < factor * rms) { + + # The RMS has not improved enough to continue iteration. + + if (rms_next < rms) { + # Keep the latest parameter values, profiles, and model + # because the new RMS is lower than the previous RMS. + # Record the improvement. + rms = rms_next + improved = YES + call g5_prnt3 (rms) + + } else { + # Restore the parameter values, profiles, and model to + # previous values because the new RMS is higher. + call amovr (Memr[last_i0], PARAMETER(ms,I0,1), nspectra) + call amovr (Memr[last_x0], PARAMETER(ms,X0,1), nspectra) + call amovr (Memr[last_s0], PARAMETER(ms,S0,1), nspectra) + call amovr (Memr[last_s1], PARAMETER(ms,S1,1), nspectra) + call amovr (Memr[last_s2], PARAMETER(ms,S2,1), nspectra) + call mod_gauss5 (ms, lower, profiles, ranges, len_profile, + nspectra) + call set_model (ms, model, profiles, ranges, len_line, + len_profile, nspectra) + } + + # Exit the iteration loop. + break + + } else { + + # The RMS has improved significantly. Record the improvement + # and continue the iteration loop. + + rms = rms_next + improved = YES + call g5_prnt3 (rms) + } + } + + call sfree (sp) + return (improved) +end + + +# G5_SET_VERBOSE -- Output procedures for verbose mode. + +procedure g5_set_verbose (verbose) + +bool verbose +bool flag + +# entry g5_prnt1 (image, naverage, track, start) +char image[1] +int naverage +bool track +int start + +# entry g5_prnt2 (line, data, len_data) +int line, len_data +real data[1] +real rms, data_rms + +real armsr() +include "fitgauss5.com" + +begin + # Toggle verbose output. + flag = verbose + if (flag) + call fseti (STDOUT, F_FLUSHNL, YES) + else + call fseti (STDOUT, F_FLUSHNL, NO) + return + +entry g5_prnt1 (image, naverage, track, start) + + # Print the values of the various task parameters. + + if (!flag) + return + + call printf ("\nMULTISPEC Model Fitting Program\n\n") + call printf ("Image file being modeled is %s.\n") + call pargstr (image) + call printf ("Average %d lines of the image.\n") + call pargi (naverage) + call printf ("Fitting algorithm %d.\n") + call pargi (algorithm) + if (algorithm == 1) { + if (parameters[I0_INDEX] == YES) + call printf ("Fit intensity scales.\n") + if (parameters[X0_INDEX] == YES) + call printf ("Fit spectra positions.\n") + if (parameters[S0_INDEX] == YES) + call printf ("Fit spectra widths.\n") + if (parameters[S1_INDEX] == YES) + call printf ("Fit model parameter s1.\n") + if (parameters[S2_INDEX] == YES) + call printf ("Fit model parameter s2.\n") + } + if (track) { + call printf ("Track model from line %d.\n") + call pargi (start) + } + call printf ( + "Iterate model until the fit RMS decreases by less than %g %%.\n\n") + call pargr (factor * 100) + + return + +entry g5_prnt2 (line, data, len_data) + + # Print the image line being fit and the data RMS. + if (flag) { + call printf ("Fit line %d:\n") + call pargi (line) + data_rms = armsr (data, len_data) + call printf (" Data RMS = %g\n") + call pargr (data_rms) + } + return + +entry g5_prnt3 (rms) + + # Print the RMS of the fit and the ratio to the data RMS. + if (flag) { + call printf (" Fit RMS = %g Fit RMS / Data RMS = %g\n") + call pargr (rms) + call pargr (rms / data_rms) + } +end diff --git a/noao/twodspec/multispec/fitsmooth.x b/noao/twodspec/multispec/fitsmooth.x new file mode 100644 index 00000000..413f3c46 --- /dev/null +++ b/noao/twodspec/multispec/fitsmooth.x @@ -0,0 +1,168 @@ + +# FIT_SMOOTH -- Least-squares fit of smoothed profiles to data profiles with +# cleaning of deviant pixels. +# +# The profile fitting and cleaning are combined in order to minimize +# the calculations in re-evaluating the least-squares fit after rejecting +# deviant pixels. +# +# The sigma used for rejection is calculated from the sigma of the fit +# before rejecting any pixels. Pixels whose residuals exceed +# +/- sigma_cut * sigma are rejected. The maximum number of pixels to be +# replaced in each spectrum is max_replace. If max_replace is zero then +# only the model fitting is performed. +# +# The output of this routine are the cleaned data profiles and the least-square +# fitted model profiles. The number of pixels replaced is returned. + + +procedure fit_smooth (line, data, model, profiles, len_prof, nspectra, nlines) + +int line # Image line of data +real data[len_prof, nspectra] # Data profiles +real model[len_prof, nspectra] # Model profiles +real profiles[len_prof, nspectra, ARB] # Work array for SMOOTH profiles +int len_prof # Length of profile +int nspectra # Number of spectra +int nlines # Number of lines profiles + +int max_replace # Maximum number of bad pixels +real sigma_cut # Sigma cutoff on the residuals + +int i, spectrum +int nmax, ntotal, nreplace, nreject, nindef, nsigma +real sum1, sum2, scale, sigma +real lower, upper, residual, resid_min, resid_max +pointer sp, a, b, c + +begin + # Allocate working memory. + call smark (sp) + call salloc (a, nspectra, TY_REAL) + call salloc (b, nspectra, TY_REAL) + call salloc (c, nspectra, TY_INT) + + # Fit each spectrum and compute sigma of fit. + sigma = 0. + nsigma = 0 + do spectrum = 1, nspectra { + # Accumulate least squares sums. + sum1 = 0. + sum2 = 0. + nindef = 0 + do i = 1, len_prof { + if (IS_INDEFR (data[i, spectrum])) + nindef = nindef + 1 + else if (model[i, spectrum] > 0.) { + sum1 = sum1 + data[i, spectrum] * model[i, spectrum] + sum2 = sum2 + model[i, spectrum] * model[i, spectrum] + } + } + + # Compute sigma if cleanning is desired. + if (nmax != 0) { + scale = sum1 / sum2 + do i = 1, len_prof { + if (!IS_INDEFR (data[i, spectrum]) && + (model[i, spectrum] > 0.)) { + sigma = sigma + + (data[i,spectrum] - scale * model[i,spectrum]) ** 2 + nsigma = nsigma + 1 + } + } + } + + Memr[a + spectrum - 1] = sum1 + Memr[b + spectrum - 1] = sum2 + Memi[c + spectrum - 1] = nindef + } + sigma = sqrt (sigma / nsigma) + + # Reject deviant pixels from the fit, scale the model to data, + # and replace rejected and INDEFR pixels with model values. + ntotal = 0 + do spectrum = 1, nspectra { + sum1 = Memr[a + spectrum - 1] + sum2 = Memr[b + spectrum - 1] + nindef = Memi[c + spectrum - 1] + + # If there are no model data points go to the next spectrum. + if (sum2 == 0.) + next + + # Reject pixels if desired. + nreplace = 0 + if (nmax != 0) { + # Compare each pixel in the profile against the model and set + # deviant pixels to INDEFR. If the number of pixels to be + # replaced is equal to the maximum allowed or the number of + # pixels rejected equals the entire profile or the number of + # deviant pixels is zero in an iteration stop cleaning and + # exit the loop. Ignore INDEFR pixels. + + repeat { + nreject = 0 + scale = sum1 / sum2 + resid_min = -lower * sigma + resid_max = upper * sigma + do i = 1, len_prof { + if (IS_INDEFR (data[i, spectrum])) + next + + # Compute the residual and remove point if it exceeds + # the residual limits. + + residual = data[i,spectrum] - scale * model[i,spectrum] + if ((residual < resid_min) || (residual > resid_max)) { + # Remove point from the least squares fit + # and flag the deviant pixel with INDEFR. + sum1 = sum1 - data[i,spectrum] * model[i,spectrum] + sum2 = sum2 - model[i,spectrum] * model[i,spectrum] + data[i,spectrum] = INDEFR + nreplace = nreplace + 1 + nreject = nreject + 1 + } + if (nreplace == nmax) + break + } + } until ((nreplace == nmax) || (nreject == 0) || (sum2 == 0.)) + } + + # If there are good pixels remaining scale the model to the + # data profile. + if (sum2 > 0.) + call amulkr (model[1, spectrum], sum1 / sum2, + model[1, spectrum], len_prof) + + # Replace bad pixels by the model values. + if ((nindef > 0) || (nreplace > 0)) { + do i = 1, len_prof { + if (IS_INDEFR (data[i, spectrum])) + data[i, spectrum] = model[i, spectrum] + } + ntotal = ntotal + nreplace + } + } + + # Print the number of pixel replaced. + call ex_prnt3 (ntotal) + + # Replace the cleaned data profiles in future SMOOTH profiles. + if (ntotal > 0) + call update_smooth (line, data, profiles, len_prof, nspectra, + nlines) + + # Free allocated memory. + call sfree (sp) + + return + +# SET_FIT_SMOOTH -- Set the cleaning parameters. + +entry set_fit_smooth (max_replace, sigma_cut) + + nmax = max_replace + lower = sigma_cut + upper = sigma_cut + return +end diff --git a/noao/twodspec/multispec/history.x b/noao/twodspec/multispec/history.x new file mode 100644 index 00000000..9c79965b --- /dev/null +++ b/noao/twodspec/multispec/history.x @@ -0,0 +1,29 @@ +include <time.h> +include "ms.h" + +# HISTORY - Add a dated comment string to the MULTISPEC database. + +procedure history (ms, comment) + +pointer ms +char comment[ARB] + +char time_string[SZ_TIME] + +long clktime() + +begin + # Get the clock time and convert to a date string. + call cnvdate (clktime(0), time_string, SZ_TIME) + + # Append the following to the comment block: + # (date string)(: )(comment string)(newline) + + call strcat (time_string, COMMENT(ms,1), SZ_MS_COMMENTS) + call strcat (": ", COMMENT(ms,1), SZ_MS_COMMENTS) + call strcat (comment, COMMENT(ms,1), SZ_MS_COMMENTS) + call strcat ("\n", COMMENT(ms,1), SZ_MS_COMMENTS) + + # Write the updated comment block to the database. + call mspcomments (ms) +end diff --git a/noao/twodspec/multispec/intgauss5.x b/noao/twodspec/multispec/intgauss5.x new file mode 100644 index 00000000..20118802 --- /dev/null +++ b/noao/twodspec/multispec/intgauss5.x @@ -0,0 +1,140 @@ +include "ms.h" + +# INT_GAUSS5 -- Interpolate the GAUSS5 profiles between sample lines. +# +# Because calculation of the model profiles from parameter values interpolated +# from the sample lines is very slow the profiles at the sample lines are +# calculated (only when needed) and the profiles are then interpolated. + +procedure int_gauss5 (ms, lower, profiles, ranges, len_profile, nspectra, + nparams, line) + +pointer ms # MULTISPEC data structure +real lower # Lower limit of profiles rel. to center +real profiles[len_profile, nspectra, nparams, 3] # Model profiles +real ranges[nspectra, LEN_RANGES, 3] # Range array for profiles +int len_profile # Length of each profile +int nspectra # Number of spectra +int nparams # Number of parameters +int line # Image line to be interpolated to + +real f, x +int i, a, b, line1, line2 + +real cveval() + +begin + # The values of the static variables are used in successive calls + # to record the state of the interpolation endpoints. To initialize + # this routine the value of the first element of the ranges array + # is checked for the flag INDEFR. The profiles array must be + # dimensioned to have three sets of profiles (each set consisting + # of nspectra * nparams profiles). The first set is the interpolated + # profiles, profiles[*,*,*,1], and the other two sets hold the + # latest profiles from the interpolation endpoint sample lines, + # profiles[*,*,*,2] and profiles[*,*,*,3]. + + # If there is only one sample line then calculate the profiles + # only once (when the ranges array has been flagged) and return + # the same profiles for every image line. + if (MS_NSAMPLES(ms) == 1) { + if (IS_INDEFR (ranges[1,1,1])) { + call msggauss5 (ms, line1) + call mod_gauss5 (ms, lower, profiles, ranges, len_profile, + nspectra) + } + return + } + + # If there is more than one sample line then interpolation makes + # sense. Initialize the interpolation algorithm if the ranges array + # has been flagged. + + if (IS_INDEFR (ranges[1,1,1])) { + call msgparam (ms, I0, 1) + call msgparam (ms, X0, 1) + call msgfits (ms, X0_FIT) + a = 1 + line1 = 0 + line2 = 0 + } + + # Find the nearest sample line which is less than the desired + # image line and is not the last sample line and mark this as + # endpoint sample line a. Start from the last endpoint for efficiency. + # Search forward if the desired image line is greater than the + # endpoint sample line and backwards otherwise. + + if (line > LINE(ms, a)) { + do i = a + 1, MS_NSAMPLES(ms) - 1 { + if (line > LINE(ms, i)) + a = i + else + break + } + } else { + do i = a, 1, -1 { + if (line <= LINE(ms, a)) + a = i + else + break + } + } + + # Since endpoint a is not allowed to be the last sample line then + # the upper interpolation endpoint is the next sample line. + b = a + 1 + + # Check to see if the new endpoints are different than the previous + # endpoints. If so then read the model parameters from the database + # for the endpoints and evaluate the model profiles. + if ((line1 == a) && (line2 == b)) + ; # Endpoints are the same. + else if ((line1 == b) && (line2 == a)) + ; # Endpoints are the same. + else if ((line1 == a) && (line2 != b)) { + line2 = b # One endpoint is different. + call msggauss5 (ms, line2) + call mod_gauss5 (ms, lower, profiles[1,1,1,3], ranges[1,1,3], + len_profile, nspectra) + } else if ((line1 == b) && (line2 != a)) { + line2 = a # One endpoint is different. + call msggauss5 (ms, line2) + call mod_gauss5 (ms, lower, profiles[1,1,1,3], ranges[1,1,3], + len_profile, nspectra) + } else if ((line1 != b) && (line2 == a)) { + line1 = b # One endpoint is different. + call msggauss5 (ms, line1) + call mod_gauss5 (ms, lower, profiles[1,1,1,2], ranges[1,1,2], + len_profile, nspectra) + } else if ((line1 != a) && (line2 == b)) { + line1 = a # One endpoint is different. + call msggauss5 (ms, line1) + call mod_gauss5 (ms, lower, profiles[1,1,1,2], ranges[1,1,2], + len_profile, nspectra) + } else { + line1 = a # Both endpoints are different. + call msggauss5 (ms, line1) + call mod_gauss5 (ms, lower, profiles[1,1,1,2], ranges[1,1,2], + len_profile, nspectra) + line2 = b + call msggauss5 (ms, line2) + call mod_gauss5 (ms, lower, profiles[1,1,1,3], ranges[1,1,3], + len_profile, nspectra) + } + + # Calculate the ranges for the interpolated range array to the + # interpolated spectra position. + f = real (line) + do i = 1, nspectra { + x = cveval (CV(ms, X0_FIT, i), f) + ranges[i, X_START, 1] = int(x) + lower + ranges[i, DX_START, 1] = ranges[i, X_START, 1] - x + } + + # Do the profile interpolation. + f = float (line - LINE(ms, line1)) / + (LINE(ms, line2) - LINE(ms, line1)) + call profile_interpolation (f, len_profile, nspectra, nparams, + profiles, ranges) +end diff --git a/noao/twodspec/multispec/mkpkg b/noao/twodspec/multispec/mkpkg new file mode 100644 index 00000000..be03b41f --- /dev/null +++ b/noao/twodspec/multispec/mkpkg @@ -0,0 +1,66 @@ +# MULTISPEC Package. + +$call relink +$exit + +update: + $call relink + $call install + ; + +relink: + $update libpkg.a + $call multispec + ; + +install: + $move x_multispec.e noaobin$ + ; + +multispec: + $omake x_multispec.x + $set LIBS = "-lxtools -lllsq -lcurfit -ldeboor -linterp" + $link x_multispec.o libpkg.a $(LIBS) + ; + +libpkg.a: + @dbio + + armsr.x + clinput.x + exgauss5.x ms.h + exsmooth.x ms.h + exstrip.x ms.h + fitclean.x ms.h + fitgauss5.x ms.h fitgauss5.com + fitsmooth.x ms.h + history.x ms.h + intgauss5.x ms.h + modgauss5.x ms.h + msextract.x ms.h + msget.x ms.h + msio.x ms.h + msnames.x ms.h + msput.x ms.h + mssmooth.x + peaks.x + profinterp.x ms.h + ranges.x + sampline.x ms.h + setfitparams.x ms.h + setmodel.x ms.h + setranges.x ms.h + setsmooth.x ms.h + solve.x ms.h + unblend.x ms.h + msplot.x <imhdr.h> + t_findpeaks.x ms.h + t_fitfunc.x ms.h + t_fitgauss5.x ms.h fitgauss5.com + t_modellist.x ms.h + t_msextract.x ms.h + t_mslist.x ms.h + t_msset.x ms.h + t_newextract.x ms.h + t_newimage.x ms.h + ; diff --git a/noao/twodspec/multispec/modellist.par b/noao/twodspec/multispec/modellist.par new file mode 100644 index 00000000..2c622668 --- /dev/null +++ b/noao/twodspec/multispec/modellist.par @@ -0,0 +1,9 @@ +# MODELLIST + +image,f,a,,,,Image +lines,s,a,,,,Sample image lines to be listed +model,s,h,"gauss5",,,Model to be listed +columns,s,h,"*",,,Image columns to be listed +naverage,i,h,20,,,Number of image lines to average +lower,r,h,-10,,,Lower limit of model profiles +upper,r,h,10,,,Upper limit of model profiles diff --git a/noao/twodspec/multispec/modgauss5.x b/noao/twodspec/multispec/modgauss5.x new file mode 100644 index 00000000..437b1a85 --- /dev/null +++ b/noao/twodspec/multispec/modgauss5.x @@ -0,0 +1,164 @@ +include "ms.h" + +# MOD_GAUSS5 -- Set GAUSS5 model profiles and ranges. +# +# This routine can be speeded up with look up tables for a and exp(-z). + +define ZMIN 0 # Issue warning if z < ZMIN +define ZMAX 10 # The profile values are zero for z > ZMAX + +procedure mod_gauss5 (ms, lower, profiles, ranges, len_profile, nspectra) + +pointer ms # MULTISPEC data structure +real lower # Lower limit of profiles +real profiles[len_profile, nspectra, ARB] # The profiles to be set + # The third dim must be >= 5 +real ranges[nspectra, LEN_RANGES] # The ranges to be set +int len_profile # The length of each profile +int nspectra # The number of spectra + +int i, j, warn +real dx, dx2, y, z +real x1, a, s, s0, s1, s2, s3, profile +real dIdx0, dIdI0, dIds0, dIds1, dIds2 +real dydx0, dzdx0 + +begin + # First set the ranges array. + call set_ranges (ms, lower, ranges, nspectra) + + # The model quantity x1 is set to 1/4 the profile length. + # This could someday become a model parameter. + x1 = len_profile / 4 + + # For each spectrum and each point in the profile set the + # profile/derivative values for the 5 Gauss5 parameters. + + warn = YES + do i = 1, nspectra { + s0 = PARAMETER(ms, S0, i) + s1 = PARAMETER(ms, S1, i) + s2 = PARAMETER(ms, S2, i) + do j = 1, len_profile { + dx = ranges[i, DX_START] + j - 1 + dx2 = dx * dx + a = 1 / sqrt (dx2 + x1 ** 2) + y = a * dx + if (y < 0) + s3 = s2 - s1 + else + s3 = s2 + s1 + s = s0 + y * s3 + z = s * dx2 + if (z < ZMIN) { + # Issue warning only once. + if (warn == YES) { + call printf ("WARNING: mod_gauss5 error.\n") + warn = NO + } + } + if (z < ZMAX) { + profile = exp(-z) + dydx0 = -(a ** 3) * (x1 ** 2) + dzdx0 = -2 * s * dx + dydx0 * s3 * dx2 + dIdI0 = profile + dIdx0 = -dzdx0 * profile + dIds0 = -dx2 * profile + dIds1 = -dx2 * y * profile + dIds2 = dIds1 + if (y < 0) + dIds1 = -dIds1 + + profiles[j,i,I0_INDEX] = dIdI0 + profiles[j,i,X0_INDEX] = dIdx0 + profiles[j,i,S0_INDEX] = dIds0 + profiles[j,i,S1_INDEX] = dIds1 + profiles[j,i,S2_INDEX] = dIds2 + } else { + profiles[j,i,I0_INDEX] = 0. + profiles[j,i,X0_INDEX] = 0. + profiles[j,i,S0_INDEX] = 0. + profiles[j,i,S1_INDEX] = 0. + profiles[j,i,S2_INDEX] = 0. + } + } + } +end + +# CONSTRAIN_GAUSS5 -- Apply constraints to the solution vector for GAUSS5. +# +# The constraints are: +# +# DI0 > -I0/2, abs(DX0) < MAX_DX0, DS0 > -S0/2, +# (S0+DS0)+-(S1+DS1)+(S2+DS2) > 0. +# +# where DI0, DX0, DS0, DS1, DS2 are the solution corrections and I0, S0, +# S1, and S2 are the original parameter values. The constraints on DI0, +# and DS0 insure that I0 and S0 remain positive and the last constraint +# insures that (S0+-S1+S2) always remains positive so that the profiles +# always decrease from the center. + +define MAX_DX0 1. # Maximum change in position + +procedure constrain_gauss5 (ms, solution, nspectra, nparams) + +pointer ms +real solution[nspectra, nparams] +int nspectra +int nparams + +int i +real max_delta +real sa, sb, dsa, dsb, scalea, scaleb, scale + +begin + do i = 1, nspectra { + + # Limit any decrease in I0 to 1/2 I0. This insures I0 > 0. + if (solution[i, I0_INDEX] != 0.) { + max_delta = PARAMETER(ms, I0, i) / 2. + solution[i, I0_INDEX] = max (solution[i, I0_INDEX], -max_delta) + } + + # Limit the correction for X0 to MAX_DX0. + # Set the position to INDEF if it falls outside the image. + if (solution[i, X0_INDEX] != 0.) { + max_delta = MAX_DX0 + solution[i, X0_INDEX] = max (solution[i, X0_INDEX], -max_delta) + solution[i, X0_INDEX] = min (solution[i, X0_INDEX], max_delta) + } + + # Limit any decrease in S0 to 1/2 of S0. This insures S0 > 0. + if (solution[i, S0_INDEX] != 0.) { + max_delta = PARAMETER(ms, S0, i) / 2. + solution[i, S0_INDEX] = max (solution[i, S0_INDEX], -max_delta) + } + + # Limit the final S0+-S1+S2 to be positive. If the value would be + # negative scale the correction vector (ds0, ds1, ds2) to make + # the final S0+-S1+S2 be 1/2 the old value. + if ((solution[i,S0_INDEX] != 0.) || (solution[i,S1_INDEX] != 0.) || + (solution[i,S2_INDEX] != 0.)) { + sa = PARAMETER(ms, S0, i) + PARAMETER(ms, S1, i) + + PARAMETER(ms, S2, i) + sb = PARAMETER(ms, S0, i) - PARAMETER(ms, S1, i) + + PARAMETER(ms, S2, i) + dsa = solution[i, S0_INDEX] + solution[i, S1_INDEX] + + solution[i, S2_INDEX] + dsb = solution[i, S0_INDEX] - solution[i, S1_INDEX] + + solution[i, S2_INDEX] + if (sa + dsa < 0.) + scalea = -sa / 2 / dsa + else + scalea = 1. + if (sb + dsb < 0.) + scaleb = -sb / 2 / dsb + else + scaleb = 1. + scale = min (scalea, scaleb) + solution[i, S0_INDEX] = scale * solution[i, S0_INDEX] + solution[i, S1_INDEX] = scale * solution[i, S1_INDEX] + solution[i, S2_INDEX] = scale * solution[i, S2_INDEX] + } + } +end diff --git a/noao/twodspec/multispec/ms.h b/noao/twodspec/multispec/ms.h new file mode 100644 index 00000000..7343e765 --- /dev/null +++ b/noao/twodspec/multispec/ms.h @@ -0,0 +1,77 @@ + +# MULTISPEC Definitions + +define SZ_MS_IMAGE 79 # Size of image filename string +define SZ_MS_TITLE 79 # Size of the image title string +define SZ_MS_COMMENTS 1024 # Size of MULTISPEC comment block +define SZ_MS_KEY 20 # Size of the database reference strings + +define MS_DB_ENTRIES 20 # Max number of database entries +define MS_MAX_DES 1 # Max number of MULTISPEC descriptors +define MAX_RANGES 30 # Maximum range dimension. + +define MS_ERROR 1000 # General MULTISPEC error code + +# MULTISPEC I/O Descriptor + +define LEN_MS_DES 2 + MS_DB_ENTRIES + +define MS_DB Memi[$1] # DBIO descriptor +define MS_NAMES Memi[$1+1] # Pointer to database names array +define MS_DATA Memi[$1+1+$2] # Pointers to data from database + +# MULTISPEC Header stored in database. + +define LEN_MS_HDR 84 # Length of MULTISPEC Header + +define MS_IMAGE Memi[MS_DATA($1,HDR)] # Image filename +define MS_TITLE Memi[MS_DATA($1,HDR)+40] # Title from the image +define MS_NSPECTRA Memi[MS_DATA($1,HDR)+80] # Number of spectra +define MS_LEN Memi[MS_DATA($1,HDR)+($2-1)+81] # Image dimensions +define MS_NSAMPLES Memi[MS_DATA($1,HDR)+83] # Number of sample lines + +# User callable macros + +define NAME Memc[MS_NAMES($1)+($2-1)*(SZ_MS_KEY+1)] +define HEADER Memi[MS_DATA($1,HDR)] +define COMMENT Memc[MS_DATA($1,COMMENTS)+($2-1)] +define LINE Memi[MS_DATA($1,SAMPLE)+($2-1)] +define PARAMETER Memr[MS_DATA($1,$2)+($3-1)] +define CV Memi[MS_DATA($1,$2)+($3-1)] + +# Ranges + +define LEN_RANGES 2 + +define X_START 1 # Start of profile in image pixel coordinates +define DX_START 2 # Start of profile relative to spectra center + +# MULTISPEC parameter identifiers + +define HDR 1 # MULTISPEC header +define COMMENTS 2 # MULTISPEC comments +define SAMPLE 3 # Sample line array +define I0 4 # Profile scale parameter +define X0 5 # Profile position parameter +define X0_FIT 6 # Spectra position fit + +define S0 7 # GAUSS5 shape parameter +define S1 8 # GAUSS5 shape parameter +define S2 9 # GAUSS5 shape parameter +define S0_FIT 10 # GAUSS5 shape paramter fit +define S1_FIT 11 # GAUSS5 shape paramter fit +define S2_FIT 12 # GAUSS5 shape paramter fit + + +# Models +define NONE 0 # No model +define GAUSS5 1 # Five parameter Gaussian model +define SMOOTH 2 # Data profile smoothing + +# Five parameter Gaussian model -- GAUSS5 +define MS_NGAUSS5 5 # Number of GAUSS5 model parameters +define I0_INDEX 1 # Index values for parameter arrays +define X0_INDEX 2 +define S0_INDEX 3 +define S1_INDEX 4 +define S2_INDEX 5 diff --git a/noao/twodspec/multispec/msextract.par b/noao/twodspec/multispec/msextract.par new file mode 100644 index 00000000..f85081c5 --- /dev/null +++ b/noao/twodspec/multispec/msextract.par @@ -0,0 +1,20 @@ +# MSEXTRACT + +image,f,a,,,,Image to be extracted +output,f,a,,,,Output extraction image file +lower,r,h,-10,,,Lower limit of extraction +upper,r,h,10,,,Upper limit of extraction +spectra,s,h,"*",,,Spectra to be extracted +lines,s,h,"*",,,Image lines to be extracted +ex_model,b,h,no,,,Extract model spectra? +integrated,b,h,yes,,,Extract integrated spectra? +unblend,b,h,no,,,Correct spectra for blending? +clean,b,h,yes,,,Clean bad and discrepant pixels? +nreplace,i,h,1000,0,,Maximum number of pixels to be cleaned +sigma_cut,r,h,4.,,,Sigma cutoff for cleaning +niterate,i,h,1,1,,Maximum number of cleaning iterations per line +model,s,h,smooth,,,Model for cleaning and/or model extraction +naverage,i,h,20,,,Number of image lines in average profile model +fit_type,i,h,2,1,2,Model fitting type for model gauss5 +interpolator,s,h,"spline3",,,Type of image interpolation +verbose,b,h,no,,,Verbose output? diff --git a/noao/twodspec/multispec/msextract.x b/noao/twodspec/multispec/msextract.x new file mode 100644 index 00000000..e3017065 --- /dev/null +++ b/noao/twodspec/multispec/msextract.x @@ -0,0 +1,154 @@ +include <fset.h> +include <imhdr.h> +include "ms.h" + +# EX_OUT -- Write and format the extracted spectra to the output image. +# SUM_PIXELS -- Sum pixel array between the limits lower and upper. +# EX_SET_VEBOSE -- Set and print verbose output. + + +# EX_OUT -- Write and format the extracted spectra to the output image. +# +# The type of output is selected by the value of ex_integral. +# If ex_integral = yes then sum the spectra profiles and output one value +# per spectrum otherwise output the strip spectra profiles. + +procedure ex_out (im_out, line_out, spectra, lower, upper, ranges, profiles, + len_profile, nspectra, ex_integral) + +pointer im_out # Output image file descriptor +int line_out # Output line +int spectra[ARB] # Spectra range list +real lower # Lower integral limit +real upper # Upper integral limit +real ranges[nspectra, LEN_RANGES] # Starting points of profiles +real profiles[len_profile, nspectra] # Real spectra profiles +int len_profile # Length of spectra profiles +int nspectra # Number of spectra profiles +bool ex_integral + +int i, spectrum_in, spectrum_out +real x_min, x_max +pointer buf_out + +int get_next_number() +real sum_pixels() +pointer impl3r() + +begin + # Loop through the selected spectra write an image line for one. + spectrum_in = 0 + spectrum_out = 0 + while (get_next_number (spectra, spectrum_in) != EOF) { + spectrum_out = spectrum_out + 1 + buf_out = impl3r (im_out, line_out, spectrum_out) + + # Select between integrated and strip spectra output. If + # integrated spectra call sum_pixels to integrate the spectrum + # profile else output the spectrum profile. + if (ex_integral) { + x_min = lower - ranges[spectrum_in, DX_START] + 1 + x_max = upper - ranges[spectrum_in, DX_START] + 1 + Memr[buf_out] = + sum_pixels (profiles[1, spectrum_in], x_min, x_max) + } else { + do i = 1, len_profile + Memr[buf_out + i - 1] = profiles[i, spectrum_in] + } + } +end + + +# SUM_PIXELS -- Sum pixel array between the limits lower and upper. +# The limits may be partial pixels. There is no checking for out of +# array range limits. + +real procedure sum_pixels (pixels, x_min, x_max) + +real pixels[ARB] # Pixel array to be summed +real x_min # Lower limit of sum +real x_max # Upper limit of sum + +int i, i_min, i_max +real f, value + +begin + # Determine bounding integer limits. + i_min = x_min + 0.5 + i_max = x_max + 0.5 + + # Add partial pixel endpoints. + + f = min (x_max, i_min + 0.5) - x_min + value = f * pixels[i_min] + if (i_min >= i_max) + return (value) + + f = x_max - (i_max - 0.5) + value = value + f * pixels[i_max] + if (i_min + 1 > i_max - 1) + return (value) + + # Sum non-endpoint pixels. + + do i = i_min + 1, i_max - 1 + value = value + pixels[i] + + return (value) +end + +# EX_SET_VERBOSE -- Output procedures for verbose mode. + +procedure ex_set_verbose (verbose) + +bool verbose + +#entry ex_prnt1 (image_in, image_out) +char image_in[1] +char image_out[1] + +# entry ex_prnt2 (line_in, line_out) +int line_in, line_out, nreplaced + +bool flag + +begin + # Toggle verbose output. + flag = verbose + if (flag) + call fseti (STDOUT, F_FLUSHNL, YES) + else + call fseti (STDOUT, F_FLUSHNL, NO) + return + +entry ex_prnt1 (image_in, image_out) + + # Set the verbose flag and print general header information. + if (flag) { + call printf ("\nMULTISPEC Extraction Program\n\n") + call printf ("Image being extracted is %s.\n") + call pargstr (image_in) + call printf ("Output extraction image is %s.\n") + call pargstr (image_out) + } + return + +entry ex_prnt2 (line_in, line_out) + + # Print the image line being extracted. + if (flag) { + call printf ("Input image line = %d and output image line = %d.\n") + call pargi (line_in) + call pargi (line_out) + } + return + +entry ex_prnt3 (nreplaced) + + # Print the number of pixels replaced in cleaning. + if (flag && (nreplaced > 0)) { + call printf (" Number of pixels replaced: %d\n") + call pargi (nreplaced) + } + return +end diff --git a/noao/twodspec/multispec/msget.x b/noao/twodspec/multispec/msget.x new file mode 100644 index 00000000..e187015a --- /dev/null +++ b/noao/twodspec/multispec/msget.x @@ -0,0 +1,208 @@ +include <imhdr.h> +include "ms.h" + +# MSGET -- Allocate memory and get data from the MULTISPEC database +# and associated image. +# +# MSGHDR -- Allocate memory and get MULTISPEC header information. +# MSGCOMMENTS -- Allocate memory and get MULTISPEC comments. +# MSGPARAM -- Allocate memory and get a line of MULTISPEC parameter data. +# MSGSAMPLE -- Allocate memory and get SAMPLE line array. +# MSGFIT -- Get parameter fit for a spectrum. +# MSGFITS -- Get parameter fit for all spectra. +# MSGGAUSS5 -- Get a line of GAUSS5 parameter data. +# MSGIMAGE -- Get a line of the image with possible averaging. + + +# MSGHDR -- Allocate memory and get MULTISPEC header information. + +procedure msghdr (ms) + +pointer ms # MULTISPEC data structure + +int i + +int dbread() + +begin + if (MS_DATA(ms, HDR) == NULL) + call calloc (MS_DATA(ms, HDR), LEN_MS_HDR, TY_STRUCT) + i = dbread (MS_DB(ms), NAME(ms, HDR), HEADER(ms), 1) +end + +# MSGCOMMENTS -- Allocate memory and get MULTISPEC comments. + +procedure msgcomments (ms) + +pointer ms # MULTISPEC data structure + +int i + +int dbread() + +begin + if (MS_DATA(ms, COMMENTS) == NULL) + call calloc (MS_DATA(ms, COMMENTS), SZ_MS_COMMENTS, TY_CHAR) + i = dbread (MS_DB(ms), NAME(ms, COMMENTS), COMMENT(ms, 1), 1) +end + +# MSGPARAM -- Allocate memory and get a line of MULTISPEC parameter data. + +procedure msgparam (ms, parameter, line) + +pointer ms # MULTISPEC data structure +int parameter # Parameter ID +int line # Sample line to be obtained + +int i +char reference[SZ_MS_KEY] + +bool is_param_id() +int dbread() + +begin + # Check if the the requested parameter is valid. + if (!is_param_id (parameter)) + call error (MS_ERROR, "Bad parameter identifier") + + if (MS_DATA(ms, parameter) == NULL) + call calloc (MS_DATA(ms, parameter), MS_NSPECTRA(ms), TY_REAL) + + # Make reference to the desired database record. + call sprintf (reference, SZ_MS_KEY, "%s[%d]") + call pargstr (NAME(ms, parameter)) + call pargi (line) + + i = dbread (MS_DB(ms), reference, PARAMETER(ms, parameter, 1), 1) +end + +# MSGSAMPLE -- Allocate memory and get SAMPLE line array. + +procedure msgsample (ms) + +pointer ms # MULTISPEC data structure + +int i + +int dbread() + +begin + if (MS_DATA(ms, SAMPLE) == NULL) + call malloc (MS_DATA(ms, SAMPLE), MS_NSAMPLES(ms), TY_INT) + i = dbread (MS_DB(ms), NAME(ms, SAMPLE), LINE(ms,1), 1) +end + + +# MSGFIT -- Get parameter fit for a spectrum. + +procedure msgfit (ms, parameter, spectrum) + +pointer ms # MULTISPEC data structure +int parameter # Parameter ID for desired fit +int spectrum # Spectrum + +int i +char reference[SZ_MS_KEY] +pointer sp, fit + +bool is_fit_id() +int dbread() + +errchk cvrestore + +begin + # Check if for valid parameter id. + if (!is_fit_id (parameter)) + call error (MS_ERROR, "Bad fit identifier") + + # Allocate memory for the curfit pointers. + if (MS_DATA(ms, parameter) == NULL) + call malloc (MS_DATA(ms, parameter), MS_NSPECTRA(ms), TY_INT) + + # Allocate memory for the curfit coefficients. + call smark (sp) + call salloc (fit, 7 + MS_NSAMPLES(ms), TY_REAL) + + # Reference appropriate data. + call sprintf (reference, SZ_MS_KEY, "%s[%d]") + call pargstr (NAME(ms, parameter)) + call pargi (spectrum) + + i = dbread (MS_DB(ms), reference, Memr[fit], 1) + iferr (call cvrestore (CV(ms, parameter, spectrum), Memr[fit])) + ; + + call sfree (sp) +end + + +# MSGFITS -- Get parameter fits. + +procedure msgfits (ms, parameter) + +pointer ms # MULTISPEC data structure +int parameter # Parameter ID for desired fit + +int i + +begin + do i = 1, MS_NSPECTRA(ms) + call msgfit (ms, parameter, i) +end + + +# MSGGAUSS5 -- Get a line of GAUSS5 parameter data. + +procedure msggauss5 (ms, line) + +pointer ms # MULTISPEC data structure +int line # Sample line to be obtained + +begin + call msgparam (ms, I0, line) + call msgparam (ms, X0, line) + call msgparam (ms, S0, line) + call msgparam (ms, S1, line) + call msgparam (ms, S2, line) +end + + +# MSGIMAGE -- Get a line of the image with possible averaging. + +procedure msgimage (im, line, naverage, data) + +pointer im # Image descriptor +int line # Line to be gotten from the image +int naverage # Number of line to use in average +real data[ARB] # The output data array + +int i, line_start, line_end +real nlines +pointer buf + +pointer imgl2r() + +begin + # If naverage is <= 1 copy the image line to the data array + # Else average the several lines. + + if (naverage <= 1) { + call amovr (Memr[imgl2r (im, line)], data, IM_LEN(im,1)) + } else { + # Determine starting and ending lines for the average. + line_start = max (1, line - naverage / 2) + line_end = min (IM_LEN(im, 2), line_start + naverage - 1) + + # Clear data array for accumulating sum and then vector + # add the image lines. + call aclrr (data, IM_LEN(im, 1)) + do i = line_start, line_end { + buf = imgl2r (im, i) + call aaddr (Memr[buf], data, data, IM_LEN(im, 1)) + } + + # Vector divide by the number of lines to form average. + nlines = line_end - line_start + 1 + call adivkr (data, nlines, data, IM_LEN(im, 1)) + } +end diff --git a/noao/twodspec/multispec/msio.x b/noao/twodspec/multispec/msio.x new file mode 100644 index 00000000..583c2253 --- /dev/null +++ b/noao/twodspec/multispec/msio.x @@ -0,0 +1,194 @@ +include <error.h> +include <imhdr.h> +include "ms.h" + +# MSIO -- MULTISPEC interface to DBMS. +# +# MSMAP -- Map a MULTISPEC database. +# MSUNMAP -- Close MULTISPEC database and free MSIO memory allocation. +# MSGDES -- Allocate and return a MSIO descriptor. Post error recovery. +# MS_FREE_DES -- Close a database and free allocated memory. +# MS_ERROR -- Take error recovery action by closing all open databases. + + +# MSMAP -- Map a MULTISPEC database. +# +# The database name is formed by adding the extension '.db' to the image. +# +# For a new database: +# Create the database, make entries for the header and comments, +# allocate memory for the header and comments and return MSIO descriptor. +# For an existing database: +# Open the database, allocate memory and read the header, comments, and +# sample line array, and return MSIO descriptor. + +pointer procedure msmap (image, mode, max_entries) + +# Procedure msmap parameters: +char image[ARB] # Image +int mode # Access mode for database +int max_entries # Maximum number of entries + +char database[SZ_FNAME] # MULTISPEC database filename +pointer db, ms + +pointer dbopen() + +begin + # Create the database filename. + call sprintf (database, SZ_FNAME, "%s.db") + call pargstr (image) + + # Open the database with specified mode and max_entries. + db = dbopen (database, mode, max_entries) + + # Get an MSIO descriptor. + call msgdes (ms) + MS_DB(ms) = db + + if (mode == NEW_FILE) { + # For a NEW_FILE enter the header and comment records and + # call msghdr and msgcomments to allocate memory. + call dbenter (db, NAME(ms, HDR), LEN_MS_HDR * SZ_STRUCT, 1) + call dbenter (db, NAME(ms, COMMENTS), SZ_MS_COMMENTS + 1, 1) + call msghdr (ms) + call msgcomments (ms) + } else { + # For an existing database read the header, comments, and + # sample line array. + call msghdr (ms) + call msgcomments (ms) + call msgsample (ms) + } + + # Return MSIO descriptor. + return (ms) +end + + +# MSUNMAP -- Close MULTISPEC database and free MSIO memory allocation. + +procedure msunmap (ms) + +pointer ms # MSIO descriptor + +begin + call dbclose (MS_DB(ms)) + call ms_free_des (ms) +end + + +# Procedures accessing the MSIO descriptor list. +# +# MSGDES -- Allocate and return a MSIO descriptor. Post error recovery. +# MS_FREE_DES -- Close a database and free allocated memory. +# MS_ERROR -- Take error recovery action by closing all open databases. + +procedure msgdes (ms) + +pointer ms # MSIO descriptor + +int init + +extern ms_error() + +int ndes # Number of allocated MSIO descriptors +pointer msdes[MS_MAX_DES] # MSIO descriptor list + +common /msiocom/ ndes, msdes + +data init/YES/ + +begin + # Initialize and post error recovery. + if (init == YES) { + ndes = 0 + call onerror (ms_error) + init = NO + } + + # Check if requested descriptor would overflow the descriptor list. + if (ndes == MS_MAX_DES) + call error (MS_ERROR, "Attempt to open too many MULTISPEC files") + + # Allocate memory for the descriptor and enter in pointer in list. + ndes = ndes + 1 + call malloc (msdes[ndes], LEN_MS_DES, TY_STRUCT) + ms = msdes[ndes] + + # Initialize descriptor to NULL. + call amovki (NULL, Memi[ms], LEN_MS_DES) + + # Initialize the MULTISPEC database name list. + call msnames (ms) +end + +# MS_FREE_DES -- Close a database and free allocated memory. + +procedure ms_free_des (ms) + +pointer ms # MSIO descriptor to be freed + +int i, j + +int ndes # Number of allocated MSIO descriptors +pointer msdes[MS_MAX_DES] # MSIO descriptor list + +common /msiocom/ ndes, msdes + +begin + # Locate the specified descriptor in the descriptor list. + # If the descriptor is not in the list do nothing. + # If the descriptor is in the list free allocated memory and remove + # the entry from the list. + + for (i = 1; (i <= ndes) && (ms != msdes[i]); i = i + 1) + ; + if (i > ndes) + return + + call mfree (MS_DATA(ms, HDR), TY_STRUCT) + call mfree (MS_DATA(ms, COMMENTS), TY_CHAR) + call mfree (MS_DATA(ms, SAMPLE), TY_INT) + call mfree (MS_DATA(ms, I0), TY_REAL) + call mfree (MS_DATA(ms, X0), TY_REAL) + call mfree (MS_DATA(ms, S0), TY_REAL) + call mfree (MS_DATA(ms, S1), TY_REAL) + call mfree (MS_DATA(ms, S2), TY_REAL) + if (MS_DATA(ms, X0_FIT) != NULL) { + do j = 1, MS_NSPECTRA(ms) + if (CV(ms, X0_FIT, j) != NULL) + call cvfree (CV(ms, X0_FIT, j)) + call mfree (MS_DATA(ms, X0_FIT), TY_INT) + } + call mfree (ms, TY_STRUCT) + + if (i < ndes) + msdes[i] = msdes[ndes] + ndes = ndes - 1 +end + +# MS_ERROR -- Take error recovery action by closing all open databases. + +procedure ms_error (error_code) + +int error_code # Error code for error recovery + +int i, ndes1 + +int ndes # Number of allocated MSIO descriptors +pointer msdes[MS_MAX_DES] # MSIO descriptor list + +common /msiocom/ ndes, msdes + +begin + # Let DBMS deal with the database descriptor, + # fio_cleanup deal with the open files, and the system + # restart deal with freeing the stack. This procedure + # cleans up the msio descriptors and memory allocations. + # The system may eventually deal with heap memory recovery. + + ndes1 = ndes + do i = 1, ndes1 + call ms_free_des (msdes[i]) +end diff --git a/noao/twodspec/multispec/mslist.par b/noao/twodspec/multispec/mslist.par new file mode 100644 index 00000000..77f3998b --- /dev/null +++ b/noao/twodspec/multispec/mslist.par @@ -0,0 +1,7 @@ +# MSLIST + +image,f,a,,,,Image to be listted +keyword,s,a,,,,Keyword for data to be listed +lines,s,a,,,,Images lines to be listed +spectra,s,a,,,,Spectra to be listed +titles,b,h,no,,,Print additional titles? diff --git a/noao/twodspec/multispec/msnames.x b/noao/twodspec/multispec/msnames.x new file mode 100644 index 00000000..93651b18 --- /dev/null +++ b/noao/twodspec/multispec/msnames.x @@ -0,0 +1,140 @@ +include "ms.h" + +# The procedures in this file deal with the mapping of the +# database names to the MULTISPEC identifiers and relations between the +# identifiers and their meaning. +# +# MSNAMES -- Allocate memory and set name array in MULTISPEC data structure. +# MS_DB_ID -- Associate a database name to the MULTISPEC identifier. +# IS_PARAM_ID -- Test if an identifier refers to a model parameter. +# IS_FIT_ID -- Test if an identifier refers to a curfit parameter fit. +# MS_FIT_ID -- Return fit identifier for specified parameter identifier. +# MS_MODEL_ID -- CL get a model name and map to a MULTISPEC identifier. + +# MSNAMES -- Allocate memory and set the name array in MULTISPEC data structure. +# +# The name array maps the integer identifiers with the names in the +# database. The name array is also allocated if necessary. +# This is the only place where the database names are explicitly known. + +procedure msnames (ms) + +pointer ms + +begin + if (MS_NAMES(ms) == NULL) + call calloc (MS_NAMES(ms), MS_DB_ENTRIES * (SZ_MS_KEY + 1), TY_CHAR) + + # Set name array mapping the MULTISPEC IDs to the database names. + call sprintf (NAME(ms, HDR), SZ_MS_KEY, "header") + call sprintf (NAME(ms, COMMENTS), SZ_MS_KEY, "comments") + call sprintf (NAME(ms, SAMPLE), SZ_MS_KEY, "samples") + call sprintf (NAME(ms, I0), SZ_MS_KEY, "i0") + call sprintf (NAME(ms, X0), SZ_MS_KEY, "x0") + call sprintf (NAME(ms, X0_FIT), SZ_MS_KEY, "x0 fit") + call sprintf (NAME(ms, S0), SZ_MS_KEY, "s0") + call sprintf (NAME(ms, S1), SZ_MS_KEY, "s1") + call sprintf (NAME(ms, S2), SZ_MS_KEY, "s2") + call sprintf (NAME(ms, S0_FIT), SZ_MS_KEY, "s0 fit") + call sprintf (NAME(ms, S1_FIT), SZ_MS_KEY, "s1 fit") + call sprintf (NAME(ms, S2_FIT), SZ_MS_KEY, "s2 fit") +end + + +# MS_DB_ID -- Associate a database name to the MULTISPEC identifier. +# +# The input entry name is matched with a database name and the +# MULTISPEC identifier is returned. + +int procedure ms_db_id (ms, entry) + +pointer ms +char entry[ARB] + +int i + +bool streq() + +begin + do i = 1, MS_DB_ENTRIES + if (streq (entry, NAME(ms, i))) + return (i) + + return (0) +end + + +# IS_PARAM_ID -- Test if an identifier refers to a model parameter. + +bool procedure is_param_id (param_id) + +int param_id + +begin + switch (param_id) { + case X0, I0, S0, S1, S2: + return (TRUE) + default: + return (FALSE) + } +end + + +# IS_FIT_ID -- Test if an identifier refers to a parameter fit. + +bool procedure is_fit_id (fit_id) + +int fit_id + +begin + switch (fit_id) { + case X0_FIT, S0_FIT, S1_FIT, S2_FIT: + return (TRUE) + default: + return (FALSE) + } +end + + +# MS_FIT_ID -- Return fit identifier for specified parameter identifier. + +int procedure ms_fit_id (param_id) + +int param_id + +begin + switch (param_id) { + case X0: + return (X0_FIT) + case S0: + return (S0_FIT) + case S1: + return (S1_FIT) + case S2: + return (S2_FIT) + default: + return (ERR) + } +end + +# MS_MODEL_ID -- CL get a model name and map to a MULTISPEC identifier. +# +# This procedure isolates the model definitions to protect against +# changes in the model names or the order and choice of identifiers +# in ms.h. + +int procedure ms_model_id (param) + +char param[ARB] # CL parameter name +char str[SZ_LINE] +int i, clgwrd() + +begin + i = clgwrd (param, str, SZ_LINE, ",gauss5,smooth,") + switch (i) { + case 1: + return (GAUSS5) + case 2: + return (SMOOTH) + } +end diff --git a/noao/twodspec/multispec/msplot.par b/noao/twodspec/multispec/msplot.par new file mode 100644 index 00000000..013a40de --- /dev/null +++ b/noao/twodspec/multispec/msplot.par @@ -0,0 +1,9 @@ +# Parameter file for MSPLOT + +image,f,a,,,,Image to be plotted +line,i,a,,,,Image line to be plotted +naverage,i,h,20,,,Number of image lines to average +lower,r,h,-10,,,Lower limit of model profiles +upper,r,h,10,,,Upper limit of model profiles +graphics,s,h,"stdgraph",,,Graphics output device +cursor,*gcur,h,"",,,Graphics cursor input diff --git a/noao/twodspec/multispec/msplot.x b/noao/twodspec/multispec/msplot.x new file mode 100644 index 00000000..4e02367f --- /dev/null +++ b/noao/twodspec/multispec/msplot.x @@ -0,0 +1,104 @@ +include <imhdr.h> +include "ms.h" + +# MSPLOT -- Plot image and model values. +# +# The output list format is column, image line, data value, model value. +# This task differs from t_new_image primarily in that there is no profile +# interpolation. The model is evaluated only at the sample lines. It +# is used to check the results of the model fitting tasks. + +procedure msplot () + +char image[SZ_FNAME] # Image +int line # Image line to plot +int naverage # Number of image lines to average +real lower # Lower limit of profile model +real upper # Upper limit of profile model + +int sample +pointer ms, im +pointer sp, data, model + +int clgeti(), get_sample_line +real clgetr() +pointer msmap(), immap() + +begin + # Get the task parameters. + + call clgstr ("image", image, SZ_FNAME) + line = clgeti ("line") + naverage = clgeti ("naverage") + lower = clgetr ("lower") + upper = clgetr ("upper") + + # Access the database and image. + + ms = msmap (image, READ_ONLY, 0) + im = immap (image, READ_ONLY, 0) + + # Allocate memory for the data and model. + + call smark (sp) + call salloc (data, IM_LEN(im, 1), TY_REAL) + call salloc (model, IM_LEN(im, 1), TY_REAL) + + sample = get_sample_line (ms, line) + line = LINE(ms, sample) + call msgimage (im, line, naverage, Memr[data]) + call gauss5_model (ms, sample, lower, upper, Memr[model]) + + call ms_graph (Memr[data], Memr[model], IM_LEN(im, 1)) + + call sfree (sp) + call msunmap (ms) + call imunmap (im) +end + + +include <gset.h> + +# MS_GRAPH -- For the selected line get the data line and compute a model line. +# Graph the data and model values. + +procedure ms_graph (data, model, npts) + +real data[npts] # Image data +real model[npts] # Model data +int npts # Number of data points + +char str[SZ_LINE] +real x1, x2 +pointer gp, gt + +real wx, wy # Cursor position +int wcs, key # WCS and cursor key + +int gt_gcur() +pointer gopen(), gt_init() + +begin + call clgstr ("graphics", str, SZ_LINE) + gp = gopen (str, NEW_FILE, STDGRAPH) + gt = gt_init () + + x1 = 1 + x2 = npts + call gswind (gp, x1, x2, INDEF, INDEF) + call gascale (gp, data, npts, 2) + call grscale (gp, model, npts, 2) + call gt_swind (gp, gt) + call gt_labax (gp, gt) + + call gseti (gp, G_PLTYPE, 1) + call gvline (gp, data, npts, x1, x2) + call gseti (gp, G_PLTYPE, 2) + call gvline (gp, model, npts, x1, x2) + + while (gt_gcur ("cursor", wx, wy, wcs, key, str, SZ_LINE) != EOF) + ; + + call gclose (gp) + call gt_free (gt) +end diff --git a/noao/twodspec/multispec/msput.x b/noao/twodspec/multispec/msput.x new file mode 100644 index 00000000..e24e825b --- /dev/null +++ b/noao/twodspec/multispec/msput.x @@ -0,0 +1,123 @@ +include "ms.h" + +# MSPUT -- Put information in the MULTISPEC database. +# +# MSPHDR -- Put MULTISPEC header record in the database. +# MSPCOMMENTS -- Put MULTISPEC comment record into the database. +# MSPSAMPLE -- Put MULTISPEC sample record into the database. +# MSPPARAM -- Put a line of MULTISPEC parameter data. +# MSPGAUSS5 -- Put a line of GAUSS5 parameter data. +# MSPFIT -- Put fit coefficients for a spectrum. +# MSPFITS -- Put fit coefficients for all spectra. + + +# MSPHDR -- Put MULTISPEC header record in the database. + +procedure msphdr (ms) + +pointer ms # MSIO descriptor + +begin + call dbwrite (MS_DB(ms), NAME(ms, HDR), HEADER(ms), 1) +end + + +# MSPCOMMENTS -- Put MULTISPEC comment record into the database. + +procedure mspcomments (ms) + +pointer ms # MSIO descriptor + +begin + call dbwrite (MS_DB(ms), NAME(ms, COMMENTS), COMMENT(ms, 1), 1) +end + + +# MSPSAMPLE -- Put MULTISPEC sample record into the database. + +procedure mspsample (ms) + +pointer ms # MSIO descriptor + +begin + call dbwrite (MS_DB(ms), NAME(ms, SAMPLE), LINE(ms,1), 1) +end + +# MSPPARAM -- Put a line of MULTISPEC parameter data. + +procedure mspparam (ms, parameter, line) + +pointer ms # MSIO descriptor +int parameter # Index to parameter array +int line # Line to be read + +char reference[SZ_MS_KEY] + +bool is_param_id() + +begin + if (!is_param_id (parameter)) + call error (MS_ERROR, "Bad parameter identifier") + + call sprintf (reference, SZ_MS_KEY, "%s[%d]") + call pargstr (NAME(ms, parameter)) + call pargi (line) + + call dbwrite (MS_DB(ms), reference, PARAMETER(ms,parameter,1), 1) +end + + +# MSPGAUSS5 -- Put a line of GAUSS5 parameter data. + +procedure mspgauss5 (ms, line) + +pointer ms +int line + +begin + call mspparam (ms, I0, line) + call mspparam (ms, X0, line) + call mspparam (ms, S0, line) + call mspparam (ms, S1, line) + call mspparam (ms, S2, line) +end + +# MSPFIT -- Put parameter fit data. + +procedure mspfit (ms, parameter, spectrum) + +pointer ms # MSIO descriptor +int parameter # Parameter to be put +int spectrum # Spectrum to be put + +char reference[SZ_MS_KEY] +pointer sp, fit + +begin + call smark (sp) + call salloc (fit, 7 + MS_NSAMPLES(ms), TY_REAL) + + call sprintf (reference, SZ_MS_KEY, "%s[%d]") + call pargstr (NAME(ms, parameter)) + call pargi (spectrum) + + call cvsave (CV(ms, parameter, spectrum), Memr[fit]) + call dbwrite (MS_DB(ms), reference, Memr[fit], 1) + + call sfree (sp) +end + + +# MSPFITS -- Put parameter fits. + +procedure mspfits (ms, parameter) + +pointer ms # MULTISPEC data structure +int parameter # Parameter ID for desired fit + +int i + +begin + do i = 1, MS_NSPECTRA(ms) + call mspfit (ms, parameter, i) +end diff --git a/noao/twodspec/multispec/msset.par b/noao/twodspec/multispec/msset.par new file mode 100644 index 00000000..8c11c205 --- /dev/null +++ b/noao/twodspec/multispec/msset.par @@ -0,0 +1,9 @@ +# MSSET + +image,f,a,,,,Image +keyword,s,a,,,,Keyword for data to be set +value,s,a,,,,Input value +lines,s,h,"*",,,Images lines to be affected +spectra,s,h,"*",,,Spectra to be affected +read_list,b,h,no,,,Read values from a list? +list,*s,h,,,,Input list diff --git a/noao/twodspec/multispec/mssmooth.x b/noao/twodspec/multispec/mssmooth.x new file mode 100644 index 00000000..be7e01ca --- /dev/null +++ b/noao/twodspec/multispec/mssmooth.x @@ -0,0 +1,81 @@ +include <math/curfit.h> + +# MS_SMOOTH -- Smooth MULTISPEC parameters with the CURFIT package. +# MS_SET_SMOOTH -- Initialize and define function for smoothing. +# MS_FREE_SMOOTH -- Free allocated memory from smoothing. + +# This procedure is numerical and does not depend on the MULTISPEC +# package. + +procedure ms_smooth (x, y) + +real x[ARB] # Array of x values +real y[ARB] # Array of y values +int curve_type # Curfit function +int order # Order of function +real xmin # Minimum x value +real xmax # Maximum x value +int npoints # Number of points in fits + +int i, npts, ier +real xmn, xmx +pointer cv, w + +real cveval() + +data cv/NULL/, w/NULL/ + +begin + # Check for a valid curfit pointer. + if (cv == NULL) + call error (0, "param_smooth: Undefined smoothing function") + + # Zero and fit the data with uniform weights. + call cvzero (cv) + # call cvfit (cv, x, y, Memr[w], npts, WTS_UNIFORM, ier) + + # Accumulate points and check for out of bounds points. + do i = 1, npts + if ((x[i] >= xmn) && (x[i] <= xmx)) + call cvaccum (cv, x[i], y[i], Memr[w+i-1], WTS_UNIFORM) + call cvsolve (cv, ier) + + if (ier != OK) + call error (0, "param_smooth: Error in function fit") + + # Evaluate fit placing fit values back in y array. + # call cvvector (cv, x, y, npts) + do i = 1, npts + if ((x[i] >= xmn) && (x[i] <= xmx)) + y[i] = cveval (cv, x[i]) + + return + +entry ms_set_smooth (xmin, xmax, npoints) + + # Set or reset curfit data structure and allocate memory for weights. + if (cv != NULL) + call cvfree (cv) + if (w == NULL) + call malloc (w, npoints, TY_REAL) + + # Determine curve_type and order. + call clgcurfit ("function", "order", curve_type, order) + + # Initialize curfit data structure and record number of points. + xmn = xmin + xmx = xmax + call cvinit (cv, curve_type, order, xmn, xmx) + npts = npoints + + return + +entry ms_free_smooth () + + # Free allocated memory. + if (cv != NULL) + call cvfree (cv) + if (w != NULL) + call mfree (w, TY_REAL) + +end diff --git a/noao/twodspec/multispec/multispec.cl b/noao/twodspec/multispec/multispec.cl new file mode 100644 index 00000000..12229f83 --- /dev/null +++ b/noao/twodspec/multispec/multispec.cl @@ -0,0 +1,21 @@ +#{ MULTISPEC -- The MULTISPEC package. + +package multispec + +task newextraction, + findpeaks, + msset, + mslist, + fitfunction, + msextract, + newimage, + modellist, + msplot, + fitgauss5 = multispec$x_multispec.e + +# Scripts +task _msfindspec1 = multispec$_msfindspec1.cl +task _msfindspec2 = multispec$_msfindspec2.cl +task _msfindspec3 = multispec$_msfindspec3.cl + +clbye diff --git a/noao/twodspec/multispec/multispec.hd b/noao/twodspec/multispec/multispec.hd new file mode 100644 index 00000000..a798e54a --- /dev/null +++ b/noao/twodspec/multispec/multispec.hd @@ -0,0 +1,14 @@ +# Help directory for the MULTISPEC package. + +$doc = "./doc/" + +findpeaks hlp=doc$findpeaks.hlp, src=t_findpeaks.x +fitfunction hlp=doc$fitfunc.hlp, src=t_fitfunc.x +fitgauss5 hlp=doc$fitgauss5.hlp, src=t_fitgauss5.x +modellist hlp=doc$modellist.hlp, src=t_modellist.x +msextract hlp=doc$msextract.hlp, src=t_msextract.x +mslist hlp=doc$mslist.hlp, src=t_mslist.x +msplot hlp=doc$msplot.hlp, src=t_msplot.cl +msset hlp=doc$msset.hlp, src=t_msset.x +newextraction hlp=doc$newextract.hlp, src=t_newextract.x +newimage hlp=doc$newimage.hlp, src=t_newimage.x diff --git a/noao/twodspec/multispec/multispec.hlp b/noao/twodspec/multispec/multispec.hlp new file mode 100644 index 00000000..b7083fb3 --- /dev/null +++ b/noao/twodspec/multispec/multispec.hlp @@ -0,0 +1,14 @@ +.help multispec OCT85 noao.twodspec.multispec +.nf + findpeaks - Find the peaks + fitfunction - Fit a function to the spectra parameter values + fitgauss5 - Fit spectra profiles with five parameter Gaussian model + modellist - List data and model pixel values + msextract - Extract spectra + mslist - List entries in a MULTISPEC database + msplot - Plot a line of image and model data + msset - Set entries in a MULTISPEC database + newextraction - Create a new MULTISPEC extraction database + newimage - Create a new multi-spectra image +.fi +.endhelp diff --git a/noao/twodspec/multispec/multispec.men b/noao/twodspec/multispec/multispec.men new file mode 100644 index 00000000..4425164f --- /dev/null +++ b/noao/twodspec/multispec/multispec.men @@ -0,0 +1,10 @@ + findpeaks - Find the peaks + fitfunction - Fit a function to the spectra parameter values + fitgauss5 - Fit spectra profiles with five parameter Gaussian model + modellist - List data and model pixel values + msextract - Extract spectra + mslist - List entries in a MULTISPEC database + msplot - Plot a line of image and model data + msset - Set entries in a MULTISPEC database + newextraction - Create a new MULTISPEC extraction database + newimage - Create a new multi-spectra image diff --git a/noao/twodspec/multispec/multispec.par b/noao/twodspec/multispec/multispec.par new file mode 100644 index 00000000..ce7cb587 --- /dev/null +++ b/noao/twodspec/multispec/multispec.par @@ -0,0 +1,3 @@ +# MULTISPEC Package parameter file. + +version,s,h,"October 1984" diff --git a/noao/twodspec/multispec/newextraction.par b/noao/twodspec/multispec/newextraction.par new file mode 100644 index 00000000..17a0bda5 --- /dev/null +++ b/noao/twodspec/multispec/newextraction.par @@ -0,0 +1,5 @@ +# NEWEXTRACTION + +image,f,a,,,,Image to be extracted +template,f,a,"",,,Template image to use for initialization +sample_lines,s,h,"10x50",,,Sample image lines diff --git a/noao/twodspec/multispec/newimage.par b/noao/twodspec/multispec/newimage.par new file mode 100644 index 00000000..24465786 --- /dev/null +++ b/noao/twodspec/multispec/newimage.par @@ -0,0 +1,17 @@ +# NEWIMAGE + +image,f,a,,,,Image to be used as a model +outpu,f,a,,,,Output image to be created +lower,r,h,-10,,,Lower limit of extraction +upper,r,h,10,,,Upper limit of extraction +lines,s,h,"*",,,Image lines to be extracted +ex_model,b,h,no,,,Extract model spectra? +clean,b,h,yes,,,Clean bad and discrepant pixels? +nreplace,i,h,1000,0,,Maximum number of pixels to be cleaned +sigma_cut,r,h,4.,,,Sigma cutoff for cleaning +niterate,i,h,1,1,,Maximum number of cleaning iterations per line +model,s,h,smooth,,,Model for cleaning and/or model extraction +naverage,i,h,20,,,Number of image lines in average profile model +fit_type,i,h,2,1,2,Model fitting type for model gauss5 +interpolator,s,h,"spline3",,,Type of image interpolation +verbose,b,h,no,,,Verbose output? diff --git a/noao/twodspec/multispec/peaks.x b/noao/twodspec/multispec/peaks.x new file mode 100644 index 00000000..910e66a5 --- /dev/null +++ b/noao/twodspec/multispec/peaks.x @@ -0,0 +1,397 @@ +# PEAKS -- The following procedures are general numerical functions +# dealing with finding peaks in a data array. +# +# FIND_PEAKS Find the peaks in the data array. +# FIND_LOCAL_MAXIMA Find the local maxima in the data array. +# IS_LOCAL_MAX Test a point to determine if it is a local maximum. +# FIND_THRESHOLD Find the peaks with positions satisfying threshold +# and contrast constraints. +# FIND_ISOLATED Flag peaks which are within separation of a peak +# with a higher peak value. +# FIND_NMAX Select up to the nmax highest ranked peaks. +# COMPARE Compare procedure for sort used in FIND_PEAKS. + +# FIND_PEAKS -- Find the peaks in the data array. +# +# The peaks are found using the following algorithm: +# +# 1. Find the local maxima. +# 2. Reject peaks below the threshold. +# 3. Determine the ranks of the remaining peaks. +# 4. Flag weaker peaks within separation of a stronger peak. +# 5. Accept at most the nmax strongest peaks. +# +# Indefinite points are ignored. The peak positions are returned in the +# array x. + +int procedure find_peaks (data, x, npoints, contrast, separation, edge, nmax, + threshold, debug) + +# Procedure parameters: +real data[npoints] # Input data array +real x[npoints] # Output peak position array +int npoints # Number of data points +real contrast # Maximum contrast between strongest and weakest +int separation # Minimum separation between peaks +int edge # Minimum distance from the edge +int nmax # Maximum number of peaks to be returned +real threshold # Minimum threshold level for peaks +bool debug # Print diagnostic information? + +int i, j +int nlmax, nthreshold, nisolated, npeaks +pointer sp, y, rank + +int find_local_maxima(), find_threshold(), find_isolated(), find_nmax() +int compare() + +extern compare() + +common /sort/ y + +begin + # Find the local maxima in data and put column positions in x.. + nlmax = find_local_maxima (data, x, npoints, debug) + + # Reject local maxima near the edge. + if (edge > 0) { + j = 0 + do i = 1, nlmax { + if ((x[i] > edge) && (x[i] <= npoints - edge)) { + j = j + 1 + x[j] = x[i] + } + } + nlmax = j + } + + # Allocate a working array y. + call smark (sp) + call salloc (y, npoints, TY_REAL) + + # Reject the local maxima which do not satisfy the thresholds. + # The array y is set to the peak values of the remaining peaks. + nthreshold = find_threshold (data, x, Memr[y], nlmax, + contrast, threshold, debug) + + # Rank the peaks by peak value. + call salloc (rank, nthreshold, TY_INT) + do i = 1, nthreshold + Memi[rank + i - 1] = i + call qsort (Memi[rank], nthreshold, compare) + + # Reject the weaker peaks within sep of a stronger peak. + nisolated = find_isolated (x, Memi[rank], nthreshold, separation, + debug) + + # Select the strongest nmax peaks. + npeaks = find_nmax (data, x, Memi[rank], nthreshold, nmax, debug) + + call sfree (sp) + return (npeaks) +end + + +# FIND_LOCAL_MAXIMA -- Find the local maxima in the data array. +# +# A data array is input and the local maxima positions array is output. +# The number of local maxima found is returned. + +int procedure find_local_maxima (data, x, npoints, debug) + +real data[npoints] # Input data array +real x[npoints] # Output local maxima positions array +int npoints # Number of input points +bool debug # Print debugging information? + +int i, nlmax + +bool is_local_max() + +begin + nlmax = 0 + do i = 1, npoints { + if (is_local_max (i, data, npoints)) { + nlmax = nlmax + 1 + x[nlmax] = i + } + } + + if (debug) { + call printf (" Number of local maxima found = %d.\n") + call pargi (nlmax) + } + + return (nlmax) +end + + +# IS_LOCAL_MAX -- Test a point to determine if it is a local maximum. +# +# Indefinite points are ignored. + +bool procedure is_local_max (index, data, npoints) + +# Procedure parameters: +int index # Index to test for local maximum +real data[npoints] # Data values +int npoints # Number of points in the data vector + +int i, j, nright, nleft + +begin + # INDEFR points cannot be local maxima. + if (IS_INDEFR (data[index])) + return (false) + + # Find the left and right indices where data values change and the + # number of points with the same value. Ignore INDEFR points. + nleft = 0 + for (i = index - 1; i >= 1; i = i - 1) { + if (!IS_INDEFR (data[i])) { + if (data[i] != data[index]) + break + nleft = nleft + 1 + } + } + nright = 0 + for (j = index + 1; i <= npoints; j = j + 1) { + if (!IS_INDEFR (data[j])) { + if (data[j] != data[index]) + break + nright = nright + 1 + } + } + + # Test for failure to be a local maxima + if ((i == 0) && (j == npoints)) { + return (FALSE) # Data is constant + } else if (i == 0) { + if (data[j] > data[index]) + return (FALSE) # Data increases to right + } else if (j == npoints) { + if (data[i] > data[index]) # Data increase to left + return (FALSE) + } else if ((data[i] > data[index]) || (data[j] > data[index])) { + return (FALSE) # Not a local maximum + } else if (!((nleft - nright == 0) || (nleft - nright == 1))) { + return (FALSE) # Not center of plateau + } + + # Point is a local maxima + return (TRUE) +end + + + + +# FIND_THRESHOLD -- Find the peaks with positions satisfying threshold +# and contrast constraints. +# +# The input is the data array, data, and the peak positions array, x. +# The x array is resorted to the nthreshold peaks satisfying the constraints. +# The corresponding nthreshold data values are returned the y array. +# The number of peaks satisfying the constraints (nthreshold) is returned. + +int procedure find_threshold (data, x, y, npoints, contrast, threshold, debug) + +real data[ARB] # Input data values +real x[npoints] # Input/Output peak positions +real y[npoints] # Output peak data values +int npoints # Number of peaks input +real contrast # Contrast constraint +real threshold # Threshold constraint +bool debug # Print debugging information? + +int i, j, nthreshold +real minval, maxval, lcut + +begin + # Set the y array to be the values at the peak positions. + do i = 1, npoints { + j = x[i] + y[i] = data[j] + } + + # Determine the min and max values of the peaks. + call alimr (y, npoints, minval, maxval) + + # Set the threshold based on the max of the absolute threshold and the + # contrast. Use arltr to set peaks below threshold to INDEFR. + lcut = max (threshold, contrast * maxval) + call arltr (y, npoints, lcut, INDEFR) + + if (debug) { + call printf (" Highest peak value = %g.\n") + call pargr (maxval) + call printf (" Peak cutoff threshold = %g.\n") + call pargr (lcut) + do i = 1, npoints { + if (IS_INDEFR (y[i])) { + j = x[i] + call printf ( + " Peak at column %d with value %g below threshold.\n") + call pargi (j) + call pargr (data[j]) + } + } + } + + # Determine the number of acceptable peaks & resort the x and y arrays. + nthreshold = 0 + do i = 1, npoints { + if (IS_INDEFR (y[i])) + next + nthreshold = nthreshold + 1 + x[nthreshold] = x[i] + y[nthreshold] = y[i] + } + + if (debug) { + call printf (" Number of peaks above the threshold = %d.\n") + call pargi (nthreshold) + } + + return (nthreshold) +end + +# FIND_ISOLATED -- Flag peaks which are within separation of a peak +# with a higher peak value. +# +# The peak positions, x, and their ranks, rank, are input. +# The rank array contains the indices of the peak positions in order from +# the highest peak value to the lowest peak value. Starting with +# highest rank (rank[1]) all peaks of lower rank within separation +# are marked by setting their positions to INDEFR. The number of +# unflaged peaks is returned. + +int procedure find_isolated (x, rank, npoints, separation, debug) + +# Procedure parameters: +real x[npoints] # Positions of points +int rank[npoints] # Rank of peaks +int npoints # Number of peaks +int separation # Minimum allowed separation +bool debug # Print diagnostic information + +int i, j +int nisolated + +begin + # Eliminate close neighbors. The eliminated + # peaks are marked by setting their positions to INDEFR. + nisolated = 0 + do i = 1, npoints { + if (IS_INDEFR (x[rank[i]])) + next + nisolated = nisolated + 1 + do j = i + 1, npoints { + if (IS_INDEFR (x[rank[j]])) + next + if (abs (x[rank[i]] - x[rank[j]]) < separation) { + if (debug) { + call printf ( + " Peak at column %d too near peak at column %d.\n") + call pargi (int (x[rank[j]])) + call pargi (int (x[rank[i]])) + } + x[rank[j]] = INDEFR + } + } + } + + if (debug) { + call printf (" Number of peaks separated by %d pixels = %d.\n") + call pargi (separation) + call pargi (nisolated) + } + + # Return number of isolated peaks. + return (nisolated) +end + + +# FIND_NMAX -- Select up to the nmax highest ranked peaks. +# +# The data values, data, peak positions, x, and their ranks, rank, are input. +# The data values are used only in printing debugging information. +# Peak positions previously eliminated are flaged by the value INDEFR. +# The rank array contains the indices to the peak positions in order from +# the highest peak value to the lowest peak value. +# First all but the nmax highest ranked peaks (which have not been previously +# eliminated) are eliminated by marking their positions with the value INDEFR. +# Then the remaining peaks are resorted to contain only the unflaged +# peaks and the number of such peaks is returned. + +int procedure find_nmax (data, x, rank, npoints, nmax, debug) + +real data[ARB] # Input data values +real x[npoints] # Peak positions +int rank[npoints] # Ranks of peaks +int npoints # Number of input peaks +int nmax # Max number of peaks to be selected +bool debug # Print debugging information? + +int i, j, npeaks + +begin + # Only mark peaks to reject if the number peaks is greater than nmax. + if (nmax < npoints) { + npeaks = 0 + do i = 1, npoints { + if (IS_INDEFR (x[rank[i]])) + next + npeaks = npeaks + 1 + if (npeaks > nmax) { + if (debug) { + j = x[rank[i]] + call printf ( + " Reject peak at column %d with rank %d and value %g.\n") + call pargi (j) + call pargi (i) + call pargr (data[j]) + } + x[rank[i]] = INDEFR + } + } + } + + # Eliminate INDEFR points and determine the number of spectra found. + npeaks = 0 + do i = 1, npoints { + if (IS_INDEFR (x[i])) + next + npeaks = npeaks + 1 + x[npeaks] = x[i] + } + + return (npeaks) +end + + +# COMPARE -- Compare procedure for sort used in FIND_PEAKS. +# Larger values are indexed first. INDEFR values are indexed last. + +int procedure compare (index1, index2) + +# Procedure parameters: +int index1 # Comparison index +int index2 # Comparison index + +pointer y + +common /sort/ y + +begin + # INDEFR points are considered to be smallest possible values. + if (IS_INDEFR (Memr[y - 1 + index1])) + return (1) + else if (IS_INDEFR (Memr[y - 1 + index2])) + return (-1) + else if (Memr[y - 1 + index1] < Memr[y - 1 + index2]) + return (1) + else if (Memr[y - 1 + index1] > Memr[y - 1 + index2]) + return (-1) + else + return (0) +end diff --git a/noao/twodspec/multispec/profinterp.x b/noao/twodspec/multispec/profinterp.x new file mode 100644 index 00000000..9af3af15 --- /dev/null +++ b/noao/twodspec/multispec/profinterp.x @@ -0,0 +1,186 @@ +include "ms.h" + +.help profile_interpolation Jul84 MULTISPEC + The input to this procedure are the intensity profiles and the derivatives +of the profiles with position for each spectrum at two sample lines y(2) and +y(3). The profiles are gridded on unit position intervals starting at two +different points x(2) and x(3). Let us denote the i_th point in these profiles +(for some given spectrum) by + + I(x(j)+i,y(j)), dI/dx(x(j)+i,y(j)) + +where j takes the values 2 and 3 in the remaining discussion. +Note that the profiles contain dI/dx0, the derivative with respect to the +profile center. This is related to the derivative with respect to x by + + dI/dx = -dI/dx0 + + We want interpolated profiles at line y(1) gridded with a starting point +x(1). Denote this profile by + + I(x(1)+i,y(1)) + + The algorithm is to first interpolate to the point x(1)+i from each of +the two neighboring points at each endpoint. This yields the quantities: + +.nf +(1) a(j) = I(x(j)+ileft,y(j)) + dI/dx(x(j)+ileft,y(j)) * dxa(j) + b(j) = I(x(j)+iright,y(j)) + dI/dx(x(j)+iright,y(j)) * dxb(j) +.fi + +where + +.nf +(2) dxa(j) = x(1) - x(j) x(1) > x(j) + dxb(j) = x(1) - (x(j) + 1) x(1) > x(j) + dxa(2) = x(1) - (x(j) - 1) x(1) < x(j) + dxb(2) = x(1) - x(j) x(1) < x(j) +.fi + +The final value is then obtained by the bi-linear interpolation formula: + +.nf +(3) I(x(1)+i,y(1)) = a(2) * wta(2) + b(2) * wtb(2) + + a(3) * wta(3) + b(3) * wtb(3) +.fi + +where + +.nf +(4) f(2) = 1 - (y(1) - y(2)) / (y(3) - y(2)) + f(3) = 1 - (y(3) - y(1)) / (y(3) - y(2)) = 1 - f(2) + wta(j) = -dxb(j) * f(j) + wtb(j) = dxa(j) * f(j) +.fi + + If x(1) > x(j) then b(j) does not exist at the rightmost profile point. +In this case in equation 1 replace the term + +.nf +(5) a(j) * wta(j) + b(j) * wtb(j) +.fi + +with + +.nf +(6) a(j) * f(j) +.fi + +for the rightmost endpoint. +Similarly, if x(1) < x(j) then a(j) does not exist for the leftmost profile +point. Then replace the term (5) with + +.nf +(7) b(j) * f(j). +.fi + + Procedure profile_interpolation implements this interpolation scheme. +The only difference is that instead of equation 3 the profiles are built up +by accumulation of the terms. +.endhelp + +# PROFILE_INTERPOLATION -- Interpolate between two profiles. +# +# The equation references are to those in the help text. + +procedure profile_interpolation (fraction, len_profile, nspectra, nparams, + profiles, ranges) + +real fraction # The interpolation point +int len_profile # The length of the profiles +int nspectra # The number of spectra +int nparams # The number of model parameters +real profiles[len_profile, nspectra, nparams, 3] # The profiles +real ranges[nspectra, LEN_RANGES, 3] # The ranges array + +int i, j, spectrum +real dx, f[3], dxa[3], dxb[3], wta[3], wtb[3], a, b + +begin + # Clear the final profiles because we accumulate the terms in + # equations 3 and 5. + call aclrr (profiles[1, 1, I0_INDEX, 1], len_profile * nspectra) + + # Equation 4. + f[2] = 1 - fraction + f[3] = fraction + + # Do each endpoint and each spectrum. + do j = 2, 3 { + do spectrum = 1, nspectra { + dx = ranges[spectrum, DX_START, 1] - + ranges[spectrum, DX_START, j] + + if (dx < 0.) { + # x(1) < x(j) and ileft = i - 1, iright = i. + + # Equation 2. + dxa[j] = 1 + dx + dxb[j] = dx + + # Equation 4. + wta[j] = -dxb[j] * f[j] + wtb[j] = dxa[j] * f[j] + + # Accumulate the terms from the left neighbor. Eq. 1 & 3 + do i = 2, len_profile { + a = profiles[i - 1, spectrum, I0_INDEX, j] - + profiles[i - 1, spectrum, X0_INDEX, j] * dxa[j] + profiles[i, spectrum, I0_INDEX, 1] = + profiles[i, spectrum, I0_INDEX, 1] + a * wta[j] + } + + # Accumulate the terms from the right neighbor. Eq. 1 & 3 + do i = 2, len_profile { + b = profiles[i, spectrum, I0_INDEX, j] - + profiles[i, spectrum, X0_INDEX, j] * dxb[j] + profiles[i, spectrum, I0_INDEX, 1] = + profiles[i, spectrum, I0_INDEX, 1] + b * wtb[j] + } + + # There is no left neighbor for the left profile endpoint. + # Eq. 1 & 7 + b = profiles[1, spectrum, I0_INDEX, j] - + profiles[1, spectrum, X0_INDEX, j] * dxb[j] + profiles[1, spectrum, I0_INDEX, 1] = + profiles[1, spectrum, I0_INDEX, 1] + b * f[j] + } + + else { + # x(1) > x(j) and ileft = i, iright = i + 1. + # Equation 2. + dxa[j] = dx + dxb[j] = dx - 1 + + # Equation 4. + wta[j] = -dxb[j] * f[j] + wtb[j] = dxa[j] * f[j] + + # Accumulate the terms from the left neighbor. Eq. 1 & 3. + do i = 1, len_profile - 1 { + a = profiles[i, spectrum, I0_INDEX, j] - + profiles[i, spectrum, X0_INDEX, j] * dxa[j] + profiles[i, spectrum, I0_INDEX, 1] = + profiles[i, spectrum, I0_INDEX, 1] + a * wta[j] + } + + # Accumulate the terms from the right neighbor. Eq. 1 & 3. + do i = 1, len_profile - 1 { + b = profiles[i + 1, spectrum, I0_INDEX, j] - + profiles[i + 1, spectrum, X0_INDEX, j] * dxb[j] + profiles[i, spectrum, I0_INDEX, 1] = + profiles[i, spectrum, I0_INDEX, 1] + b * wtb[j] + } + + # There is no right neighbor for the right profile endpoint. + # Eq. 1 & 6 + a = profiles[len_profile, spectrum, I0_INDEX, j] - + profiles[len_profile, spectrum, X0_INDEX, j] * dxa[j] + profiles[len_profile, spectrum, I0_INDEX, 1] = + profiles[len_profile, spectrum, I0_INDEX, 1] + a * f[j] + } + } + } + call amaxkr (profiles[1, 1, I0_INDEX, 1], 0., + profiles[1, 1, I0_INDEX, 1], len_profile * nspectra) +end diff --git a/noao/twodspec/multispec/ranges.x b/noao/twodspec/multispec/ranges.x new file mode 100644 index 00000000..6704b192 --- /dev/null +++ b/noao/twodspec/multispec/ranges.x @@ -0,0 +1,385 @@ +include <mach.h> +include <ctype.h> + +.help ranges xtools "Range Parsing Tools" +.ih +PURPOSE + +These tools +parse a string using a syntax to represent integer values, ranges, and +steps. The parsed string is used to generate a list of integers for various +purposes such as specifying lines or columns in an image or tape file numbers. +.ih +SYNTAX + +The syntax for the range string consists of positive integers, '-' (minus), +'x', ',' (comma), and whitespace. The commas and whitespace are ignored +and may be freely used for clarity. The remainder of the string consists +of sequences of five fields. The first field is the beginning of a range, +the second is a '-', the third is the end of the range, the fourth is +a 'x', and the fifth is a step size. Any of the five fields may be +missing causing various default actions. The defaults are illustrated in +the following table. + +.nf +-3x1 A missing starting value defaults to 1. +2-x1 A missing ending value defaults to MAX_INT. +2x1 A missing ending value defaults to MAX_INT. +2-4 A missing step defaults to 1. +4 A missing ending value and step defaults to an ending + value equal to the starting value and a step of 1. +x2 Missing starting and ending values defaults to + the range 1 to MAX_INT with the specified step. +"" The null string is equivalent to "1 - MAX_INT x 1", + i.e all positive integers. +.fi + +The specification of several ranges yields the union of the ranges. +.ih +EXAMPLES + +The following examples further illustrate the range syntax. + +.nf +- All positive integers. +1,5,9 A list of integers equivalent to 1-1x1,5-5x1,9-9x1. +x2 Every second positive integer starting with 1. +2x3 Every third positive integer starting with 2. +-10 All integers between 1 and 10. +5- All integers greater than or equal to 5. +9-3x1 The integers 3,6,9. +.fi +.ih +PROCEDURES + +.ls 4 decode_ranges + +.nf +int procedure decode_ranges (range_string, ranges, max_ranges, minimum, + maximum, nvalues) + +char range_string[ARB] # Range string to be decoded +int ranges[3, max_ranges] # Range array +int max_ranges # Maximum number of ranges +int minimum, maximum # Minimum and maximum range values allowed +int nvalues # The number of values in the ranges +.fi + +The range string is decoded into an integer array of maximum dimension +3 * max_ranges. Each range consists of three consecutive integers +corresponding to the starting and ending points of the range and the +step size. The number of integers covered by the ranges is returned +as nvalue. The end of the set of ranges is marked by a NULL. +The returned status is either ERR or OK. +.le +.ls 4 get_next_number, get_last_number + +.nf +int procedure get_next_number (ranges, number) +int procedure get_previous_number (ranges, number) + +int ranges[ARB] # Range array +int number # Both input and output parameter +.fi + +Given a value for number the procedures find the next (previous) number in +increasing (decreasing) +value within the set of ranges. The next (previous) number is returned in +the number argument. A returned status is either OK or EOF. +EOF indicates that there are no greater values. The usual usage would +be in a loop of the form: + +.nf + number = 0 + while (get_next_number (ranges, number) != EOF) { + <Statements using number> + } +.fi +.le +.ls 4 is_in_range + +.nf +bool procedure is_in_range (ranges, number) + +int ranges[ARB] # Ranges array +int number # Number to check againts ranges +.fi + +A boolean value is returned indicating whether number is covered by +the ranges. + +.endhelp + + +# DECODE_RANGES -- Parse a string containing a list of integer numbers or +# ranges, delimited by either spaces or commas. Return as output a list +# of ranges defining a list of numbers, and the count of list numbers. +# Range limits must be positive nonnegative integers. ERR is returned as +# the function value if a conversion error occurs. The list of ranges is +# delimited by a single NULL. + + +int procedure decode_ranges (range_string, ranges, max_ranges, minimum, + maximum, nvalues) + +char range_string[ARB] # Range string to be decoded +int ranges[3, max_ranges] # Range array +int max_ranges # Maximum number of ranges +int minimum, maximum # Minimum and maximum range values allowed +int nvalues # The number of values in the ranges + +int ip, nrange, out_of_range, a, b, first, last, step, ctoi() + +begin + ip = 1 + nrange = 1 + nvalues = 0 + out_of_range = 0 + + while (nrange < max_ranges) { + # Default values + a = minimum + b = maximum + step = 1 + + # Skip delimiters + while (IS_WHITE(range_string[ip]) || range_string[ip] == ',') + ip = ip + 1 + + # Get first limit. + # Must be a number, '*', '-', 'x', or EOS. If not return ERR. + if (range_string[ip] == EOS) { # end of list + if (nrange == 1) { + if (out_of_range == 0) { + # Null string defaults + ranges[1, 1] = a + ranges[2, 1] = b + ranges[3, 1] = step + ranges[1, 2] = NULL + nvalues = (b - a) / step + 1 + return (OK) + } else { + # Only out of range data + return (ERR) + } + } else { + ranges[1, nrange] = NULL + return (OK) + } + } else if (range_string[ip] == '-') + ; + else if (range_string[ip] == '*') + ; + else if (range_string[ip] == 'x') + ; + else if (IS_DIGIT(range_string[ip])) { # ,n.. + if (ctoi (range_string, ip, a) == 0) + return (ERR) + } else + return (ERR) + + # Skip delimiters + while (IS_WHITE(range_string[ip]) || range_string[ip] == ',') + ip = ip + 1 + + # Get last limit + # Must be '-', '*', or 'x' otherwise b = a. + if (range_string[ip] == 'x') + ; + else if ((range_string[ip] == '-') || (range_string[ip] == '*')) { + ip = ip + 1 + while (IS_WHITE(range_string[ip]) || range_string[ip] == ',') + ip = ip + 1 + if (range_string[ip] == EOS) + ; + else if (IS_DIGIT(range_string[ip])) { + if (ctoi (range_string, ip, b) == 0) + return (ERR) + } else if (range_string[ip] == 'x') + ; + else + return (ERR) + } else + b = a + + # Skip delimiters + while (IS_WHITE(range_string[ip]) || range_string[ip] == ',') + ip = ip + 1 + + # Get step. + # Must be 'x' or assume default step. + if (range_string[ip] == 'x') { + ip = ip + 1 + while (IS_WHITE(range_string[ip]) || range_string[ip] == ',') + ip = ip + 1 + if (range_string[ip] == EOS) + ; + else if (IS_DIGIT(range_string[ip])) { + if (ctoi (range_string, ip, step) == 0) + ; + } else if (range_string[ip] == '-') + ; + else if (range_string[ip] == '*') + ; + else + return (ERR) + } + + # Output the range triple. + first = min (a, b) + last = max (a, b) + if (first < minimum) + first = minimum + mod (step - mod (minimum - first, step), step) + if (last > maximum) + last = maximum - mod (last - maximum, step) + if (first <= last) { + ranges[1, nrange] = first + ranges[2, nrange] = last + ranges[3, nrange] = step + nvalues = nvalues + (last - first) / step + 1 + nrange = nrange + 1 + } else + out_of_range = out_of_range + 1 + } + + return (ERR) # ran out of space +end + + +# GET_NEXT_NUMBER -- Given a list of ranges and the current file number, +# find and return the next file number. Selection is done in such a way +# that list numbers are always returned in monotonically increasing order, +# regardless of the order in which the ranges are given. Duplicate entries +# are ignored. EOF is returned at the end of the list. + +int procedure get_next_number (ranges, number) + +int ranges[ARB] # Range array +int number # Both input and output parameter + +int ip, first, last, step, next_number, remainder + +begin + # If number+1 is anywhere in the list, that is the next number, + # otherwise the next number is the smallest number in the list which + # is greater than number+1. + + number = number + 1 + next_number = MAX_INT + + for (ip=1; ranges[ip] != NULL; ip=ip+3) { + first = ranges[ip] + last = ranges[ip+1] + step = ranges[ip+2] + if (number >= first && number <= last) { + remainder = mod (number - first, step) + if (remainder == 0) + return (number) + if (number - remainder + step <= last) + next_number = number - remainder + step + } else if (first > number) + next_number = min (next_number, first) + } + + if (next_number == MAX_INT) + return (EOF) + else { + number = next_number + return (number) + } +end + + +# GET_PREVIOUS_NUMBER -- Given a list of ranges and the current file number, +# find and return the previous file number. Selection is done in such a way +# that list numbers are always returned in monotonically decreasing order, +# regardless of the order in which the ranges are given. Duplicate entries +# are ignored. EOF is returned at the end of the list. + +int procedure get_previous_number (ranges, number) + +int ranges[ARB] # Range array +int number # Both input and output parameter + +int ip, first, last, step, next_number, remainder + +begin + # If number-1 is anywhere in the list, that is the previous number, + # otherwise the previous number is the largest number in the list which + # is less than number-1. + + number = number - 1 + next_number = 0 + + for (ip=1; ranges[ip] != NULL; ip=ip+3) { + first = ranges[ip] + last = ranges[ip+1] + step = ranges[ip+2] + if (number >= first && number <= last) { + remainder = mod (number - first, step) + if (remainder == 0) + return (number) + if (number - remainder >= first) + next_number = number - remainder + } else if (last < number) { + remainder = mod (last - first, step) + if (remainder == 0) + next_number = max (next_number, last) + else if (last - remainder >= first) + next_number = max (next_number, last - remainder) + } + } + + if (next_number == 0) + return (EOF) + else { + number = next_number + return (number) + } +end + + +# IS_IN_RANGE -- Test number to see if it is in range. + +bool procedure is_in_range (ranges, number) + +int ranges[ARB] # Range array +int number # Number to be tested against ranges + +int ip, first, last, step + +begin + for (ip=1; ranges[ip] != NULL; ip=ip+3) { + first = ranges[ip] + last = ranges[ip+1] + step = ranges[ip+2] + if (number >= first && number <= last) + if (mod (number - first, step) == 0) + return (TRUE) + } + + return (FALSE) +end + +# EXPAND_RANGES -- Expand a range string into a array of values. + +int procedure expand_ranges (ranges, array, max_nvalues) + +int ranges[ARB] # Range array +int array[max_nvalues] # Array of values +int max_nvalues # Maximum number of values + +int n, value + +int get_next_number() + +begin + n = 0 + value = 0 + while ((n < max_nvalues) && (get_next_number (ranges, value) != EOF)) { + n = n + 1 + array[n] = value + } + + return (n) +end diff --git a/noao/twodspec/multispec/response.par b/noao/twodspec/multispec/response.par new file mode 100644 index 00000000..0d6cdf60 --- /dev/null +++ b/noao/twodspec/multispec/response.par @@ -0,0 +1,11 @@ +# RESPONSE + +input_image,f,a,,,,Input image to be smoothed and cleaned +output_image,f,a,,,,Smoothed and cleaned output image +spline_order,i,h,4,2,,Smoothing spline order +width,i,a,1,1,,Width of smoothing region +sigma_min,r,h,1,,,Minimum pixel sigma +above,r,h,5,,,Upper cleaning threshold +below,r,h,5,,,Lower cleaning threshold +window,i,h,0,0,,Rejection window radiu +div_threshold,r,h,1000.,,,Division threshold diff --git a/noao/twodspec/multispec/sampline.x b/noao/twodspec/multispec/sampline.x new file mode 100644 index 00000000..37583f9f --- /dev/null +++ b/noao/twodspec/multispec/sampline.x @@ -0,0 +1,73 @@ +include <mach.h> +include "ms.h" + + +# GET_SAMPLE_LINE -- Get the nearest sample line to the given image lines. +# +# The nearest sample line to each image line is found an returned +# as the function value. + +int procedure get_sample_line (ms, line) + +pointer ms # MULTISPEC data structure +int line # Image line + +int sample, midpoint + +begin + sample = 0 + midpoint = 0 + + repeat { + sample = sample + 1 + if (sample < MS_NSAMPLES(ms)) + midpoint = (LINE(ms, sample) + LINE(ms, sample + 1)) / 2 + else if (sample == MS_NSAMPLES(ms)) + midpoint = MAX_INT + else + break + } until (line < midpoint) + + return (sample) +end + + +# GET_SAMPLE_LINES -- Get the sample lines for the given image lines. +# +# Image lines in the form of a range array are given. +# The nearest sample line to each image line is found. The array of +# sample lines is returned and the function value is the number of +# sample lines. + +int procedure get_sample_lines (ms, lines, samples) + +pointer ms # MULTISPEC data structure +int lines[ARB] # Image line range array +int samples[ARB] # Return sample lines + +int nsamples, sample, line, midpoint +int get_next_number() + +begin + nsamples = 0 + sample = 0 + midpoint = 0 + line = 0 + + while (get_next_number (lines, line) != EOF) { + repeat { + sample = sample + 1 + if (sample < MS_NSAMPLES(ms)) + midpoint = (LINE(ms, sample) + LINE(ms, sample + 1)) / 2 + else if (sample == MS_NSAMPLES(ms)) + midpoint = MAX_INT + else + return (nsamples) + } until (line < midpoint) + + nsamples = nsamples + 1 + samples[nsamples] = sample + line = midpoint - 1 + } + return (nsamples) +end diff --git a/noao/twodspec/multispec/setfitparams.x b/noao/twodspec/multispec/setfitparams.x new file mode 100644 index 00000000..780572c3 --- /dev/null +++ b/noao/twodspec/multispec/setfitparams.x @@ -0,0 +1,27 @@ +include "ms.h" + +# SET_FITPARAMS -- Set the fitparams array from the spectra range array +# and the parameters array. + +procedure set_fitparams (spectra, parameters, nspectra, nparams, fitparams) + +int spectra[ARB] +int parameters[nparams] +int nspectra +int nparams +int fitparams[nspectra, nparams] + +int i, j + +bool is_in_range() + +begin + do i = 1, nspectra { + do j = 1, nparams { + if (is_in_range (spectra, i) && (parameters[j] == YES)) + fitparams[i, j] = YES + else + fitparams[i, j] = NO + } + } +end diff --git a/noao/twodspec/multispec/setmodel.x b/noao/twodspec/multispec/setmodel.x new file mode 100644 index 00000000..98c1a630 --- /dev/null +++ b/noao/twodspec/multispec/setmodel.x @@ -0,0 +1,86 @@ +include "ms.h" + +# SET_MODEL -- Set a line of model data from profiles based on their +# ranges starting values. + +procedure set_model (ms, model, model_profiles, ranges, len_line, len_profile, + nspectra) + +pointer ms # MULTISPEC data structure +real model[len_line] # Model line created +real model_profiles[len_profile, nspectra] # Model profiles +real ranges[nspectra, LEN_RANGES] # Ranges array for the profiles +int len_line # The length of the model line +int len_profile # The length of the profiles +int nspectra # The number of spectra + +int i, x, spectrum + +begin + # Set the model background to zero. + call aclrr (model, len_line) + + # For each spectrum and each profile point add contribution to model. + do spectrum = 1, nspectra { + do i = 1, len_profile { + # Column corresponding to profile point i and spectrum. + x = ranges[spectrum, X_START] + i - 1 + + # Scale the model profile by the model parameter I0 and + # add to the model line. + if ((x >= 1) && (x <= len_line)) + model[x] = model[x] + PARAMETER(ms, I0, spectrum) * + model_profiles[i, spectrum] + } + } +end + +# SET_MODEL1 -- Set a line of model data from profiles based on the spectra +# function fit position centers and the ranges dx_start value. + +procedure set_model1 (ms, line, profiles, coeff, ranges, len_line, len_profile, + nspectra, model) + +pointer ms # MULTISPEC data structure +int line # Image line for model +real profiles[len_profile, nspectra] # Profiles +real coeff[ARB] # Image interpolation coeff. +real ranges[nspectra, LEN_RANGES] # Ranges array for profiles +int len_line # Length of model line +int len_profile # Length of profiles +int nspectra # Number of spectra +real model[len_line] # Model line to be created + +int i, x, spectrum +real x_start, dx + +real cveval(), asival() + +begin + # Clear the model to a zero background. + call aclrr (model, len_line) + + # Add the contribution for each spectrum. + do spectrum = 1, nspectra { + # Fit image interpolator to profile. + call asifit (profiles[1,spectrum], len_profile, coeff) + + # Determine starting column corresponding to spectrum at specified + # line whose central position is given by the fit function. + x_start = cveval (CV(ms, X0_FIT, spectrum), real (line)) + + ranges[spectrum, DX_START] + + # For each column corresponding to a point in the profile determine + # the interpolation point dx within the profile and evaluate the + # the image interpolation function. + + x = x_start + do i = 1, len_profile - 1 { + x = x + 1 + if ((x >= 1) && (x <= len_line)) { + dx = x - x_start + 1 + model[x] = model[x] + asival (dx, coeff) + } + } + } +end diff --git a/noao/twodspec/multispec/setranges.x b/noao/twodspec/multispec/setranges.x new file mode 100644 index 00000000..46247a08 --- /dev/null +++ b/noao/twodspec/multispec/setranges.x @@ -0,0 +1,23 @@ +include "ms.h" + +# SET_RANGES -- Set profile starting range array. +# +# The ranges array relates the starting point of the profiles relative +# to the center of profile and relative to the image line. For more +# details see the MULTISPEC system documentation. + +procedure set_ranges (ms, lower, ranges, nspectra) + +pointer ms # MULTISPEC data structure +real lower # Relative lower limit of profiles +real ranges[nspectra, LEN_RANGES] # Ranges array to be set +int nspectra # Number of spectra + +int i + +begin + do i = 1, nspectra { + ranges[i, X_START] = int (PARAMETER(ms, X0, i)) + lower + ranges[i, DX_START] = ranges[i, X_START] - PARAMETER(ms, X0, i) + } +end diff --git a/noao/twodspec/multispec/setsmooth.x b/noao/twodspec/multispec/setsmooth.x new file mode 100644 index 00000000..10740dce --- /dev/null +++ b/noao/twodspec/multispec/setsmooth.x @@ -0,0 +1,250 @@ +include <imhdr.h> +include "ms.h" + +.help set_smooth Jul84 MULTISPEC +.sh +Procedure set_smooth + + This procedure returns data profiles for the requested image line and model +profiles consisting of the sum of (naverage =) nlines - 1 image line data +profiles surrounding (and excluding) the data image line. + + A buffer of nlines + 1 set of profiles is kept. The first set of profiles +is used to keep the sum of the nlines - 1 profiles which excludes the current +line of data profiles (thus, the number of lines in the sum = nlines - 1). +The remaining sets of profiles (2 to nlines + 1) contain data profiles for all +the lines in the sum plus the current data line. The lines are stored in a +cyclic fashion with the buffer line being related to the data line by + + buffer line = 2 + mod (data line - 1, nlines) + +Each data line is read and converted into a set of profiles and put into the +buffer only if it is not already in the buffer. + + The algorithm first checks the state of the previous profiles buffer. +If it would be unchanged then it returns. Otherwise, it subtracts the profiles +which are not in common with the new set of summation lines from the +sum profiles before replacing those lines in the profiles buffer with new data +profiles. If the number of vector subtractions exceeds the number of vector +additions to readd the common lines to the sum profiles then the common +profiles are readded instead. The new data profiles are then obtained from +the image (with procedure msgprofiles) and added, if needed, to the sum +profiles. Finally, the sum profiles are copied to the model profiles and +the profiles from the profiles buffer corresponding to the requested data +line are copied to the data profiles array. + + This algorithm is maximumally efficient with its imageio. If the model +lines are requested sequentially through the image then each image data line +will be read only once and each new model line will, on average, require only +one image read, two vector additions, and two vector subtractions. The +number of vector additions and subtractions is two because the current data +line is excluded from the sum. +.sh +Procedure msgprofiles + + In order to obtain model profiles based on summing the profiles from +a number of neighboring lines, the profiles from each line must be +shifted to the relative profile centers. The procedure msgprofiles reads +an image line and computes an interpolation function for the line. +The spectra profiles are then extracted using the position interpolation +function to determine the spectra centers in the image line. The +profiles are aligned to the same relative positions in the profiles +array based on the ranges array. +.endhelp + + +# SET_SMOOTH -- Set the SMOOTH model profiles. + +procedure set_smooth (ms, im, line, ranges, profiles, coeff, + len_prof, nspectra, nlines, data, model) + +pointer ms # MULTISPEC data structure +int im # IMIO image descriptor +int line # Image line to be modeled +real ranges[nspectra, LEN_RANGES] # Ranges array +real profiles[len_prof, nspectra, ARB] # Profiles array +real coeff[ARB] # Image interpolator coeffs. +int len_prof # Length of profiles +int nspectra # Number of spectra +int nlines # Number of lines in average +real data[len_prof, nspectra] # Data profiles for line +real model[len_prof, nspectra] # SMOOTH model profiles + +int i, j, navg +int len_profs, last_line, last_start, last_end, line_start, line_end +pointer k + +data len_profs/0/ + +begin + # Initialize + if (len_profs == 0) { + navg = nlines - 1 + len_profs = len_prof * nspectra + last_line = 0 + last_start = -nlines + last_end = 0 + } + + # Determine range of lines for averaging. + + # The following is to use the center of the averaging region. + #line_start = max (1, line - nlines / 2) + + # The following uses the preceeding nlines - 1 lines. + line_start = max (1, line - (nlines - 1)) + + line_start = min (line_start, IM_LEN(im, 2) - nlines) + line_end = line_start + nlines - 1 + + # Return if the same line is the same and the lines used in the + # sum profile are the same. + + if ((line_start == last_start) && (line == last_line)) + return + + # If the number of lines in common with the previous sum profile is + # < nlines / 2 then it is more efficient to clear the sum profile + # and readd the common lines. + + if (abs (line_start - last_start) > nlines / 2) { + call aclrr (profiles[1,1,1], len_profs) + do i = last_start, last_end { + j = i - line_start + + # If the old line i is within the new sum add it to the sum. + # However, if the line is the new data line do not add it. + if ((j >= 0) && (j < nlines) && (i != line)) { + k = 2 + mod (i - 1, nlines) + call aaddr (profiles[1,1,1], profiles[1,1,k], + profiles[1,1,1], len_profs) + } + } + + # If the number in lines in common is >= nlines / 2 then it is more + # efficient to subtract the lines not in common from the sum. + + } else { + do i = last_start, last_end { + j = i - line_start + k = 2 + mod (i - 1, nlines) + + # If the old line i is not within the new sum subtract it. + # Also, if the line is the new data line subtract it. + if ((j < 0) || (j >= nlines) || (i == line)) { + # However, don't subtract the last data line since it was + # not in the previous sum. + if (i != last_line) { + call asubr (profiles[1,1,1], profiles[1,1,k], + profiles[1,1,1], len_profs) + } + + # If the old line is within the new sum but it was the old data + # line then add it to the sum since it was not in the old sum. + } else if (i == last_line) { + call aaddr (profiles[1,1,1], profiles[1,1,k], + profiles[1,1,1], len_profs) + } + } + } + + # Get the new profiles into the profile buffer and the add to the sum. + do i = line_start, line_end { + j = i - last_start + if ((j < 0) || (j >= nlines)) { + k = 2 + mod (i - 1, nlines) + + # Get the data profile for line i and put it in profiles k. + call msgprofiles (ms, im, i, ranges, profiles[1,1,k], coeff, + len_prof, nspectra) + + # If the new line in the buffer is not the data line then + # add it to the sum profile. + if (i != line) { + call aaddr (profiles[1,1,1], profiles[1,1,k], + profiles[1,1,1], len_profs) + } + } + } + + # Record current state of the average. + last_line = line + last_start = line_start + last_end = line_end + + # Set the data profiles and model profiles. The copies are + # made rather than working directly from the profiles buffer so that + # changes can be made in the data and model profiles without affecting + # the buffer. + + k = 2 + mod (line - 1, nlines) + call amovr (profiles[1,1,k], data, len_profs) + call amovr (profiles[1,1,1], model, len_profs) +end + + +# UPDATE_SMOOTH -- Replace an updated data profile in the profiles buffer. + +procedure update_smooth (line, data, profiles, len_prof, nspectra, nlines) + +int line # Data image line +real data[len_prof, nspectra] # Data profiles +real profiles[len_prof, nspectra, ARB] # Profiles buffer +int len_prof # Length of profiles +int nspectra # Number of spectra +int nlines # Number of lines in buffer + +int i + +begin + i = 2 + mod (line - 1, nlines) + call amovr (data, profiles[1,1,i], len_prof * nspectra) +end + + +# MSGPROFILES -- Read image line and extract profiles in standard positions. + +procedure msgprofiles (ms, im, line, ranges, profile, coeff, len_prof, + nspectra) + +pointer ms # MULTISPEC data structure +pointer im # IMIO image descriptor +int line # Image line to be read +real ranges[nspectra, LEN_RANGES] # Ranges array for profiles +real profile[len_prof, nspectra] # Profiles to be obtained +real coeff[ARB] # Image interpolator coeffs. +int len_prof # Length of profiles +int nspectra # Number of spectra + +int i, j +real x +pointer im_buf + +pointer imgl2r() +real cveval(), asival() + +begin + # Read image line. + im_buf = imgl2r (im, line) + + # Fit image interpolation function. + call asifit (Memr[im_buf], IM_LEN(im, 1), coeff) + + # For each spectrum extract the profiles. + do j = 1, nspectra { + + # Determine profile starting point in image coordinates using the + # fit function for the spectrum center. + x = cveval (CV(ms, X0_FIT, j), real (line)) + + ranges[j, DX_START] - 1 + + # For each point in the profile evaluate the image interpolator. + do i = 1, len_prof { + x = x + 1 + if ((x < 1) || (x > IM_LEN(im, 1))) + profile[i, j] = 0. + else + profile[i, j] = asival (x, coeff) + } + } +end diff --git a/noao/twodspec/multispec/solve.x b/noao/twodspec/multispec/solve.x new file mode 100644 index 00000000..b7249242 --- /dev/null +++ b/noao/twodspec/multispec/solve.x @@ -0,0 +1,312 @@ +include "ms.h" + +# SOLVE: +# Solve for the parameter correction vector using the banded matrix +# technique decribed in Lawson and Hanson. +# +# The variables g, mdg, nb, ip, ir, mt, jt, rnorm, x and n have the +# same meaning as described in Lawson and Hanson. + +procedure solve (ms, data, model, fitparams, profiles, ranges, len_line, + len_profile, nspectra, nparams, solution, norm) + +# Procedure parameters: +pointer ms # MULTISPEC data structure +real data[len_line] # Data to be fit +real model[len_line] # Model to be corrected +int fitparams[nspectra, nparams] # Model parameters to be fit +real profiles[len_profile, nspectra, nparams]# Model parameter derivatives +real ranges[nspectra, LEN_RANGES] # Ranges array for profiles +int len_line # Length of data line +int len_profile # Length of profiles +int nspectra # Number of spectra +int nparams # Number of model parameters +real solution[nspectra, nparams] # Solution correction vector +real norm # Measure of fit + +# Lawson and Hanson parameters: +pointer g # Working array +pointer x # Working vector +int mdg # Maximum dimension of g +int n # Number of parameters to be determined +int nb # Parameter bandwith +int ip, ir, mt, jt, jt_next # Array pointers +real rnorm # Deviation from fit +int ier # Error flag + +int ns # Maximum spectra bandwidth +pointer columns # Columns to be used. +int ncolumns # Number of columns +pointer spectra # Spectra to be used. +int nspectra_to_solve # Number of spectra +int k_start, k_next # Indices to the spectra array +int column, spectrum, parameter # Column, spectrum and parameter values +int ns_in_band # Number of spectra in band +int i, j, k, l, m +bool is_zero +pointer sp + +begin + # Determine columns, spectra, and parameters contributing to + # the solution matrix and the bandwidth of the matrix. + call smark (sp) + call salloc (columns, len_line, TY_INT) + call salloc (spectra, nspectra, TY_INT) + call band_set (ms, fitparams, data, profiles, ranges, Memi[columns], + Memi[spectra], len_line, len_profile, nspectra, nparams, ncolumns, + nspectra_to_solve, n, ns, nb) + if (n == 0) { + call sfree (sp) + return + } + + # Allocate working memory for the Lawson and Hanson routines. + mdg = ncolumns + call salloc (g, mdg * (nb + 1), TY_REAL) + call salloc (x, n, TY_REAL) + + # Initialize array indices. + ip = 1 + ir = 1 + jt = 1 + mt = 0 + jt_next = jt + k_next = 1 + + # Accumulate banded matrix for the specifed columns, spectra, and + # parameters. + do i = 1, ncolumns { + column = Memi[columns + i - 1] + + k_start = k_next + j = jt + ns_in_band = 0 + do k = k_start, nspectra_to_solve { + spectrum = Memi[spectra + k - 1] + + # Evalute parameter derivatives and determine if all + # derivatives for the spectrum are zero. + is_zero = TRUE + do parameter = 1, nparams { + if (fitparams[spectrum, parameter] == NO) + next + j = j + 1 + m = column - ranges[spectrum, X_START] + 1 + if ((m < 1) || (m > len_profile)) + Memr[x + j - 2] = 0. + else { + Memr[x + j - 2] = profiles[m, spectrum, parameter] + if (parameter != I0_INDEX) + Memr[x + j - 2] = Memr[x + j - 2] * + PARAMETER (ms, I0, spectrum) + if (Memr[x + j - 2] != 0.) + is_zero = FALSE + } + } + + # If the spectrum has a non-zero contribution to the parameter + # matrix then increment the number of spectra in the + # band (ns_in_band). + # Else if the number of spectra in the band is still zero then + # increment the spectrum and parameter pointers. + # Else the band is assumed complete so break to accumulate + # the band. + + if (!is_zero) + ns_in_band = ns_in_band + 1 + else if (ns_in_band == 0) { + k_next = min (k + 1, nspectra_to_solve - ns + 1) + jt_next = min (j, n - nb + 1) + } else { + do l = j, jt_next + nb - 1 + Memr[x + (l - 1)] = 0. + break + } + } + + # If the number of spectra in the band is zero then reset the + # spectrum pointer (k_next) and go to the next column. + # Else if the number of spectra in the band exceeds the specified + # bandwidth return an error. + # Else accumulate the new band. + + if (ns_in_band == 0) { + k_next = k_start + jt_next = jt + next + } else if (ns_in_band > ns) + call error (MS_ERROR, "Bandwidth too small") + + # If a new submatrix is being started accumulate last submatrix. + if ((jt_next != jt) && (mt > 0)) { + call bndacc (Memr[g], mdg, nb, ip, ir, mt, jt) + mt = 0 + } + + # Increment the submatrix line pointer (mt) and add the band to + # submatrix being accumulated. + + mt = mt + 1 + jt = jt_next + do k = 1, nb + Memr[g+ir+mt-2 + (k-1)*mdg] = Memr[x + (jt - 1) + (k - 1)] + # INDEFR data may already be ignored in the column selection in + # band_set. + if (IS_INDEFR (data[column])) + Memr[g+ir+mt-2 + nb*mdg] = 0. + else + Memr[g+ir+mt-2 + nb*mdg] = data[column] - model[column] + } + + # Accumulate last submatrix and calculate banded matrix solution vector. + call bndacc (Memr[g], mdg, nb, ip, ir, mt, jt) + call bndsol (1, Memr[g], mdg, nb, ip, ir, Memr[x], n, rnorm, ier) + if (ier != 0) { + call error (MS_ERROR, "bandsol: Solution error") + } + + # Compute error matrix here. Not yet implemented. + + # The solution from bndsol is in array x. Copy x to solution. + j = 0 + do i = 1, nspectra_to_solve { + spectrum = Memi[spectra + i - 1] + do parameter = 1, nparams { + if (fitparams[spectrum, parameter] == YES) { + solution[spectrum, parameter] = Memr[x + j] + j = j + 1 + } else + solution[spectrum, parameter] = 0. + } + } + norm = rnorm + + call sfree (sp) +end + + +# Reject parameters which have only zero derivatives. Determine spectra, +# columns, and number of parameters contributing to the solution. +# Determine bandwidth of the banded matrix. + +procedure band_set (ms, fitparams, data, profiles, ranges, columns, spectra, + len_line, len_profile, nspectra, nparams, ncolumns, nspectra_to_solve, + n, ns, nb) + +pointer ms # MULTISPEC data structure +int fitparams[nspectra, nparams] # Parameters to be fit +real data[len_line] # Data being fit +real profiles[len_profile, nspectra, nparams]# Parameter derivatives +real ranges[nspectra, LEN_RANGES] # Ranges array for profiles +int columns[len_line] # Return columns to be used +int spectra[nspectra] # Return spectra to used +int len_line # Length of data being fit +int len_profile # Length of profiles +int nspectra # Number of spectra +int nparams # Number of parameters +int ncolumns # Number of useful columns +int nspectra_to_solve # Number of useful spectra +int n # Number of parameters in fit +int ns # Number of spectra in band +int nb # Bandwith of matrix + +int i, j, k +int column, spectrum, parameter +int col_start +real dx +int xmin, xmax + +begin + # Initially set the spectra and columns to NO. + call amovki (NO, spectra, nspectra) + call amovki (NO, columns, len_line) + + # Determine the spectra and columns in which the fitparams have + # non-zero derivatives. Flag those fitparams which do not have + # non-zero derivatives with NO. Count the number of parameters + # which have non-zero derivatives. + + n = 0 + do spectrum = 1, nspectra { + do parameter = 1, nparams { + if (fitparams[spectrum, parameter] == YES) { + fitparams[spectrum, parameter] = NO + col_start = ranges[spectrum, X_START] + do k = 1, len_profile { + if (profiles[k, spectrum, parameter] != 0.) { + column = col_start + k - 1 + if ((column >= 1) && (column <= len_line)) { + + # If the INDEFR data points are not to be + # ignored but replaced by the model in solve, + # replace the if clause with the following. + # columns[column] = YES + # fitparams[spectrum, parameter] = YES + + if (!IS_INDEFR (data[column])) { + columns[column] = YES + fitparams[spectrum, parameter] = YES + } + } + } + } + if (fitparams[spectrum, parameter] == YES) { + n = n + 1 + spectra[spectrum] = YES + } + } + } + } + + # Count the number spectra to be used and set the spectra array. + nspectra_to_solve = 0 + do spectrum = 1, nspectra { + if (spectra[spectrum] == YES) { + nspectra_to_solve = nspectra_to_solve + 1 + spectra[nspectra_to_solve] = spectrum + } + } + + # Count the number of columns to be used and set the columns array. + ncolumns = 0 + do column = 1, len_line { + if (columns[column] == YES) { + ncolumns = ncolumns + 1 + columns[ncolumns] = column + } + } + + # Determine the maximum number spectra contributing to any column. + ns = 1 + do i = 1, nspectra_to_solve - 1 { + xmax = 0 + do parameter = 1, nparams { + if (fitparams[spectra[i], parameter] == YES) + xmax = max (xmax, + int (ranges[spectra[i], X_START] + len_profile - 1)) + } + do j = i + 1, nspectra_to_solve { + xmin = len_line + do parameter = 1, nparams { + if (fitparams[spectra[j], parameter] == YES) + xmin = min (xmin, int (ranges[spectra[j], X_START])) + } + dx = xmax - xmin + if (dx < 0) + break + else + ns = max (ns, j - i + 1) + } + } + + # Determine the banded matrix bandwidth. + nb = 0 + do parameter = 1, nparams { + do i = 1, nspectra_to_solve { + if (fitparams[spectra[i], parameter] == YES) { + nb = nb + ns + break + } + } + } +end diff --git a/noao/twodspec/multispec/t_findpeaks.x b/noao/twodspec/multispec/t_findpeaks.x new file mode 100644 index 00000000..2e4cf79e --- /dev/null +++ b/noao/twodspec/multispec/t_findpeaks.x @@ -0,0 +1,137 @@ +include <imhdr.h> +include <fset.h> +include "ms.h" + +# T_FIND_PEAKS -- Find the spectra peaks in a MULTISPEC image and record +# their positions in the database. +# +# An average of naverage lines from the MULTISPEC image is searched +# for peaks satisfying constraints on the minimum and maximum number, +# columns, peak values, and separation between peaks. The positions +# of the peaks satisfying these constraints is entered in the database. +# It is an error if fewer than the minimum number of peaks is found +# or if the number of peaks differs from a previously determined number. +# The peak finding is done by the function FIND_PEAKS which is numerical +# and may be used outside the MULTISPEC package. + +procedure t_find_peaks () + +# CL parameters: +char image[SZ_FNAME] # Image to be searched +int lines[3, MAX_RANGES] # Image lines in which to find spectra +int min_npeaks # Minimum number of spectra to be found +int max_npeaks # Maximum number of spectra to be accepted +int separation # Minimum pixel separation between spectra +int edge # Minimum distance to edge of image +real threshold # Minimum peak value +real contrast # Max contrast between strongest and weakest +int columns[3, MAX_RANGES] # Spectra positions limited to these columns +int naverage # Number of image lines to average +bool debug # Print debugging information + +char comment[SZ_LINE] +int i, j, k, line, sample, nsamples, npoints, nspectra +pointer ms, im +pointer sp, data, x, samples + +int find_peaks(), get_sample_lines() +int clgeti(), clgranges() +real clgetr() +bool clgetb(), is_in_range() +pointer msmap(), immap() + +begin + # Get task parameters and access files. + call clgstr ("image", image, SZ_FNAME) + ms = msmap (image, READ_WRITE, 0) + im = immap (image, READ_ONLY, 0) + i = clgranges ("lines", 1, IM_LEN(im, 2), lines, MAX_RANGES) + min_npeaks = clgeti ("min_npeaks") + max_npeaks = clgeti ("max_npeaks") + separation = clgeti ("separation") + edge = clgeti ("edge") + threshold = clgetr ("threshold") + contrast = clgetr ("contrast") + i = clgranges ("columns", 1, IM_LEN(im, 1), columns, MAX_RANGES) + naverage = clgeti ("naverage") + debug = clgetb ("debug") + + call fseti (STDOUT, F_FLUSHNL, YES) + + # Allocate working memory. + npoints = IM_LEN(im, 1) + call smark (sp) + call salloc (samples, MS_NSAMPLES(ms), TY_INT) + call salloc (data, npoints, TY_REAL) + call salloc (x, npoints, TY_REAL) + + # Get the sample lines. + nsamples = get_sample_lines (ms, lines, Memi[samples]) + + # Loop through each sample line. + do i = 1, nsamples { + sample = Memi[samples + i - 1] + line = LINE(ms, sample) + + # Get the image data with averaging. + call msgimage (im, line, naverage, Memr[data]) + + # Mark columns which are to be ignored with INDEFR. + do j = 1, npoints + if (!is_in_range (columns, j)) + Memr[data + j - 1] = INDEFR + + # Find the peaks. + nspectra = find_peaks (Memr[data], Memr[x], npoints, + contrast, separation, edge, max_npeaks, threshold, debug) + + if (debug) { + call printf (" Number of spectra found in line %d = %d.\n") + call pargi (line) + call pargi (nspectra) + } + if (nspectra < min_npeaks) + call error (MS_ERROR, "Too few spectra found") + + # Enter the spectra found in the database. If the number of + # spectra has not been previously set in the database then + # enter the number of spectra and make entries in the + # database. Otherwise check that the number of spectra found + # agrees with that already in the database. + + if (MS_NSPECTRA(ms) == 0) { + if (nspectra == 0) + next + MS_NSPECTRA(ms) = nspectra + call dbenter (MS_DB(ms), NAME(ms, I0), nspectra * SZ_REAL, + MS_NSAMPLES(ms)) + call dbenter (MS_DB(ms), NAME(ms, X0), nspectra * SZ_REAL, + MS_NSAMPLES(ms)) + } else if (MS_NSPECTRA(ms) != nspectra) + call error (MS_ERROR, "Attempt to change the number of spectra") + + call msgparam (ms, X0, sample) + call amovr (Memr[x], PARAMETER(ms, X0, 1), nspectra) + call mspparam (ms, X0, sample) + + # The peak scale is taken and the pixel value at the peak. + call msgparam (ms, I0, sample) + do j = 1, nspectra { + k = PARAMETER(ms, X0, j) + PARAMETER(ms, I0, j) = Memr[data + k - 1] + } + call mspparam (ms, I0, sample) + + # Enter a comment in the database. + call sprintf (comment, SZ_LINE, + "Spectra located in sample line %d.") + call pargi (sample) + call history (ms, comment) + } + + # Update the database and close the database and image. + call msphdr (ms) + call msunmap (ms) + call imunmap (im) + call sfree (sp) +end diff --git a/noao/twodspec/multispec/t_fitfunc.x b/noao/twodspec/multispec/t_fitfunc.x new file mode 100644 index 00000000..9f6209ad --- /dev/null +++ b/noao/twodspec/multispec/t_fitfunc.x @@ -0,0 +1,158 @@ +include <math/curfit.h> +include "ms.h" + +# T_FIT_FUNCTION -- Fit a function to selected spectra parameters. +# +# A function is fit to the parameter values determined at the sample +# lines for selected spectra. The function coefficients are stored in +# the database and the fitted values replace the original values at +# the sample lines. The type of function, the parameter to be fitted, +# the sample lines used in the fit, and the spectra to be fitted +# are all selected by the user. + +procedure t_fit_function() + +char image[SZ_FNAME] # Image affected +char parameter[SZ_LINE] # Parameter to be fit +int function # Type of fitting function +int order # Order of the fitting function +int spectra[3, MAX_RANGES] # Spectra to be fitted +pointer samples # Sample lines to be fitted. + +int i, param_id, nsamples +pointer ms, sp + +int ms_db_id(), clgranges(), get_sample_lines() +pointer msmap() + +begin + # Access database and determine parameter to be fit and the + # fitting function and order. + + call clgstr ("image", image, SZ_FNAME) + ms = msmap (image, READ_WRITE, 0) + call clgstr ("parameter", parameter, SZ_LINE) + param_id = ms_db_id (ms, parameter) + call clgcurfit ("function", "order", function, order) + + # Get the image lines to be used in the fit and convert to sample + # lines. Get the spectra to be fit. + + i = clgranges ("lines", 1, MS_LEN(ms, 2), spectra, MAX_RANGES) + call smark (sp) + call salloc (samples, MS_NSAMPLES(ms), TY_INT) + nsamples = get_sample_lines (ms, spectra, Memi[samples]) + i = clgranges ("spectra", 1, MS_NSPECTRA(ms), spectra, + MAX_RANGES) + + # Fit the parameters for each spectrum, store the fits in the database, + # and substitute the fitted values for the parameter values at all + # the sample lines. + + call fit_function (ms, Memi[samples], nsamples, spectra, param_id, + function, order) + + # Finish up. + call msphdr (ms) + call msunmap (ms) + call sfree (sp) +end + + + +# FIT_FUNCTION -- Fit a function to the parameter data. +# +# If the fit coefficients for the specified parameter are not in +# the database then the database entry is created. + +procedure fit_function (ms, lines, nlines, spectra, param_id, function, order) + +pointer ms # MULTISPEC data structure +int lines[nlines] # Sample lines to be used +int nlines # Number of sample lines +int spectra[ARB] # Spectra to be fitted +int param_id # Parameter being fit +int function # Function to be fit +int order # Order of the function + +char comment[SZ_LINE] +int i, spectrum, fit_id, ier +real x, wt + +int ms_fit_id(), get_next_number() +real cveval() +bool dbaccess() + +begin + # Determine the MULTISPEC fit id from the parameter id. + fit_id = ms_fit_id (param_id) + if (fit_id == ERR) + call error (MS_ERROR, "Unknown fit identifier") + + # Enter the fit records in the database if necessary. + if (!dbaccess (MS_DB(ms), NAME(ms, fit_id))) + call dbenter (MS_DB(ms), NAME(ms, fit_id), + (7 + MS_NSAMPLES(ms)) * SZ_REAL, MS_NSPECTRA(ms)) + + # Allocate memory for the curfit data structures pointers. + if (MS_DATA(ms, fit_id) == NULL) + call malloc (MS_DATA(ms, fit_id), MS_NSPECTRA(ms), TY_INT) + + # Initialize the curfit data structures. + # If the order is INDEF then use maximum order assuming no INDEF points. + spectrum = 0 + while (get_next_number (spectra, spectrum) != EOF) { + if (IS_INDEFI (order)) { + switch (function) { + case LEGENDRE, CHEBYSHEV: + order = nlines + case SPLINE3: + order = nlines - 3 + } + } + call cvinit (CV(ms, fit_id, spectrum), function, order, 1., + real (MS_LEN(ms, 2))) + } + + # Accumulate the parameter values. + do i = 1, nlines { + x = LINE(ms, lines[i]) + call msgparam (ms, param_id, lines[i]) + + spectrum = 0 + while (get_next_number (spectra, spectrum) != EOF) + call cvaccum (CV(ms, fit_id, spectrum), x, + PARAMETER(ms, param_id, spectrum), wt, WTS_UNIFORM) + } + + # Compute and write the fit coeffients to the database. + + spectrum = 0 + while (get_next_number (spectra, spectrum) != EOF) { + call cvsolve (CV(ms, fit_id, spectrum), ier) + if (ier == NO_DEG_FREEDOM) + call error (MS_ERROR, "Error fitting parameters") + call mspfit (ms, fit_id, spectrum) + } + + # For each sample line and each selected spectrum replace the + # selected parameter value with the fit evaluation. + + do i = 1, MS_NSAMPLES(ms) { + x = LINE(ms, i) + call msgparam (ms, param_id, i) + + spectrum = 0 + while (get_next_number (spectra, spectrum) != EOF) + PARAMETER(ms, param_id, spectrum) = + cveval (CV(ms, fit_id, spectrum), x) + + call mspparm (ms, param_id, i) + } + + # Add a comment to the database comments. + + call sprintf (comment, SZ_LINE, "Fit a function to parameter %s.") + call pargstr (NAME(ms, param_id)) + call history (ms, comment) +end diff --git a/noao/twodspec/multispec/t_fitgauss5.x b/noao/twodspec/multispec/t_fitgauss5.x new file mode 100644 index 00000000..146d37b6 --- /dev/null +++ b/noao/twodspec/multispec/t_fitgauss5.x @@ -0,0 +1,209 @@ +include "ms.h" + +# T_FIT_GAUSS5 -- Fit the GAUSS5 model. +# +# This task selects the database, the sample lines to be modeled, the +# model fitting algorithm, whether to track models from one sample line +# to the next or model them independently. + +procedure t_fit_gauss5 () + +char image[SZ_FNAME] # Image +int lines[3, MAX_RANGES] # Sample lines to be modeled +bool track # Track model solution +int start # Starting line for modeling +int naverage # Number of image lines to average +real lower # Starting point of profile +real upper # Ending point of profile + +int i, nsamples, sample_start, sample, line, improved +int len_line, len_profile, nspectra, nparams +pointer ms, im +pointer sp, data, model, profiles, ranges, samples + +int get_sample_line(), get_sample_lines() +int g5_fit1(), g5_fit2() +int clgeti(), clgranges(), btoi() +bool clgetb() +real clgetr() +pointer msmap(), immap() + +include "fitgauss5.com" + +begin + # Access the database and the image. + call clgstr ("image", image, SZ_FNAME) + ms = msmap (image, READ_WRITE, 0) + im = immap (image, READ_ONLY, 0) + + # Get the task parameters. + i = clgranges ("lines", 1, MS_LEN(ms, 2), lines, MAX_RANGES) + i = clgranges ("spectra", 1, MS_NSPECTRA(ms), spectra, MAX_RANGES) + track = clgetb ("track") + start = clgeti ("start") + naverage = clgeti ("naverage") + lower = clgetr ("lower") + upper = clgetr ("upper") + factor = clgetr ("factor") + + # Algorithm 1 fits the parameters selected in the parameters array + # simultaneously. Algorithm 2 does not require the user to specify + # the parameters. + + algorithm = clgeti ("algorithm") + if (algorithm == 1) { + parameters[I0_INDEX] = btoi (clgetb ("fit_i0")) + parameters[X0_INDEX] = btoi (clgetb ("fit_x0")) + parameters[S0_INDEX] = btoi (clgetb ("fit_s0")) + parameters[S1_INDEX] = btoi (clgetb ("fit_s1")) + parameters[S2_INDEX] = btoi (clgetb ("fit_s2")) + } + + # Select whether to smooth the shape parameters after fitting. + # If smoothing is desired get the spline smoothing parameters. + + smooth[S0_INDEX] = btoi (clgetb ("smooth_s0")) + smooth[S1_INDEX] = btoi (clgetb ("smooth_s1")) + smooth[S2_INDEX] = btoi (clgetb ("smooth_s2")) + if ((smooth[S0_INDEX] == YES) || (smooth[S1_INDEX] == YES) || + (smooth[S2_INDEX] == YES)) { + call ms_set_smooth (1., real(MS_LEN(ms, 1)), MS_NSPECTRA(ms)) + } + + call g5_set_verbose (clgetb ("verbose")) + call g5_prnt1 (image, naverage, track, start) + + # Set the various array dimensions and allocate memory. + len_line = MS_LEN(ms, 1) + len_profile = nint (upper - lower + 2) + nspectra = MS_NSPECTRA(ms) + nparams = MS_NGAUSS5 + call smark (sp) + call salloc (samples, MS_NSAMPLES(ms), TY_INT) + call salloc (data, len_line, TY_REAL) + call salloc (model, len_line, TY_REAL) + call salloc (profiles, len_profile * nspectra * nparams, TY_REAL) + call salloc (ranges, nspectra * LEN_RANGES, TY_REAL) + + # Convert from image lines to sample lines. + nsamples = get_sample_lines (ms, lines, Memi[samples]) + sample_start = get_sample_line (ms, start) + + # Initialize forward tracking. If tracking get the initial parameters, + # model profiles and model line from the starting line. + + if (track) { + call msggauss5 (ms, sample_start) + call mod_gauss5 (ms, lower, Memr[profiles], Memr[ranges], + len_profile, nspectra) + call set_model (ms, Memr[model], Memr[profiles], Memr[ranges], + len_line, len_profile, nspectra) + } + + # Track forward from the starting line to the specified sample lines. + + do i = 1, nsamples { + sample = Memi[samples + i - 1] + if (sample < sample_start) + next + line = LINE(ms, sample) + + # Get the image data line. + call msgimage (im, line, naverage, Memr[data]) + + # If not tracking get the initial parameters, model profiles, and + # model line for the current line. Otherwise record the starting + # parameters. + + if (!track) { + call msggauss5 (ms, sample) + call mod_gauss5 (ms, lower, Memr[profiles], Memr[ranges], + len_profile, nspectra) + call set_model (ms, Memr[model], Memr[profiles], Memr[ranges], + len_line, len_profile, nspectra) + } else + call mspgauss5 (ms, sample) + + call g5_prnt2 (line, Memr[data], len_line) + + # Do the model fitting using the selected algorithm. + switch (algorithm) { + case 1: + improved = g5_fit1 (ms, Memr[data], Memr[model], Memr[profiles], + Memr[ranges], lower, len_profile) + case 2: + improved = g5_fit2 (ms, Memr[data], Memr[model], Memr[profiles], + Memr[ranges], lower, len_profile) + } + + # If the new model parameters have improved the fit record them in + # the database. + if (improved == YES) + call mspgauss5 (ms, sample) + } + + # Initialize backward tracking. If tracking get the initial parameters, + # model profiles and model line from the starting line. + + if (track) { + call msggauss5 (ms, sample_start) + call mod_gauss5 (ms, lower, Memr[profiles], Memr[ranges], + len_profile, nspectra) + call set_model (ms, Memr[model], Memr[profiles], Memr[ranges], + len_line, len_profile, nspectra) + } + + # Track backward from the starting line to the specified sample lines. + + do i = nsamples, 1, -1 { + sample = Memi[samples + i - 1] + if (sample >= sample_start) + next + line = LINE(ms, sample) + + # Get the image data line. + call msgimage (im, line, naverage, Memr[data]) + + # If not tracking get the initial parameters, model profiles, and + # model line for the current line. Else record the starting + # parameters. + + if (!track) { + call msggauss5 (ms, sample) + call mod_gauss5 (ms, lower, Memr[profiles], Memr[ranges], + len_profile, nspectra) + call set_model (ms, Memr[model], Memr[profiles], Memr[ranges], + len_line, len_profile, nspectra) + } else + call mspgauss5 (ms, sample) + + call g5_prnt2 (line, Memr[data], len_line) + + + # Do the model fitting using the selected algorithm. + switch (algorithm) { + case 1: + improved = g5_fit1 (ms, Memr[data], Memr[model], Memr[profiles], + Memr[ranges], lower, len_profile) + case 2: + improved = g5_fit2 (ms, Memr[data], Memr[model], Memr[profiles], + Memr[ranges], lower, len_profile) + } + + # If the new model parameters have improved the fit record them in + # the database. + + if (improved == YES) + call mspgauss5 (ms, sample) + } + + # Finish up. + if ((smooth[S0_INDEX] == YES) || (smooth[S1_INDEX] == YES) || + (smooth[S2_INDEX] == YES)) { + call ms_free_smooth () + } + call imunmap (im) + call history (ms, "Fit model") + call msunmap (ms) + call sfree (sp) +end diff --git a/noao/twodspec/multispec/t_modellist.x b/noao/twodspec/multispec/t_modellist.x new file mode 100644 index 00000000..911ec2ee --- /dev/null +++ b/noao/twodspec/multispec/t_modellist.x @@ -0,0 +1,126 @@ +include <imhdr.h> +include "ms.h" + + +# T_MODEL_LIST -- List model values for selected columns and sample lines. +# +# The output list format is column, image line, data value, model value. +# This task differs from t_new_image primarily in that there is no profile +# interpolation. The model is evaluated only at the sample lines. It +# is used to check the results of the model fitting tasks. + +procedure t_model_list () + +# User parameters: +char image[SZ_FNAME] # Image +int model_type # Model type: gauss5, profile +int columns[3, MAX_RANGES] # Columns to be listed +int lines[3, MAX_RANGES] # Sample Lines to be listed +int naverage # Number of image lines to average +real lower # Lower limit of profile model +real upper # Upper limit of profile model + +int i, sample, nsamples, line, column +pointer ms, im +pointer sp, samples, data, model + +int clgeti(), ms_model_id(), clgranges() +int get_next_number(), get_sample_lines +real clgetr() +pointer msmap(), immap() + +begin + # Access the database and image. + call clgstr ("image", image, SZ_FNAME) + ms = msmap (image, READ_ONLY, 0) + im = immap (image, READ_ONLY, 0) + + # Get the task parameters. + model_type = ms_model_id ("model") + i = clgranges ("columns", 1, IM_LEN(im, 1), columns, MAX_RANGES) + i = clgranges ("lines", 1, IM_LEN(im, 2), lines, MAX_RANGES) + naverage = clgeti ("naverage") + lower = clgetr ("lower") + upper = clgetr ("upper") + + # Currently only model GAUSS5 is available. + if (model_type != GAUSS5) + return + + # Allocate memory for the sample lines, data and model. + call smark (sp) + call salloc (samples, MS_NSAMPLES(ms), TY_INT) + call salloc (data, IM_LEN(im, 1), TY_REAL) + call salloc (model, IM_LEN(im, 1), TY_REAL) + + # Convert to sample lines. + nsamples = get_sample_lines (ms, lines, Memi[samples]) + + # For each sample line get the data line and compute a model line. + # Print the data and model values for the selected image columns. + do i = 1, nsamples { + sample = Memi[samples + i - 1] + line = LINE(ms, sample) + + call msgimage (im, line, naverage, Memr[data]) + + switch (model_type) { + case GAUSS5: + call gauss5_model (ms, sample, lower, upper, Memr[model]) + } + + column = 0 + while (get_next_number (columns, column) != EOF) { + call printf ("%d %d %g %g\n") + call pargi (column) + call pargi (line) + call pargr (Memr[data + column - 1]) + call pargr (Memr[model + column - 1]) + } + } + + call sfree (sp) + call imunmap (im) + call msunmap (ms) +end + + +# GAUSS5_MODEL -- Generate a line of the GAUSS5 model. + +procedure gauss5_model (ms, line, lower, upper, model) + +pointer ms # MULTISPEC data structure +int line # Sample line +real lower # Lower profile limit +real upper # Upper profile limit +real model[ARB] # Model data array to be returned + +int nspectra, nparams, len_line, len_profile +pointer sp, profiles, ranges + +begin + # Set the dimensions of the arrays. + nspectra = MS_NSPECTRA(ms) + nparams = MS_NGAUSS5 + len_line = MS_LEN(ms, 1) + len_profile = nint (upper - lower + 2) + + # Allocate arrays. + call smark (sp) + call salloc (ranges, nspectra * LEN_RANGES, TY_REAL) + call salloc (profiles, len_profile * nspectra * nparams, TY_REAL) + + # Read the model parameters for the specified sample line. + call msggauss5 (ms, line) + + # Calculate the model profiles. + call mod_gauss5 (ms, lower, Memr[profiles], Memr[ranges], len_profile, + nspectra) + + # Make a model line using the model profiles. + call set_model (ms, model, Memr[profiles], Memr[ranges], len_line, + len_profile, nspectra) + + # Return memory. + call sfree (sp) +end diff --git a/noao/twodspec/multispec/t_msextract.x b/noao/twodspec/multispec/t_msextract.x new file mode 100644 index 00000000..da649469 --- /dev/null +++ b/noao/twodspec/multispec/t_msextract.x @@ -0,0 +1,112 @@ +include <imhdr.h> +include "ms.h" + +# T_MSEXTRACT -- General MULTISPEC extraction task. +# +# The general task parameters are obtained and the desired extraction +# procedure is called. The input database and image are accessed and +# the output image is created. + +procedure t_msextract () + +# User parameters: +char image[SZ_FNAME] # Image +char output[SZ_FNAME] # Output image file +real lower # Lower limit of strip +real upper # Upper limit of strip +int spectra[3, MAX_RANGES] # Spectra to be extracted +int lines[3, MAX_RANGES] # Lines to be extracted +bool ex_model # Extract model or data +bool integrated # Extract integrated spectra? +bool unblend # Correct for spectra blending +bool clean # Correct for bad pixels +int nreplace # Maximum number pixels replaced +real sigma_cut # Threshold for replacing bad pixels +int model # Model type: gauss5, profile + +bool ex_spectra +int nlines +int nspectra +pointer ms, im_in, im_out + +int clgeti(), ms_model_id(), clgranges() +bool clgetb() +real clgetr() +pointer msmap(), immap() + +begin + # Access input and output files. + call clgstr ("image", image, SZ_FNAME) + ms = msmap (image, READ_ONLY, 0) + im_in = immap (image, READ_ONLY, 0) + call clgstr ("output", output, SZ_FNAME) + im_out = immap (output, NEW_IMAGE, 0) + + # Determine extraction limits. + lower = clgetr ("lower") + upper = clgetr ("upper") + nlines = clgranges ("lines", 1, IM_LEN(im_in, 2), lines, MAX_RANGES) + nspectra = clgranges ("spectra", 1, MS_NSPECTRA(ms), spectra, + MAX_RANGES) + + # Determine type of extraction. + ex_spectra = TRUE + ex_model = clgetb ("ex_model") + integrated = clgetb ("integrated") + + # Determine whether to clean data spectra and the cleaning parameters. + clean = clgetb ("clean") + if (clean) { + nreplace = clgeti ("nreplace") + sigma_cut = clgetr ("sigma_cut") + } else + nreplace = 0 + + # Determine whether to apply blending correction. + if (!ex_model) + unblend = clgetb ("unblend") + + # Set type of model to be used. If a blending correction is desired + # the model must GAUSS5 otherwise the user selects the model. + model = NONE + if (unblend) + model = GAUSS5 + else if (ex_model || clean) + model = ms_model_id ("model") + + # Set verbose output. + call ex_set_verbose (clgetb ("verbose")) + call ex_prnt1 (MS_IMAGE(ms), output) + + # Set image header for output extraction image file. + IM_NDIM(im_out) = 3 + if (integrated) + IM_LEN(im_out, 1) = 1 + else + IM_LEN(im_out, 1) = nint (upper - lower + 1) + IM_LEN(im_out, 2) = nlines + IM_LEN(im_out, 3) = nspectra + IM_PIXTYPE(im_out) = TY_REAL + call strcpy (IM_TITLE(im_in), IM_TITLE(im_out), SZ_IMTITLE) + + # Select extraction procedure based on model. + switch (model) { + case GAUSS5: + call set_fit_and_clean (clgeti ("niterate"), nreplace, sigma_cut, + clgeti ("fit_type"), ex_model) + call ex_gauss5 (ms, im_in, im_out, spectra, lines, lower, upper, + ex_spectra, ex_model, integrated) + case SMOOTH: + call set_fit_smooth (nreplace, sigma_cut) + call ex_smooth (ms, im_in, im_out, spectra, lines, lower, upper, + ex_spectra, ex_model, integrated) + default: + call ex_strip (ms, im_in, im_out, spectra, lines, lower, upper, + ex_spectra, ex_model, integrated) + } + + # Close files. + call imunmap (im_in) + call imunmap (im_out) + call msunmap (ms) +end diff --git a/noao/twodspec/multispec/t_mslist.x b/noao/twodspec/multispec/t_mslist.x new file mode 100644 index 00000000..e21d685e --- /dev/null +++ b/noao/twodspec/multispec/t_mslist.x @@ -0,0 +1,312 @@ +include <fset.h> +include "ms.h" + +# T_MS_LIST -- Print general MULTISPEC database information. + +procedure t_ms_list () + +char image[SZ_FNAME] +char keyword[SZ_LINE] +bool titles + +int ms_id +pointer ms + +bool clgetb(), streq() +int ms_db_id() +pointer msmap() + +begin + call fseti (STDOUT, F_FLUSHNL, YES) + + # Get task parameters. + call clgstr ("image", image, SZ_FNAME) + ms = msmap (image, READ_ONLY, 0) + call clgstr ("keyword", keyword, SZ_LINE) + titles = clgetb ("titles") + + # Check for special keywords. + if (streq (keyword, "gauss5")) { + call g5_list (ms, keyword, titles) + + # Keyword is one of the database record names. Convert to a + # MULTISPEC id and switch to appropriate listing routine. + } else { + ms_id = ms_db_id (ms, keyword) + switch (ms_id) { + case HDR: + call hdr_list (ms, keyword, titles) + case COMMENTS: + call com_list (ms, keyword, titles) + case SAMPLE: + call sam_list (ms, keyword, titles) + case I0, X0, S0, S1, S2: + call par_list (ms, ms_id, keyword, titles) + case X0_FIT, S0_FIT, S1_FIT, S2_FIT: + call fit_list(ms, ms_id, keyword, titles) + } + } + + call msunmap (ms) +end + + +# HDR_LIST - List the contents of the MULTISPEC database header + +procedure hdr_list (ms, keyword, titles) + +pointer ms # MULTISPEC data structure +char keyword[ARB] # List keyword +bool titles # Print titles? + +begin + call printf ("Image: %s\n") + call pargstr (MS_IMAGE(ms)) + call printf ("Keyword: %s\n") + call pargstr (keyword) + call printf ("Title: %s\n") + call pargstr (MS_TITLE(ms)) + call printf ("Number of spectra: %d\n") + call pargi (MS_NSPECTRA(ms)) + call printf ("Number of sample image lines: %d\n") + call pargi (MS_NSAMPLES(ms)) + call printf ("Image size: %d x %d\n") + call pargi (MS_LEN(ms, 1)) + call pargi (MS_LEN(ms, 2)) +end + +procedure com_list (ms, keyword, titles) + +pointer ms # MULTISPEC data structure +char keyword[ARB] # List keyword +bool titles # Print titles? +int i + +begin + if (titles) { + call printf ("Image: %s\n") + call pargstr (MS_IMAGE(ms)) + call printf ("Keyword: %s\n") + call pargstr (keyword) + call printf ("Comments:\n") + } + + for (i=1; (i <= SZ_MS_COMMENTS) && (COMMENT(ms, i) != EOS); i=i+1) + call putchar (COMMENT(ms, i)) +end + + +# SAM_LIST -- List the sample image lines. + +procedure sam_list (ms, keyword, titles) + +pointer ms # MULTISPEC data structure +char keyword[ARB] # List keyword +bool titles # Print titles? +int i + +begin + if (titles) { + call printf ("Image: %s\n") + call pargstr (MS_IMAGE(ms)) + call printf ("Keyword: %s\n") + call pargstr (keyword) + call printf ("Sample Image Lines:\n") + } + + do i = 1, MS_NSAMPLES(ms) { + call printf ("%8d\n") + call pargi (LINE(ms, i)) + } +end + + +# PAR_LIST -- Print MULTISPEC profile parameters. +# +# This procedure does some CLIO. + +procedure par_list (ms, ms_id, keyword, titles) + +pointer ms # MULTISPEC data structure +int ms_id # MULTISPEC parameter id +char keyword[ARB] # List keyword +bool titles # Print titles? + +int lines[3, MAX_RANGES], spectra[3, MAX_RANGES] +int i, nsamples, sample, spectrum +pointer sp, samples + +int clgranges(), get_next_number(), get_sample_lines() + +begin + if ((MS_NSAMPLES(ms) == 0) || (MS_NSPECTRA(ms) == 0)) + return + + # Get desired image lines and spectra to be listed. + i = clgranges ("lines", 1, MS_LEN(ms, 2), lines, MAX_RANGES) + i = clgranges ("spectra", 1, MS_NSPECTRA(ms), spectra, MAX_RANGES) + + # Convert image lines to sample lines. + call smark (sp) + call salloc (samples, MS_NSAMPLES(ms), TY_INT) + nsamples = get_sample_lines (ms, lines, Memi[samples]) + + # Print header titles if needed. + if (titles) { + call printf ("Image: %s\n") + call pargstr (MS_IMAGE(ms)) + call printf ("Keyword: %s\n") + call pargstr (keyword) + call printf ("%8s %8s %8s\n") + call pargstr ("Line") + call pargstr ("Spectrum") + call pargstr (NAME(ms, ms_id)) + } + + # For each sample line get the parameter values for the selected + # parameter and list those for the selected spectra. + do i = 1, nsamples { + sample = Memi[samples + i - 1] + + call msgparam (ms, ms_id, sample) + + spectrum = 0 + while (get_next_number (spectra, spectrum) != EOF) { + call printf ("%8d %8d %8.3g\n") + call pargi (LINE(ms, sample)) + call pargi (spectrum) + call pargr (PARAMETER(ms, ms_id, spectrum)) + } + } + + call sfree (sp) +end + + +# FIT_LIST -- Print MULTISPEC fit. +# +# This procedure does CLIO. + +procedure fit_list (ms, ms_id, keyword, titles) + +pointer ms # MULTISPEC data structure +int ms_id # MULTISPEC parameter id +char keyword[ARB] # List keyword +bool titles # Print header titles? + +int lines[3, MAX_RANGES] +int spectra[3, MAX_RANGES] + +int i, line, spectrum + +real cveval() +int clgranges(), get_next_number() + +begin + if (MS_NSPECTRA(ms) == 0) + return + + # Get the image lines at which to evaluate the function and + # the spectra to be listed. + + i = clgranges ("lines", 1, MS_LEN(ms, 2), lines, MAX_RANGES) + i = clgranges ("spectra", 1, MS_NSPECTRA(ms), spectra, MAX_RANGES) + + # Get the fits. + call msgfits (ms, ms_id) + + # Print header titles if needed. + if (titles) { + call printf ("Image: %s\n") + call pargstr (MS_IMAGE(ms)) + call printf ("Keyword: %s\n") + call pargstr (keyword) + call printf ("%8s %8s %8s\n") + call pargstr ("Line") + call pargstr ("Spectrum") + call pargstr (NAME(ms, ms_id)) + } + + # For each selected image line evalute the functions for the + # selected spectra and print the values. + + line = 0 + while (get_next_number (lines, line) != EOF) { + spectrum = 0 + while (get_next_number (spectra, spectrum) != EOF) { + call printf ("%8d %8d %8.3g\n") + call pargi (line) + call pargi (spectrum) + call pargr (cveval (CV(ms, ms_id, spectrum), real (line))) + } + } +end + + +# G5_LIST -- Print MULTISPEC model gauss5 profile parameters. +# +# This procedure does CLIO. + +procedure g5_list (ms, keyword, titles) + +pointer ms # MULTISPEC data structure +char keyword[ARB] # List keyword +bool titles # Print header titles? + +int lines[3, MAX_RANGES], spectra[3, MAX_RANGES] +int i, nsamples, sample, spectrum +pointer sp, samples + +int clgranges(), get_next_number(), get_sample_lines() + +begin + if ((MS_NSAMPLES(ms) == 0) || (MS_NSPECTRA(ms) == 0)) + return + + # Get desired image lines and spectra to be listed. + i = clgranges ("lines", 1, MS_LEN(ms, 2), lines, MAX_RANGES) + i = clgranges ("spectra", 1, MS_NSPECTRA(ms), spectra, MAX_RANGES) + + # Convert image lines to sample lines. + call smark (sp) + call salloc (samples, MS_NSAMPLES(ms), TY_INT) + nsamples = get_sample_lines (ms, lines, Memi[samples]) + + # Print header titles if needed. + if (titles) { + call printf ("Image: %s\n") + call pargstr (MS_IMAGE(ms)) + call printf ("Keyword: %s\n") + call pargstr (keyword) + call printf ("%8s %8s %8s %8s %8s %8s %8s\n") + call pargstr ("Line") + call pargstr ("Spectrum") + call pargstr (NAME (ms, X0)) + call pargstr (NAME (ms, I0)) + call pargstr (NAME (ms, S0)) + call pargstr (NAME (ms, S1)) + call pargstr (NAME (ms, S2)) + } + + # For each sample line get the GAUSS5 values and list for the + # selected spectra. + do i = 1, nsamples { + sample = Memi[samples + i - 1] + + call msggauss5 (ms, sample) + + spectrum = 0 + while (get_next_number (spectra, spectrum) != EOF) { + call printf ("%8d %8d %8.3g %8.3g %8.3g %8.3g %8.3g\n") + call pargi (LINE(ms, sample)) + call pargi (spectrum) + call pargr (PARAMETER(ms, X0, spectrum)) + call pargr (PARAMETER(ms, I0, spectrum)) + call pargr (PARAMETER(ms, S0, spectrum)) + call pargr (PARAMETER(ms, S1, spectrum)) + call pargr (PARAMETER(ms, S2, spectrum)) + } + } + + call sfree (sp) +end diff --git a/noao/twodspec/multispec/t_msset.x b/noao/twodspec/multispec/t_msset.x new file mode 100644 index 00000000..81d94f0c --- /dev/null +++ b/noao/twodspec/multispec/t_msset.x @@ -0,0 +1,189 @@ +include "ms.h" + +# T_MS_SET -- Set profile parameters in database. + +procedure t_ms_set () + +char image[SZ_FNAME] +char keyword[SZ_LINE] + +char comment[SZ_LINE] +int i, nspectra, ms_id +pointer ms + +bool streq(), clgetb() +int clscan(), nscan(), ms_db_id() +pointer msmap() + +begin + # Get the task parameters and access the database. + call clgstr ("image", image, SZ_FNAME) + ms = msmap (image, READ_WRITE, 0) + call clgstr ("keyword", keyword, SZ_LINE) + + # Decode the keyword for the desired database quantity. + if (streq (keyword, "nspectra")) { + # Set the value of MS_NSPECTRA in the MULTISPEC header record. + if (clgetb ("read_list")) + i = clscan ("list") + else + i = clscan ("value") + call gargi (nspectra) + if (nscan () != 1) + call error (MS_ERROR, "Bad parameter value") + + # It is an error to attempt to change the value previously set. + if (MS_NSPECTRA(ms) == 0) + MS_NSPECTRA(ms) = nspectra + else if (MS_NSPECTRA(ms) != nspectra) + call error (MS_ERROR, "Attempt to change number of spectra") + } else { + # Keyword is one of the database record names. Convert to + # a MULTISPEC parameter ID and call the appropriate procedure. + + ms_id = ms_db_id (ms, keyword) + switch (ms_id) { + case COMMENTS: + call com_set (ms, comment) + case I0, X0, S0, S1, S2: + call par_set (ms, ms_id, comment) + } + } + + # Finish up. + call msphdr (ms) + call msunmap (ms) +end + + +# COM_SET -- Add a comment to the MULTISPEC database comment block. +# +# This procedure does CLIO. + +procedure com_set (ms, comment) + +pointer ms # MULTISPEC data structure +char comment[SZ_LINE] # Input comment buffer. + +int i + +bool clgetb() +int clscan() + +begin + # Desire whether to use list input or CL parameter input. + if (clgetb ("read_list")) { + # Read a list of comment strings. + while (clscan ("list") != EOF) { + call gargstr (comment, SZ_LINE) + call history (ms, comment) + } + } else { + # Read a comment line from the parameter "value". + i = clscan ("value") + call gargstr (comment, SZ_LINE) + call history (ms, comment) + } +end + + +# PAR_SET -- Set the values of the model parameters. +# +# This procedure does CLIO. + +procedure par_set (ms, ms_id, comment) + +pointer ms # MULTISPEC data structure +int ms_id # MULTISPEC ID +char comment[SZ_LINE] # Comment buffer + +int i, line, nsamples, sample, last_sample, spectrum +int lines[3, MAX_RANGES], spectra[3, MAX_RANGES] +real value +pointer sp, samples + +int clscan(), nscan(), clgranges(), get_next_number() +int get_sample_line(), get_sample_lines() +bool dbaccess(), clgetb() + +begin + if ((MS_NSAMPLES(ms) == 0) || (MS_NSPECTRA(ms) == 0)) + return + + # Enter the parameter in the database if necessary. + if (!dbaccess (MS_DB(ms), NAME(ms, ms_id))) + call dbenter (MS_DB(ms), NAME(ms, ms_id), + MS_NSPECTRA(ms) * SZ_REAL, MS_NSAMPLES(ms)) + + # Determine input source. + if (clgetb ("read_list")) { + # Read values from a list. + last_sample = 0 + while (clscan ("list") != EOF) { + + # Get line, spectrum, and value from the list. + call gargi (line) + call gargi (spectrum) + call gargr (value) + + # Check that the data is valid otherwise go to next input. + if (nscan () != 3) + next + if ((spectrum < 1) || (spectrum > MS_NSPECTRA(ms))) + next + + # If the last sample is not the same as the previous sample + # flush the last parameter values if the last sample is not + # zero and get the next line of parameter values. + + sample = get_sample_line (ms, line) + if (sample != last_sample) { + if (last_sample != 0) + call mspparam (ms, ms_id, last_sample) + call msgparam (ms, ms_id, sample) + last_sample = sample + } + + # Set the parameter value. + PARAMETER(ms, ms_id, spectrum) = value + } + + # Flush the last line of parameter values. + call mspparam (ms, ms_id, last_sample) + + } else { + # Set the parameter values for the selected lines and spectra + # to the CL parameter "value". + + i = clgranges ("lines", 1, MS_LEN(ms, 2), lines, MAX_RANGES) + i = clgranges ("spectra", 1, MS_NSPECTRA(ms), spectra, MAX_RANGES) + i = clscan ("value") + + # Convert the image lines to sample lines. + call smark (sp) + call salloc (samples, MS_NSAMPLES(ms), TY_INT) + nsamples = get_sample_lines (ms, lines, Memi[samples]) + + # Check that the parameter value is a real number. + call gargr (value) + if (nscan () != 1) + call error (MS_ERROR, "Bad parameter value") + + # Go through the selected sample lines and spectra setting the + # parameter value. + + do i = 1, nsamples { + sample = Memi[samples + i - 1] + call msgparam (ms, ms_id, sample) + spectrum = 0 + while (get_next_number (spectra, spectrum) != EOF) + PARAMETER (ms, ms_id, spectrum) = value + call mspparam (ms, ms_id, sample) + } + } + + # Add a history comment. + call sprintf (comment, SZ_LINE, "Values of parameter %s set.") + call pargstr (NAME(ms, ms_id)) + call history (ms, comment) +end diff --git a/noao/twodspec/multispec/t_newextract.x b/noao/twodspec/multispec/t_newextract.x new file mode 100644 index 00000000..0e695222 --- /dev/null +++ b/noao/twodspec/multispec/t_newextract.x @@ -0,0 +1,99 @@ +include <imhdr.h> +include "ms.h" + +# T_NEW_EXTRACTION -- Create a new extraction database. +# +# This is the first step in using the MULTISPEC package. The new database +# may be created from scratch or intialized from an template image. + +procedure t_new_extraction () + +# Task parameters: +char image[SZ_FNAME] # Multi-spectra image +char template[SZ_FNAME] # Template image +int samples[3, MAX_RANGES] # Sample line range array + +char comment[SZ_LINE] +char database[SZ_FNAME], old_database[SZ_FNAME] +pointer im, ms + +bool strne() +int clgranges(), expand_ranges() +pointer immap(), msmap() + +begin + # Get database and image name. Map the image and check that + # it is two dimensional. + call clgstr ("image", image, SZ_FNAME) + im = immap (image, READ_ONLY, 0) + if (IM_NDIM(im) != 2) + call error (MS_ERROR, "Image file must be two dimensional.") + + # Get the template image name. + call clgstr ("template", template, SZ_FNAME) + + if (strne (template, "")) { + # If a template is given then map the template and check + # that the new image dimensions agree with the old dimensions. + + ms = msmap (template, READ_ONLY, 0) + if ((MS_LEN(ms, 1) != IM_LEN(im, 1)) || + (MS_LEN(ms, 2) != IM_LEN(im, 2))) + call error (MS_ERROR, + "New image size does not agree with the old image size.") + call msunmap (ms) + + # Copy the old database. Map the new database and clear the + # the old comments before adding a new comment. + + call sprintf (database, SZ_FNAME, "%s.db") + call pargstr (image) + call sprintf (old_database, SZ_FNAME, "%s.db") + call pargstr (template) + call fcopy (old_database, database) + + ms = msmap (image, READ_WRITE, 0) + COMMENT(ms, 1) = EOS + call sprintf (comment, SZ_LINE, + "Database initialized from the template image %s.") + call pargstr (template) + call history (ms, comment) + + } else { + # For a new database initialize the header parameters. + ms = msmap (image, NEW_FILE, MS_DB_ENTRIES) + MS_LEN(ms, 1) = IM_LEN(im, 1) + MS_LEN(ms, 2) = IM_LEN(im, 2) + MS_NSPECTRA(ms) = 0 + + # Get the sample line ranges and set the number of sample lines + # in the database header. + MS_NSAMPLES(ms) = clgranges ("sample_lines", 1, MS_LEN (ms, 2), + samples, MAX_RANGES) + + # Make an entry in the database for the sample lines and then + # access the entry in order to allocate memory for the sample + # line array. + call dbenter (MS_DB(ms), NAME(ms, SAMPLE), MS_NSAMPLES(ms)*SZ_INT,1) + call msgsample (ms) + + # Expand the sample line range array into the sample line array. + # Then put the sample line array in the database. + MS_NSAMPLES(ms) = expand_ranges (samples, LINE(ms, 1), + MS_NSAMPLES(ms)) + call mspsample (ms) + + # Add a history line. + call history (ms, "New MULTISPEC database created.") + } + + # Set the image name and image title in the database. + call strcpy (image, MS_IMAGE(ms), SZ_MS_IMAGE) + call strcpy (IM_TITLE(im), MS_TITLE(ms), SZ_MS_TITLE) + + # Close image and database. Write the database header record before + # closing the database. + call imunmap (im) + call msphdr (ms) + call msunmap (ms) +end diff --git a/noao/twodspec/multispec/t_newimage.x b/noao/twodspec/multispec/t_newimage.x new file mode 100644 index 00000000..c74ce22a --- /dev/null +++ b/noao/twodspec/multispec/t_newimage.x @@ -0,0 +1,97 @@ +include <imhdr.h> +include "ms.h" + +# T_NEW_IMAGE -- General MULTISPEC extraction task. +# +# The general task parameters are obtained and the desired extraction +# procedure is called. The input database and image are accessed and +# the output image is created. + +procedure t_new_image () + +# User parameters: +char image[SZ_FNAME] # MULTISPEC database +char output[SZ_FNAME] # Output image file +real lower # Lower limit of strip +real upper # Upper limit of strip +int lines[3, MAX_RANGES] # Lines to be extracted +int spectra[3, MAX_RANGES] # Spectra to be extracted +bool ex_model # Extract model or data +bool clean # Correct for bad pixels +int nreplace # Maximum number of bad pixels replaced +real sigma_cut # Threshold for replacing bad pixels +int model # Model type: gauss5, profile + +bool ex_spectra # Extract spectra or image line +bool integrated # Extract integrated spectra or strip +int nlines +pointer ms, im_in, im_out + +int clgeti(), ms_model_id(), clgranges() +bool clgetb() +real clgetr() +pointer msmap(), immap() + +begin + # Access input and output files. + call clgstr ("image", image, SZ_FNAME) + ms = msmap (image, READ_ONLY, 0) + im_in = immap (image, READ_ONLY, 0) + call clgstr ("output", output, SZ_FNAME) + im_out = immap (output, NEW_IMAGE, 0) + + # Determine extraction limits. + nlines = clgranges ("lines", 1, IM_LEN(im_in, 2), lines, MAX_RANGES) + lower = clgetr ("lower") + upper = clgetr ("upper") + + # Determine type of extraction. + ex_spectra = FALSE + ex_model = clgetb ("ex_model") + integrated = FALSE + + # Determine whether to clean data lines and the cleaning parameters. + clean = clgetb ("clean") + if (clean) { + nreplace = clgeti ("nreplace") + sigma_cut = clgetr ("sigma_cut") + } else + nreplace = 0 + + # Set type of model to be used. + model = NONE + if (ex_model || clean) + model = ms_model_id ("model") + + # Set verbose output. + call ex_set_verbose (clgetb ("verbose")) + call ex_prnt1 (image, output) + + # Set image header for output extraction image file. + IM_NDIM(im_out) = IM_NDIM(im_in) + IM_LEN(im_out, 1) = IM_LEN(im_in, 1) + IM_LEN(im_out, 2) = nlines + IM_PIXTYPE(im_out) = IM_PIXTYPE(im_in) + call strcpy (IM_TITLE(im_in), IM_TITLE(im_out), SZ_IMTITLE) + + # Select extraction procedure based on model. + switch (model) { + case GAUSS5: + call set_fit_and_clean (clgeti ("niterate"), nreplace, + sigma_cut, clgeti ("fit_type"), ex_model) + call ex_gauss5 (ms, im_in, im_out, spectra, lines, lower, upper, + ex_spectra, ex_model, integrated) + case SMOOTH: + call set_fit_smooth (nreplace, sigma_cut) + call ex_smooth (ms, im_in, im_out, spectra, lines, lower, upper, + ex_spectra, ex_model, integrated) + default: + call ex_strip (ms, im_in, im_out, spectra, lines, lower, upper, + ex_spectra, ex_model, integrated) + } + + # Close files. + call imunmap (im_in) + call imunmap (im_out) + call msunmap (ms) +end diff --git a/noao/twodspec/multispec/unblend.x b/noao/twodspec/multispec/unblend.x new file mode 100644 index 00000000..707c6b49 --- /dev/null +++ b/noao/twodspec/multispec/unblend.x @@ -0,0 +1,38 @@ +include "ms.h" + +# UNBLEND -- Create unblended data profiles from a blended data line. +# +# For each point in each spectrum profile determine the corresponding column +# in the data line from the ranges array. If the model is non-zero then the +# data profile value for that spectrum is a fraction of the total data value +# at that point given by the fraction of that model profile to the total +# model at that point. + +procedure unblend (data, data_profiles, model, model_profiles, ranges, + len_line, len_profile, nspectra) + +real data[len_line] # Data line to be unblended +real data_profiles[len_profile, nspectra] # Output data profiles +real model[len_line] # Model line +real model_profiles[len_profile, nspectra] # Model profiles +real ranges[nspectra, LEN_RANGES] # Ranges for model profiles +int len_line # Length of data/model line +int len_profile # Length of each profile +int nspectra # Number of spectra + +int i, x, spectrum + +begin + do spectrum = 1, nspectra { + do i = 1, len_profile { + x = ranges[spectrum, X_START] + i - 1 + if ((x >= 1) && (x <= len_line)) { + if (model[x] > 0.) + data_profiles[i, spectrum] = + data[x] * model_profiles[i, spectrum] / model[x] + else + data_profiles[i, spectrum] = data[x] + } + } + } +end diff --git a/noao/twodspec/multispec/x_multispec.x b/noao/twodspec/multispec/x_multispec.x new file mode 100644 index 00000000..accdb148 --- /dev/null +++ b/noao/twodspec/multispec/x_multispec.x @@ -0,0 +1,10 @@ +task newextraction = t_new_extraction, + findpeaks = t_find_peaks, + mslist = t_ms_list, + msset = t_ms_set, + fitfunction = t_fit_function, + modellist = t_model_list, + fitgauss5 = t_fit_gauss5, + msextract = t_msextract, + newimage = t_new_image, + msplot |