include include include define MAX_NR_BEAMS 100 # Max number of instrument apertures define KEY "noao$lib/scr/flatfit.key" define PROMPT "flatfit cursor options" # Definitions for Plotting modes define PLT_FIT 1 # Plot the direct fit define PLT_ERR 2 # Plot the errors in the fit define PLT_LIN 3 # Plot the fit minus the linear part # T_FLATFIT -- Accumulate a series of flat field spectra to produce # a grand sum and fit a function to the sum to produce a normalized # flat containing the pixel-to-pixel variations. # User interaction via the graphics cursor is provided. The following # cursor commands are recognized: # # ? - Screen help # / - Status line help # e - Plot in residual error mode # f - Plot in fit to the data mode # o - Change order of fit # l - Change lower rejection sigma # u - Change upper rejection sigma # r - Reset fit to include rejected pixels # s - Change upper and lower sigmas to same value # i - Iterate again # n - Iterate N times # q - Quit and accept current solution (also RETURN) # procedure t_flatfit () pointer image # Image name to be fit pointer images # Image name to be fit pointer ofile # Output image file name int function # Fitting function int order # Order of fitting function int recs # Spectral record numbers int root, nrecs # CL and ranges flags real expo # Exposure time real dtime # Deadtime real power # Power law coin. correction real lower # Lower rejection sigma real upper # Upper threshold sigma int ngrow # Rejection radius real div_min # Division min for option RESP bool coincidence, all # Apply coincidence correction bool interact # Interactive levels pointer bstat # Status of each aperture pointer npts # Length of spectrum pointer esum # Accumulated exposure time pointer accum # Pointers to beam accumulators pointer title int ccmode, beam int niter int i pointer sp, str, im int clgeti(), clgwrd(), clpopni(), imgeti() int get_next_image(), decode_ranges() real clgetr(), imgetr() bool clgetb() pointer immap() begin call smark (sp) call salloc (image, SZ_FNAME, TY_CHAR) call salloc (images, MAX_NR_BEAMS, TY_POINTER) call salloc (ofile, SZ_FNAME, TY_CHAR) call salloc (recs, 300, TY_INT) call salloc (bstat, MAX_NR_BEAMS, TY_INT) call salloc (npts, MAX_NR_BEAMS, TY_INT) call salloc (esum, MAX_NR_BEAMS, TY_REAL) call salloc (accum, MAX_NR_BEAMS, TY_POINTER) call salloc (title, MAX_NR_BEAMS, TY_POINTER) call salloc (str, SZ_LINE, TY_CHAR) call amovki (NULL, Memi[images], MAX_NR_BEAMS) # Get task parameters. root = clpopni ("input") # Get input record numbers call clgstr ("records", Memc[str], SZ_LINE) if (decode_ranges (Memc[str], Memi[recs], 100, nrecs) == ERR) call error (0, "Bad range specification") call clgstr ("output", Memc[ofile], SZ_LINE) call clgcurfit ("function", "order", function, order) lower = clgetr ("lower") upper = clgetr ("upper") ngrow = clgeti ("ngrow") div_min = clgetr ("div_min") # Determine desired level of activity interact = clgetb ("interact") all = clgetb ("all_interact") niter = clgeti ("niter") # Is coincidence correction to be performed? coincidence = clgetb ("coincor") if (coincidence) { ccmode = clgwrd ("ccmode", Memc[str], SZ_LINE, ",photo,iids,") dtime = clgetr ("deadtime") power = clgetr ("power") } call reset_next_image () # Clear all beam status flags call amovki (INDEFI, Memi[bstat], MAX_NR_BEAMS) call aclrr (Memr[esum], MAX_NR_BEAMS) call printf ("Accumulating spectra --\n") call flush (STDOUT) 10 while (get_next_image (root, Memi[recs], nrecs, Memc[image], SZ_FNAME) != EOF) { iferr (im = immap (Memc[image], READ_ONLY, 0)) { call eprintf ("Header info not available for [%s]\n") call pargstr (Memc[image]) goto 10 } iferr (beam = imgeti (im, "BEAM-NUM")) beam = 0 if (beam < 0 || beam > MAX_NR_BEAMS-1) call error (0, "Invalid aperture number") iferr (expo = imgetr (im, "EXPOSURE")) iferr (expo = imgetr (im, "ITIME")) iferr (expo = imgetr (im, "EXPTIME")) expo = 1 # Add spectrum into accumulator if (IS_INDEFI (Memi[bstat+beam])) { Memi[npts+beam] = IM_LEN (im,1) call salloc (Memi[accum+beam], Memi[npts+beam], TY_REAL) call aclrr (Memr[Memi[accum+beam]], Memi[npts+beam]) Memi[bstat+beam] = 0 call salloc (Memi[title+beam], SZ_LINE, TY_CHAR) call strcpy (IM_TITLE(im), Memc[Memi[title+beam]], SZ_LINE) } call ff_accum_spec (im, Memi[npts], expo, Memi[bstat], beam+1, Memi[accum], Memr[esum], coincidence, ccmode, dtime, power, Memi[title]) call printf ("[%s] added to aperture %1d\n") call pargstr (Memc[image]) call pargi (beam) call flush (STDOUT) if (Memi[images+beam] == NULL) call salloc (Memi[images+beam], SZ_FNAME, TY_CHAR) call strcpy (Memc[image], Memc[Memi[images+beam]], SZ_FNAME) call imunmap (im) } # Review all apertures containing data and perform fits. # Act interactively if desired do i = 0, MAX_NR_BEAMS-1 { if (!IS_INDEFI (Memi[bstat+i])) { call fit_spec (Memr[Memi[accum+i]], Memi[npts+i], Memr[esum+i], interact, function, order, niter, lower, upper, ngrow, div_min, i) if (interact & !all) interact = false call wrt_fit_spec (Memc[Memi[images+i]], Memr[Memi[accum+i]], Memr[esum+i], Memc[ofile], i, Memc[Memi[title+i]], Memi[npts+i], order) } } call sfree (sp) call clpcls (root) end # ACCUM_SPEC -- Accumulate spectra by beams procedure ff_accum_spec (im, len, expo, beam_stat, beam, accum, expo_sum, coincidence, ccmode, dtime, power, title) pointer im, accum[ARB], title[ARB] real expo, expo_sum[ARB] int beam_stat[ARB], beam, len[ARB] bool coincidence int ccmode real dtime, power int npts, co_flag, imgeti() pointer pix pointer imgl1r() begin npts = IM_LEN (im, 1) # Map pixels and optionally correct for coincidence pix = imgl1r (im) if (coincidence) { iferr (co_flag = imgeti (im, "CO-FLAG")) co_flag = -1 if (co_flag < 1) { call coincor (Memr[pix], Memr[pix], npts, expo, co_flag, dtime, power, ccmode) } } # Add in the current data npts = min (npts, len[beam]) call aaddr (Memr[pix], Memr[accum[beam]], Memr[accum[beam]], npts) beam_stat[beam] = beam_stat[beam] + 1 expo_sum [beam] = expo_sum [beam] + expo end # WRT_FIT_SPEC -- Write out normalized spectrum procedure wrt_fit_spec (image, accum, expo_sum, ofile, beam, title, npts, order) char image[SZ_FNAME] real accum[ARB], expo_sum int beam, npts, order char ofile[SZ_FNAME] char title[SZ_LINE] char output[SZ_FNAME], temp[SZ_LINE] pointer im, imnew, newpix pointer immap(), impl1r() int strlen() begin im = immap (image, READ_ONLY, 0) 10 call strcpy (ofile, output, SZ_FNAME) call sprintf (output[strlen (output) + 1], SZ_FNAME, ".%04d") call pargi (beam) # Create new image with a user area # If an error occurs, ask user for another name to try # since many open errors result from trying to overwrite an # existing image. iferr (imnew = immap (output, NEW_COPY, im)) { call eprintf ("Cannot create [%s] -- Already exists??\07\n") call pargstr (output) call clgstr ("output", ofile, SZ_FNAME) go to 10 } call strcpy ("Normalized flat:", temp, SZ_LINE) call sprintf (temp[strlen (temp) + 1], SZ_LINE, "%s") call pargstr (title) call strcpy (temp, IM_TITLE (imnew), SZ_LINE) IM_PIXTYPE (imnew) = TY_REAL newpix = impl1r (imnew) call amovr (accum, Memr[newpix], npts) call imaddr (imnew, "EXPOSURE", expo_sum) call imaddi (imnew, "QF-FLAG", order) call imunmap (im) call imunmap (imnew) call printf ("Fit for aperture %1d --> [%s]\n") call pargi (beam) call pargstr (output) call flush (STDOUT) end # FIT_SPEC -- Fit a line through the spectrum with user interaction procedure fit_spec (accum, npts, expo_sum, interact, function, order, niter, lower, upper, ngrow, div_min, beam) real accum[ARB], expo_sum bool interact int function, order, niter, ngrow, npts, beam real lower, upper, div_min int cc, key, gp, plt_mode int i, initer, sum_niter, newgraph real x1, y1, sigma, temp pointer sp, wts, x, y, cv bool first char gtitle[SZ_LINE], command[SZ_FNAME] int clgcur(), clgeti() pointer gopen() real clgetr(), cveval() data plt_mode/PLT_FIT/ begin # Perform initial fit call smark (sp) call salloc (wts, npts, TY_REAL) call salloc (x , npts, TY_REAL) call salloc (y , npts, TY_REAL) first = true if (!interact) { sum_niter = 0 do i = 1, niter call linefit (accum, npts, function, order, lower, upper, ngrow, cv, first, Memr[wts], Memr[x]) sum_niter = niter } else { gp = gopen ("stdgraph", NEW_FILE, STDGRAPH) call sprintf (gtitle, SZ_LINE, "Flat Field Sum - %f seconds ap:%1d") call pargr (expo_sum) call pargi (beam) key = 'r' repeat { switch (key) { case 'e': # Plot errors plt_mode = PLT_ERR newgraph = YES case 'f': # Plot fit plt_mode = PLT_FIT newgraph = YES case 'o': # Change order order = clgeti ("new_order") # Reinstate all pixels first = true newgraph = YES case 'l': # Change lower sigma lower = clgetr ("new_lower") newgraph = YES case 'u': # Change upper sigma upper = clgetr ("new_upper") newgraph = YES case 'r': # Reset fit parameters first = true newgraph = YES case 's': # Change both rejection sigmas lower = clgetr ("new_lower") upper = lower call clputr ("new_upper", upper) newgraph = YES case 'i': # Iterate again - Drop thru initer = 1 newgraph = YES case 'n': # Iterate n times initer = clgeti ("new_niter") newgraph = YES case 'q': # Quit break case '?': # Clear and help call gpagefile (gp, KEY, PROMPT) case '/': # Status line help call ff_sts_help case 'I': # Interrupt call fatal (0, "Interrupt") default: call printf ("\07\n") } if (newgraph == YES) { # Suppress an iteration if plot mode change requested if (key != 'e' && key != 'f') { if (first) { sum_niter = 0 initer = niter call cvfree (cv) } do i = 1, initer call linefit (accum, npts, function, order, lower, upper, ngrow, cv, first, Memr[wts], Memr[x]) sum_niter = sum_niter + initer } switch (plt_mode) { case PLT_FIT: call plot_fit (gp, accum, cv, function, order, npts, gtitle, Memr[wts], Memr[x], Memr[y], sigma) case PLT_ERR: call plot_fit_er (gp, accum, cv, function, order, npts, gtitle, Memr[wts], Memr[x], Memr[y], sigma) } newgraph = NO } } until (clgcur ("cursor",x1,y1,cc,key,command,SZ_FNAME) == EOF) call gclose (gp) } # Replace original data with the data/fit do i = 1, npts { temp = cveval (cv, real (i)) if (temp == 0.0) temp = max (temp, div_min) accum[i] = accum[i] / temp } call cvfree (cv) call sfree (sp) # Save iteration count for next time niter = sum_niter end # LINEFIT -- Fit desired function thru data procedure linefit (pix, npts, function, order, lower, upper, ngrow, cv, first, wts, x) real pix[ARB] # Data array to fit int npts # Elements in array int function # Type of fitting function int order # Order of fitting function real lower # Lower rejection threshold real upper # Upper rejection threshold int ngrow # Rejection growing radius pointer cv real wts[ARB] # Array weights real x[ARB] bool first int ier, i, nreject int reject() begin 10 if (first) { do i = 1, npts { x[i] = i wts[i] = 1.0 } # Initialize curve fitting. call cvinit (cv, function, order, 1., real (npts)) call cvfit (cv, x, pix, wts, npts, WTS_USER, ier) nreject = 0 first = false } # Do pixel rejection if desired. if ((lower > 0.) || (upper > 0.)) nreject = reject (cv, x, pix, wts, npts, lower, upper, ngrow) else nreject = 0 if (nreject == ERR) { call eprintf ("Cannot fit data -- too many points rejected??\n") call cvfree (cv) first = true go to 10 } end # REJECT -- Reject points with large residuals from the fit. # # The sigma of the input to the fit is calculated. The rejection thresholds # are set at -lower*sigma and upper*sigma. Points outside the rejection # thresholds are rejected from the fit and flaged by setting their # weights to zero. Finally, the remaining points are refit and a new # fit line evaluated. The number of points rejected is returned. int procedure reject (cv, x, y, w, npoints, lower, upper, ngrow) pointer cv # Curve descriptor real x[ARB] # Input ordinates real y[ARB] # Input data values real w[ARB] # Weights int npoints # Number of input points real lower # Lower rejection sigma real upper # Upper rejection sigma int ngrow # Rejection radius int i, j, n, i_min, i_max, nreject real sigma, residual, resid_min, resid_max real cveval() begin # Determine sigma of fit and set rejection limits. sigma = 0. n = 0 do i = 1, npoints { if (w[i] == 0.) next sigma = sigma + (y[i] - cveval (cv, x[i])) ** 2 n = n + 1 } sigma = sqrt (sigma / (n - 1)) resid_min = -lower * sigma resid_max = upper * sigma # Reject the residuals exceeding the rejection limits. nreject = 0 for (i = 1; i <= npoints; i = i + 1) { if (w[i] == 0.) next residual = y[i] - cveval (cv, x[i]) if ((residual < resid_min) || (residual > resid_max)) { i_min = max (1, i - ngrow) i_max = min (npoints, i + ngrow) # Reject points from the fit and flag them with zero weight. do j = i_min, i_max { call cvrject (cv, x[j], y[j], w[j]) w[j] = 0. nreject = nreject + 1 } i = i_max } } # Refit if points have been rejected. if (nreject > 0) { call cvsolve (cv, i) if (i != OK) return (ERR) } return (nreject) end # PLOT_FIT -- Plot the fit to the image line and data procedure plot_fit (gp, pix, cv, function, order, npts, gtitle, wts, xfit, yfit, sigma) int gp, npts, function, order real pix[ARB], wts[ARB], xfit[ARB], yfit[ARB] pointer cv real sigma char gtitle[SZ_LINE] real x1, x2 int i begin # Set up plot x1 = 1.0 x2 = npts call gseti (gp, G_NMINOR, 0) call gclear (gp) call gsview (gp, 0.15, 0.95, 0.20, 0.9) call gploto (gp, pix, npts, x1, x2, gtitle) # Now plot the fit do i = 1, npts xfit[i] = i call cvvector (cv, xfit, yfit, npts) call gvline (gp, yfit, npts, x1, x2) # Compute sigma and write it out call get_sigma (pix, yfit, wts, npts, sigma) call show_status (function, order, sigma, npts, wts) end # PLOT_FIT_ER -- Plot the error in the fit to the image line and data procedure plot_fit_er (gp, pix, cv, function, order, npts, gtitle, wts, xfit, yfit, sigma) int gp, npts, function, order real pix[ARB], wts[ARB], xfit[ARB], yfit[ARB] pointer cv real sigma char gtitle[SZ_LINE] real x1, x2, y[2] int i begin # Set up plot x1 = 1.0 x2 = npts y[1] = -0.0001 y[2] = +0.0001 call cvvector (cv, xfit, yfit, npts) # Compute percentage errors do i = 1, npts if (pix[i] != 0.0) yfit[i] = (pix[i] - yfit[i]) / pix[i] else yfit[i] = 0.0 call gseti (gp, G_NMINOR, 0) call gclear (gp) call gsview (gp, 0.15, 0.95, 0.20, 0.9) call gploto (gp, yfit, npts, x1, x2, "Flat field fractional error in fit") # Draw a zero error line call gline (gp, x1, y[1], x2, y[2]) # Compute sigma call get_sigma0 (yfit, wts, npts, sigma) call show_status (function, order, sigma, npts, wts) end # SHOW_STATUS -- Show the fit status on status line procedure show_status (function, order, sigma, npts, wts) int function, order, npts real sigma, wts[ARB] int i, nvals begin # Count non-rejected points nvals = 0 do i = 1, npts if (wts[i] != 0.0) nvals = nvals + 1 call printf ("Fit type: %s order: %2d rms: %6.3f") switch (function) { case LEGENDRE: call pargstr ("Legendre") case CHEBYSHEV: call pargstr ("Chebyshev") case SPLINE3: call pargstr ("Spline3") case SPLINE1: call pargstr ("Spline1") default: call pargstr ("???") } call pargi (order) call pargr (sigma) call printf (" points: %d out of %d") call pargi (nvals) call pargi (npts) call flush (STDOUT) end # GET_SIGMA -- Compute rms error between two vectors whose average difference # is zero. procedure get_sigma (y1, y2, wts, n, sigma) real y1[ARB], y2[ARB], wts[ARB], sigma int n int i, nval real sum begin sum = 0.0 nval = 0 do i = 1, n if (wts[i] != 0.0) { sum = sum + (y1[i] - y2[i]) ** 2 nval = nval + 1 } sigma = sqrt (sum / (nval-1)) return end # GET_SIGMA0 -- Compute rms error of a vector procedure get_sigma0 (y1, wts, n, sigma) real y1[ARB], wts[ARB], sigma int n int i, nval real sum begin sum = 0.0 nval = 0 do i = 1, n if (wts[i] != 0.0) { sum = sum + y1[i]**2 nval = nval + 1 } sigma = sqrt (sum / (nval-1)) return end # FF_STS_HELP -- Status line help for Flat Fit procedure ff_sts_help () int linenr, maxline data linenr/1/ data maxline/2/ begin switch (linenr) { case 1: call printf ("e=err plot f=data plot o=order l=lower sigma ") call printf ("u=upper sigma s=both sigmas") case 2: call printf ("r=incl reject i=iterate n=niterate q=quit ") call printf ("?=help /=linehelp =quit") } call flush (STDOUT) linenr = linenr + 1 if (linenr > maxline) linenr = 1 end