PRO xrt_dark_sub, index_in, image_in, index_out, image_out, $ dark_file=dark_file, force=force, $ verbose=verbose, quiet=quiet, $ qabort=qabort, qstop=qstop ; ========================================================================== ;+ ; PROJECT: ; Solar-B / XRT ; ; NAME: ; XRT_DARK_SUB ; ; CATEGORY: ; Data calibration ; ; PURPOSE: ; Subtract a dark current image from an XRT image. The dark image ; should be in FITS file format. The "/force" switch may be used ; to manipulate the dark to better match the data. ; ; CALLING SEQUENCE: ; XRT_DARK_SUB, index_in, image_in, index_out, image_out, ; dark_image=dark_image [,/force] [,/verbose] ; [,/quiet] [,qabort=qabort] [,/qstop] ; ; INPUTS: ; INDEX_IN - [Mandatory] (structure scalar) The index structure ; for the input image (e.g., "index" from output of ; "read_xrt.pro".) ; IMAGE_IN - [Mandatory] (number array, [Nx,Ny]) The input image ; data array. ; DARK_FILE - [Mandatory] (string scalar) The dark image (FITS file) ; that will be subtracted from the image. ; ; KEYWORDS: ; /FORCE - [Optional] (Boolean) If set, the program will try ; to change the dark to match the image. The following ; steps are performed, as necessary. ; a) Change summing to match. ; b) Use lower-left of dark if cannot match the actual ; CCD pixels of the image. ; c) Normalize to image exposure duration. ; /VERBOSE - [Optional] (Boolean) Print out extra information. ; Overrides "/quiet" (see Note #2). ; /QUIET - [Optional] (Boolean) Suppress messages (see Note #2). ; /QSTOP - [Optional] (Boolean) For debugging. ; ; OUTPUTS: ; INDEX_OUT - [Mandatory] (structure scalar) ; The updated index structure of the output image. ; IMAGE_OUT - [Mandatory] (float array, [Nx,Ny]) ; The dark-subtracted output image data array. ; QABORT - [Optional] (Boolean) Indicates that the program ; exited gracefully without completing. (Might be ; useful for calling programs.) ; 0: Program ran to completion. ; 1: Program aborted before completion. ; ; EXAMPLES: ; ; Straightforward usage: ; IDL> xrt_dark_sub, index_in, image_in, index_out, image_out, $ ; IDL> dark_file='XRT_dark.fits' ; ; If you want to use a dark that doesn't perfectly match the image: ; IDL> xrt_dark_sub, index_in, image_in, index_out, image_out, $ ; IDL> dark_file='XRT_dark.fits', /force ; ; Same as previous, but shut it up: ; IDL> xrt_dark_sub, index_in, image_in, index_out, image_out, $ ; IDL> dark_file='XRT_dark.fits', /force, /quiet ; ; ; COMMON BLOCKS: ; None. ; ; ; NOTES: ; ; 1) The "v2006-Nov-30" version does not allow CAL darks to be used. ; ; 2) There are three levels of verbosity. ; a) "verbose" = highest priority. All errors and messages are ; displayed. ("if q_vb") ; b) "quiet" = lower priority. No errors or messages are ; displayed. ("if q_qt") ; c) neither = lowest priority. All errors and some messages are ; displayed. ("if not q_qt") ; ; 3) The "index_out.HISTORY" is updated to reflect the ; dark subtraction. ; ; 4) The "v2006-Nov-30" version of this program does not make any ; adjustments for the CCD temperature, although it will reject ; a dark subtraction if the difference is too large. ; ; 5) The "v2006-Nov-30" version assumes that "image_in" has already ; had its bias (pedestal) subtracted. ; ; 6) As of 2007-Feb-14, the "v2006-Nov-30" version has been deprecated ; in the sense that it is not currently used by . It ; anticipated that this code may become useful for calibration ; analyses. ; ; ; CONTACT: ; ; Comments, feedback, and bug reports regarding this routine may be ; directed to this email address: ; xrt_manager ~at~ head.cfa.harvard.edu ; ; ; MODIFICATION HISTORY: ; progver = 'v2006-May-17' ;--- (P.R. Jibben) Written. progver = 'v2006-Nov-30' ;--- (MW) Systemic changes. ; ; ;- ;=========================================================================== ;=== Initial setup ==================================================== ;===== Track program runtime. t0 = systime(1) ;===== Initialize program constants. prognam='XRT_DARK_SUB' ;=== Image and dark must differ in temperature by less than this amount: temp_diff_threshold = 8. ;Degrees Kelvin ;=== Image and dark must differ in time by less than this amount: time_diff_threshold = 60d ;days ccd_bias = 35 ; [DN] for full-resolution pixels ;===== Set Booleans which control print statements. ;===== Keyword "verbose" overrules "quiet". q_vb = keyword_set(verbose) q_qt = keyword_set(quiet) and (not q_vb) ;===== Announce version of . if q_vb then box_message, 'XRT_DARK_SUB: Running ' + prognam + $ ' ' + progver + '.' ;===== Set some keyword Booleans. q_dkfil = keyword_set(dark_file) q_force = keyword_set(force) qstop = keyword_set(qstop) qabort = 0B ;===== Other useful stuff. ;=== First element is just a placeholder. hist_entry = '' ;===== Are there 4 parameters? if (n_params() ne 4) then begin if (not q_qt) then box_message, 'XRT_DARK_SUB: Requires 4 ' $ + 'parameters. Aborting...' qabort = 1B return endif ;=== Check "index_in" and "image_in" ================================== ;===== This block checks "index_in". if q_vb then print, 'XRT_DARK_SUB: Checking input "index_in"...' ;=== Check "index_in". if (datatype(index_in) ne 'STC') then begin if (not q_qt) then box_message, 'XRT_DARK_SUB: Input "index_in" ' $ + 'needs to be a structure from an XRT FITS header. Aborting...' qabort = 1B return endif if (n_elements(index_in) ne 1) then begin if (not q_qt) then box_message, 'XRT_DARK_SUB: Input "index_in" ' $ + 'needs to be a scalar. Aborting...' qabort = 1B return endif ;=== Check for necessary tags. if not required_tags(index_in, 'CAL_INFO,EC_IMTYP,CCD_TEMP,CHIP_SUM,' $ + 'EXPTIME,CCD_READ,DATE_OBS,RPOS_COL,RPOS_ROW,RSIZ_COL,' $ + 'RSIZ_ROW,CTIME,HISTORY', missing=missing) then begin if (not q_qt) then box_message, ['XRT_DARK_SUB: Input "index_in" ' $ + 'does not have these required tags:', $ ' ' + missing, ' Aborting...'] qabort = 1B return endif else begin img_cal = gt_tagval(index_in, /cal_info) ;Cal image? 0=no 1=yes img_typ = gt_tagval(index_in, /ec_imtyp) ;Type? 0=normal 1=dark img_tmp = gt_tagval(index_in, /ccd_tmpc) ;CCD temperature img_sum = gt_tagval(index_in, /platescl) ;CCD summing factor img_edi = gt_tagval(index_in, /ec_einde) ;Exposure duration index img_exp = gt_tagval(index_in, /exptime) ;Actual exposure duration img_prt = gt_tagval(index_in, /ccd_read) ;Read port 0=right 1=left img_tim = gt_tagval(index_in, /date_obs) ;Image time img_ctm = gt_tagval(index_in, /ctime) ;Image time readable img_x0 = gt_tagval(index_in, /rpos_col) ;ROI x-corner img_y0 = gt_tagval(index_in, /rpos_row) ;ROI y-corner img_nx0 = gt_tagval(index_in, /rsiz_col) ;ROI x-size img_ny0 = gt_tagval(index_in, /rsiz_row) ;ROI y-size endelse ;=== Check whether this image has already been dark-subtracted. previous = get_history(index_in, 'XRT_DARK_SUB', found=found) if found then begin if (not q_qt) then box_message, 'XRT_DARK_SUB: This image has ' $ + 'already been dark-subtracted. Aborting...' qabort = 1B return endif if q_vb then print, ' ...OK' ;===== This block checks "image_in". if q_vb then print, 'XRT_DARK_SUB: Checking input "image_in"...' ;=== Ensure "image_in" is of a number type. num_check = total(is_number(image_in)) eq n_elements(image_in) ;=== Ensure "image_in" has 2 dimensions. dim_check = (size(image_in,/n_dim) eq 2) if not (num_check and dim_check) then begin if (not q_qt) then box_message, ['XRT_DARK_SUB: Input "image_in" ' $ + 'needs to be a single XRT image.', $ ' Aborting...'] qabort = 1B return endif if q_vb then print, ' ...OK' ;=== Check dark input ================================================= ;===== This block checks the "dark_file" keyword input. if q_vb then print, 'XRT_DARK_SUB: Checking "dark_file" keyword...' ;== Current version requires dark file to be supplied. if not q_dkfil then begin if (not q_qt) then box_message, ['XRT_DARK_SUB: Requires that ' $ + 'dark_file be supplied as an input.', $ ' Aborting...'] qabort = 1B return endif ;=== Keyword needs to be a string filename. if (datatype(dark_file) ne 'STR') then begin if (not q_qt) then box_message, ['XRT_DARK_SUB: Keyword ' $ + '"dark_file" needs to be a string naming ', $ ' a dark FITS file. Aborting...'] qabort = 1B return endif ;=== Keyword needs to be a single filename. if (n_elements(dark_file) ne 1) then begin if (not q_qt) then box_message, 'XRT_DARK_SUB: Keyword "dark_file" ' $ + 'needs to be a scalar. Aborting...' qabort = 1B return endif if q_vb then print, ' ...OK' ;===== This block reads in "dark_file". if q_vb then print, 'XRT_DARK_SUB: Reading "dark_file"...' read_xrt, dark_file, index_dark, image_dark, $ verbose=verbose, quiet=quiet, qstop=qstop if q_vb then print, ' ...OK' ;===== This block checks "index_dark". if q_vb then print, 'XRT_DARK_SUB: Checking the dark index...' ;=== Check "index_dark". if (datatype(index_dark) ne 'STC') then begin if (not q_qt) then box_message, 'XRT_DARK_SUB: Dark index needs ' $ + 'to be a structure from an XRT FITS header. Aborting...' qabort = 1B return endif if (n_elements(index_dark) ne 1) then begin if (not q_qt) then box_message, 'XRT_DARK_SUB: Dark index needs ' $ + 'to be a scalar. Aborting...' qabort = 1B return endif ;=== Check for necessary tags. if not required_tags(index_dark, 'CAL_INFO,EC_IMTYP,CCD_TEMP,CHIP_SUM,' $ + 'EXPTIME,CCD_READ,DATE_OBS,RPOS_COL,RPOS_ROW,RSIZ_COL,' $ + 'RSIZ_ROW,CTIME,HISTORY,COMMENT', missing=missing) then begin if (not q_qt) then box_message, ['XRT_DARK_SUB: Dark index does ' $ + 'not have these required tags:', $ ' ' + missing, ' Aborting...'] qabort = 1B return endif else begin drk_cal = gt_tagval(index_dark, /cal_info) ;Cal image? 0=no 1=yes drk_typ = gt_tagval(index_dark, /ec_imtyp) ;Type? 0=normal 1=dark drk_tmp = gt_tagval(index_dark, /ccd_tmpc) ;CCD temperature drk_sum = gt_tagval(index_dark, /platescl) ;CCD summing factor drk_edi = gt_tagval(index_dark, /ec_einde) ;Exposure duration index drk_exp = gt_tagval(index_dark, /exptime) ;Actual exposure duration drk_prt = gt_tagval(index_dark, /ccd_read) ;Read port 0=right 1=left drk_tim = gt_tagval(index_dark, /date_obs) ;Image time drk_ctm = gt_tagval(index_dark, /ctime) ;Image time readable drk_x0 = gt_tagval(index_dark, /rpos_col) ;ROI x-corner drk_y0 = gt_tagval(index_dark, /rpos_row) ;ROI y-corner drk_nx0 = gt_tagval(index_dark, /rsiz_col) ;ROI x-size drk_ny0 = gt_tagval(index_dark, /rsiz_row) ;ROI y-size endelse ;=== Is actually a dark? if (drk_typ ne 1) then begin if (not q_qt) then box_message, ['XRT_DARK_SUB: Input "dark_file" ' $ + 'does not actually contain ', $ ' dark image data. Aborting...'] qabort = 1B return endif if q_vb then print, ' ...OK' ;===== This block checks "image_dark". if q_vb then print, 'XRT_DARK_SUB: Checking dark image...' ;=== Ensure "image_dark" is of a number type. num_check = total(is_number(image_dark)) eq n_elements(image_dark) ;=== Ensure "image_dark" has 2 dimensions. dim_check = (size(image_dark,/n_dim) eq 2) if not (num_check and dim_check) then begin if (not q_qt) then box_message, ['XRT_DARK_SUB: Input "image_dark" ' $ + 'needs to be a single XRT image.', $ ' Aborting...'] qabort = 1B return endif if q_vb then print, ' ...OK' ;===== Currently not supporting CAL darks as darks. if ((drk_cal eq 1) or (n_elements(image_dark[*,0]) gt 2048) $ or (n_elements(image_dark[0,*]) gt 2048)) then begin if (not q_qt) then box_message, ['XRT_DARK_SUB: CAL darks not ' $ + 'currently accepted for regular', $ ' dark subtraction. Aborting...'] qabort = 1B return endif ;=== Match dark to data =============================================== ;===== This block checks whether image and dark cover the same ROI. if q_vb then print, 'XRT_DARK_SUB: Checking whether the image and ' $ + 'dark can be matched...' ;=== Has "image_in" been rescaled? if (((n_elements(image_in[*,0])*img_sum) ne img_nx0) or $ ((n_elements(image_in[0,*])*img_sum) ne img_ny0)) then begin if (not q_qt) then box_message, $ ['XRT_DARK_SUB: Input "image_in" has been rescaled or otherwise', $ ' altered such that the pixel ranges cannot be ', $ ' ascertained from the header. Aborting...'] qabort = 1B return endif ;===== This block checks several matches between the image and dark. ;===== A mismatch causes an abort unless the "force" keyword has ;===== been invoked. ;=== Does dark span image's pixels? if ((drk_x0 gt img_x0) or ((drk_x0+drk_nx0) lt (img_x0+img_nx0)) or $ (drk_y0 gt img_y0) or ((drk_y0+drk_ny0) lt (img_y0+img_ny0))) $ then begin if not q_force then begin if (not q_qt) then box_message, 'XRT_DARK_SUB: Dark ROI does ' $ + 'not match the image ROI. Aborting...' qabort = 1B return endif else begin if q_vb then print, 'XRT_DARK_SUB: Dark ROI does not match the ' $ + 'image ROI.' if q_vb then print, ' Forced to proceed.' mismatch_span = 1B endelse endif else begin mismatch_span = 0B endelse ;=== Does dark summing match image's? if (img_sum ne drk_sum) then begin if not q_force then begin if (not q_qt) then box_message, $ ['XRT_DARK_SUB: Dark chip-summing does not match ', $ ' the image chip-summing. Aborting...'] qabort = 1B return endif else begin if q_vb then print, 'XRT_DARK_SUB: Dark chip-summing does not ' $ + 'match the image ROI.' if q_vb then print, ' Forced to proceed.' mismatch_sum = 1B endelse endif else begin mismatch_sum = 0B endelse ;=== Does dark exposure duration match image's? if (img_edi ne drk_edi) then begin if not q_force then begin if (not q_qt) then box_message, $ ['XRT_DARK_SUB: Dark exposure duration does not match ', $ ' the image exposure duration. Aborting...'] qabort = 1B return endif else begin if q_vb then print, 'XRT_DARK_SUB: Dark exposure duration does ' $ + 'not match the image' if q_vb then print, ' exposure duration. Forced ' $ + 'to proceed.' endelse endif ;=== Does dark read-port match image's? if (img_prt ne drk_prt) then begin if not q_force then begin if (not q_qt) then box_message, $ ['XRT_DARK_SUB: CCD read-port for the dark does not match ', $ ' that for the image. Aborting...'] qabort = 1B return endif else begin if q_vb then print, 'XRT_DARK_SUB: CCD read-port for the dark ' $ + 'does not match' if q_vb then print, ' that for the image. Forced ' $ + 'to proceed.' endelse endif ;=== Is dark's CCD temperature close enough to image's? temp_diff = abs(img_tmp - drk_tmp) aa0 = string(temp_diff, format='(F6.2)') aa1 = string(temp_diff_threshold, format='(F6.2)') if (temp_diff gt temp_diff_threshold) then begin if not q_force then begin if (not q_qt) then box_message, $ ['XRT_DARK_SUB: CCD temperature for the dark differs from ', $ ' that for the image by ' + aa0 + ' degrees.', $ ' Limit is ' + aa1 + '. Aborting...'] qabort = 1B return endif else begin if q_vb then print, 'XRT_DARK_SUB: CCD temperature for the ' $ + 'dark differs from that' if q_vb then print, ' for the image by ' + aa0 + $ ' degrees. Limit is ' + aa1 + ' degrees.' if q_vb then print, ' Forced to proceed.' endelse endif ;=== Is dark's exposure date close enough to image's? time_diff = abs(anytim(img_tim,/utime) - anytim(drk_tim,/utime)) time_diff = time_diff / 3600d / 24d aa0 = string(time_diff, format='(F7.3)') aa1 = string(time_diff_threshold, format='(F7.3)') if (time_diff gt time_diff_threshold) then begin if not q_force then begin if (not q_qt) then box_message, $ ['XRT_DARK_SUB: Exposure date for the dark differs from ', $ ' that for the image by ' + aa0 + ' days.', $ ' Limit is ' + aa1 + '. Aborting...'] qabort = 1B return endif else begin if q_vb then print, 'XRT_DARK_SUB: Exposure date for the dark ' $ + 'differs from that' if q_vb then print, ' for the image by ' + aa0 + $ ' days. Limit is ' + aa1 + ' days.' if q_vb then print, ' Forced to proceed.' endelse endif if q_vb then print, ' ' $ + ' ...OK' if q_vb then print, 'XRT_DARK_SUB: Matching dark to image...' ;===== This block extracts the part of the dark that matches to the ;===== image. By this point in the program, either mismatches have ;===== already aborted the routine, or the "force" keyword was invoked. ;=== Make dark summing match that of image. if mismatch_sum then begin image_dark = xrt_resum_img(temporary(image_dark), drk_sum, $ img_sum, quiet=quiet, verbose=verbose, $ qabort=qabort, qstop=qstop) if qabort then begin if (not q_qt) then box_message, 'XRT_DARK_SUB: Cannot match ' $ + 'dark summing level to image. Aborting...' return endif aa0 = strcompress(drk_sum,/rem) aa1 = strcompress(img_sum,/rem) hist_entry0 = 'Dark summing level does not match image. Forced ' + $ 'to re-sum dark to match image: ' + aa0 + 'x --> ' + $ aa1 + 'x.' hist_entry = [hist_entry, hist_entry0] endif else begin hist_entry0 = 'Dark summing level matches image: ' + $ strcompress(img_sum,/rem) + 'x.' endelse ;=== These next coords are "absolute" wrt the CCD corner. ;=== The "1" subscript means they have units of "summed pixels". ;=== (Eg: img_x0 = 80 in CCD pixels, img_sum = 8 ==> img_x1 = 10.) img_nx1 = long(img_nx0/img_sum) img_ny1 = long(img_ny0/img_sum) img_x1 = long(img_x0/img_sum) img_y1 = long(img_y0/img_sum) drk_nx1 = long(drk_nx0/img_sum) drk_ny1 = long(drk_ny0/img_sum) drk_x1 = long(drk_x0/img_sum) drk_y1 = long(drk_y0/img_sum) ;=== If dark ROI doesn't completely span the image ROI. if mismatch_span then begin ;=== If dark ROI is smaller than the image ROI? if ((drk_nx0 lt img_nx0) or (drk_ny0 lt img_ny0)) then begin if (not q_qt) then box_message, $ ['XRT_DARK_SUB: Dark ROI is smaller than image ROI.', $ ' Cannot subtract. Aborting...'] qabort = 1B return ;=== Else if dark ROI is big enough, but doesn't span image. endif else begin if (not q_qt) then box_message, $ ['XRT_DARK_SUB: Dark ROI does not match image ROI.', $ ' Forced to use lower-left corner of dark.'] image_dark = temporary(image_dark[0:img_nx1-1, 0:img_ny1-1]) aa0 = strcompress(img_nx0-1,/rem) aa1 = strcompress(img_ny0-1,/rem) aa2 = strcompress(img_x0,/rem) aa3 = strcompress(img_x0+img_nx0-1,/rem) aa4 = strcompress(img_y0,/rem) aa5 = strcompress(img_y0+img_ny0-1,/rem) hist_entry0 = 'Dark ROI does not match image. Forced to use ' + $ 'dark corner. Dark ROI = [0:' + aa0 + ',0:' + aa1 + $ '] --> Image ROI = [' + aa2 + ':' + aa3 + ',' + aa4 $ + ':' + aa5 + '].' hist_entry = [hist_entry, hist_entry0] endelse ;=== Else if dark ROI *does* span the image ROI, then get that span. endif else begin ;=== These next coords are "relative" to the corner of the dark's ROI. ;=== The "1" subscript still means they have units of "summed pixels". x1 = img_x1 - drk_x1 x2 = x1 + img_nx1 - 1 y1 = img_y1 - drk_y1 y2 = y1 + img_ny1 - 1 image_dark = temporary(image_dark[x1:x2, y1:y2]) aa0 = strcompress(img_x0,/rem) aa1 = strcompress(img_x0+img_nx0-1,/rem) aa2 = strcompress(img_y0,/rem) aa3 = strcompress(img_y0+img_ny0-1,/rem) hist_entry0 = 'Dark ROI matches image. ROI = [' + aa0 + ':' + aa1 + $ ',' + aa2 + ':' + aa3 + '].' hist_entry = [hist_entry, hist_entry0] endelse stop ;===== This block subtracts the CCD bias (pedestal) from the dark. ;=== This needs to happen before the normalization. ;=== An earlier block matched the dark's summing level to that ;=== of the image, but did not update drk_sum, so use img_sum. ;=== This program assumes that the image has already had its ;==== bias subtracted. image_dark = (temporary(image_dark) - (ccd_bias * (img_sum^2.))) > 0 stop ;===== Normalize the exposure. if (drk_edi ne img_edi) then begin image_dark = temporary(image_dark) * img_exp / drk_exp aa0 = string(drk_exp, format='(F6.3)') aa1 = string(img_exp, format='(F6.3)') hist_entry0 = 'Dark exposure duration does not match image. ' + $ 'Forced to normalize to image. Dark exp (s) = ' + $ aa0 + ' --> Image exp (s) = ' + aa1 + '.' hist_entry = [hist_entry, hist_entry0] endif else begin aa0 = string(img_exp, format='(F6.3)') hist_entry0 = 'Dark exposure duration matches image. Exp (s) = ' $ + aa0 + '.' hist_entry = [hist_entry, hist_entry0] endelse ;===== Adjust for temperature. ;=== (This part not implemented yet.) aa0 = string(drk_tmp, format='(F6.2)') aa1 = string(img_tmp, format='(F6.2)') hist_entry0 = 'No calibration for temperature. Dark temp (C) = ' $ + aa0 + '. Image temp (C) = ' + aa1 + '.' hist_entry = [hist_entry, hist_entry0] if q_vb then print, ' ...OK' ;=== Subtract dark from image ========================================= stop ;=== Do the deed. if q_vb then print, 'XRT_DARK_SUB: Subtracting dark from image...' image_out = (image_in - image_dark) > 0 index_out = index_in if q_vb then print, ' ...OK' ;=== Now is the time to update the HISTORY tag. if q_vb then print, 'XRT_DARK_SUB: Updating HISTORY...' hist_prefix = prognam + ' ' + progver + ': (' + systim() + ') ' hist_entry0 = 'Subtracted dark. Dark file: ' + $ strip_dirname(dark_file) ;=== Remove placeholder. hist_entry = hist_entry[1:*] hist_entry = hist_prefix + [hist_entry0, hist_entry] update_history, index_out, hist_entry, /noroutine if q_vb then print, ' ...OK' ;=== Print logs ======================================================= if (not q_qt) then begin td = abs(anytim(img_tim,/utime) - anytim(drk_tim,/utime)) dd = strcompress(long(td/86400), /rem) hh = strcompress(long(td/3600) mod 24,/rem) mm = strcompress(long(td/60) mod 60,/rem) ss = strcompress(long(td) mod 60,/rem) box_message, ['XRT_DARK_SUB: Image time = ' + img_ctm + '.', $ ' Dark time = ' + drk_ctm + '.', $ ' Difference = ' + dd + ' dys, ' $ + hh + ' hrs, ' + mm + ' min, ' + ss + ' sec.', $ ' Processing time = ' + $ strcompress(systime(1)-t0,/rem) + ' sec.' ] endif if q_vb then begin print, 'XRT_DARK_SUB: Adding verbose information...' aa0 = string(img_sum, format='(I1)') aa1 = string(drk_sum, format='(I1)') print, ' Image sum = ' + aa0 + $ 'x. Dark sum = ' + aa1 + 'x.' aa0 = string(img_exp, format='(F6.3)') aa1 = string(drk_exp, format='(F6.3)') print, ' Image exposure (s) = ' + aa1 + $ '. Dark exposure (s) = ' + aa1 + '.' aa0 = string(img_tmp, format='(F6.2)') aa1 = string(drk_tmp, format='(F6.2)') print, ' Image CCD temp (deg) = ' + aa0 + $ '. Dark CCD temp (deg) = ' + aa1 + '.' img_sdv = stdev(image_in, img_men) drk_sdv = stdev(image_dark, drk_men) aa0 = string(img_men, format='(F8.3)') aa1 = string(drk_men, format='(F8.3)') aa2 = string(img_sdv, format='(F8.3)') aa3 = string(drk_sdv, format='(F8.3)') print, ' Image mean = ' + aa0 $ + '. Dark mean = ' + aa1 + '.' print, ' Image std-dev = ' + aa2 $ + '. Dark std-dev = ' + aa3 + '.' img_min = min(image_in) img_max = max(image_in) drk_min = min(image_dark) drk_max = max(image_dark) aa0 = string(img_min, format='(F8.3)') aa1 = string(drk_min, format='(F8.3)') aa2 = string(img_max, format='(F8.3)') aa3 = string(drk_max, format='(F8.3)') print, ' Image min = ' + aa0 $ + '. Dark min = ' + aa1 + '.' print, ' Image max = ' + aa2 $ + '. Dark max = ' + aa3 + '.' drk_hst = gt_tagval(index_dark, /history) drk_com = gt_tagval(index_dark, /comment) print, ' Dark history = ' ss = where(drk_hst ne '', count) if (count gt 0) then print, transpose(drk_hst) print, ' Dark commentary = ' ss = where(drk_com ne '', count) if (count gt 0) then print, transpose(drk_com) endif if qstop then stop END ;=======================================================================