PRO aia_rfilter, list, data_out, index_out, idl_out=idl_out, dir_out=dir_out, $ jp2=jp2, png=png, fits=fits, nsum=nsum, bin=bin, nring=nring, $ corscl=corscl, cutout=cutout, speed=speed, create_sav=create_sav, $ sav=sav, color=color, ver=ver, border=border, use_ref=use_ref, $ index_ref=index_ref, cross_correl=cross_correl, correl_img=correl_img, $ jhelio=jhelio, deconvolve=deconvolve, no_capt=no_capt, no_skip=no_skip, $ error_thresh=error_thresh ; ========================================================================= ;+ ; PROJECT: ; SDO / AIA ; ; NAME: ; ; AIA_RFILTER ; ; CATEGORY: ; ; Image processing. ; ; PURPOSE: ; ; Creates images in which the contrast of the corona is enchanced to show ; fine structure. A number of images are summed and the coronal component ; is divided into rings. Each ring is then scaled based on its radius ; and associated pixel brightnesses relative to its neighbors. The ; disk is pulled from the central image in the sum to create the final ; output. A number of keywords are available for user control of output ; type, dimensions, scaling, and alignment; see below. ; ; CALLING SEQUENCE: ; ; AIA_RFILTER, list [,data_out] [,index_out] [,/idl_out] [,dir_out=dir_out] $ ; [,/jp2] [,/png] [,/fits] [,nsum=nsum] [,bin=bin] [,nring=nring] $ ; [,corscl=corscl] [,cutout=cutout] [,/speed] [,sav=sav] [,/create_sav] $ ; [,/color] [,ver=ver] [,border=border] [,/use_ref] [,index_ref=index_ref] $ ; [,/cross_correl] [,correl_img=correl_img] [,/jhelio] [,/deconvolve] $ ; [,/no_capt] [,/no_skip] [,error_thresh=error_thresh] ; ; INPUTS: ; ; LIST - [Mandatory] (string array) ; Array of image filepaths. Takes Level-1 or 1.5 data. The list ; MUST be populated with observations of the same wavelength, and ; observatios from any AIA passband are accepted. ; ; OUTPUTS: ; ; DATA_OUT - [Optional] (image array) ; Specify to output an IDL array of the resultant images. This variable ; must be defined in conjunction with the /IDL_OUT keyword. This ; is necessary to avoid carrying the output array in memory ; if it's not actually desired upon completion. Use with caution, as ; this output array may quickly eat up and exceed your machine's ; memory. Note that if set, no file outputs will be created unless one ; of the filetype keywords is also set (/JP2, /PNG, /FITS). ; INDEX_OUT - [Optional] (structure array) ; Specify to ouput a structure array containing the header info. ; ; KEYWORDS: ; ; ; IDL_OUT - [Optional] (boolean) ; Set to output an array of the resultant images. This keyword ; must be set and the DATA_OUT variable must be defined. This ; is necessary to avoid carrying the output array in memory ; if it's not actually desired upon completion. Use with caution, ; as this output array may quickly eat up and exceed your machine's ; memory. Note that if set, no file outputs will be created unless ; one of the filetype keywords is also set (/JP2, /PNG, /FITS). ; DIR_OUT - [Optional] (string) ; Directory for output images. If not set, current working ; directory is used. ; JP2 - [Optional] (boolean) ; Set to output jpeg2000s (.jp2). This is the default output because ; the header info is preserved and they are considerably smaller than ; PNGs. Note that the file AIA_RFILTER_JP2GEN is also need to output ; jp2s, but AIA_RFILTER can be run without the jp2gen function if one ; of the other file type keywords is set. Also Note that multiple file ; types can be outputted by setting multiple keywords. ; PNG - [Optional] (boolean) ; Set to output .png. Note that multiple filetypes can be outputted ; by setting multiple keywords. ; FITS - [Optional] (boolean) ; Set to output .fits. Images will NOT include captions. Note that ; multiple filetypes can be outputted by setting multiple keywords. ; NSUM - [Optional] (integer) ; Number of images to be summed to produce the image of the corona. ; The middle image of each sum will be used for the disk. If not set, ; defaults to 5. Accepts any value greater than or equal to 1. ; BIN - [Optional] (integer) ; Set to specify binning (resolution) of output image. Uses FREBIN(), ; which allows for any arbitrary binning. BIN=1: 4096x4096 (full res), ; BIN=2: 2048x2048, etc. Default is 4 (1024x1024). Accepts any value ; greater than or equal to 1. ; NRING - [Optional] (integer) ; Set to specify how many rings the corona will be divided into. More ; rings will yield a smoother image but will slow the routine. The ; routine tries to anticipate how many rings are needed given the ; specified resolution by setting nring=500/sqrt(bin). Accepts any ; value greater than or equal to 2. ; CORSCL - [Optional] (integer) ; Coronal scaling factor, useful for examining particularly bright or ; faint structures. The default value is 3.75. Increasing this will ; DECREASE the overall brightness of the corona and vice versa. ; Accepts any value greater than 0. ; CUTOUT - [Optional] (4-element array) ; Set for a cutout of orignal image. Array elements correspond ; to the desired pixels to be read out: [x1,x2,y1,y1]. These pixel ; values correspond to the full resolution (4096x4096) image. If you ; wanted, for instance, a 2048x2048px cutout but in a 512x512 final ; image, you might specify the following: CUTOUT=[0,2047,0,2047], BIN=8 ; SPEED - [Optional] (boolean) ; Normally, the coronal scaling factors are redefined for each filtered ; image. If /SPEED is set, these values will be computed only once and ; then then used throughout to save 20% or so of runtime. This could be ; be disadvantageous if the first few images in LIST are corrupted for ; some reason or contain a transient brightening, but works well in ; general. An alternative to this would be to use the CREATE_SAV and SAV ; keywords to decide upon and specify a set of parameters that you like. ; CREATE_SAV - [Optional] (boolean) ; Set this keyword to output .sav files contaning the coronal scaling ; parameters for each image, to be applied using the SAV keyword. A .sav ; file will be created for each output image, which can then be used to ; determine which set of parameters does the best job. This could be useful ; if, for instance, you're looking to create a set of images with uniform ; scaling over a time period where the overall brightness of the corona is ; highly variable. ; SAV - [Optional] (string) ; .sav filepath containing parameters for scaling the corona, created ; using the /CREATE_SAV keyword. ; COLOR - [Optional] (boolean) ; If set, the standard AIA color table for the given wavelength is ; loaded via AIA_LCT.PRO. Grayscale is used if not set (LOADCT, 0). ; VER - [Optional] (integer or string) ; Version indicator. Will be tacked onto the end of the filename ; after an underscore. ; BORDER - [Optional] (integer) ; Set to specify border that will be excluding from filtering. ; Default is 15px. This is necessary to prevent edge effects due ; to alignment from throwing off the filter. Accepts any value greater ; than or equal to 0. ; USE_REF - [Optional] (boolean) ; Set if you'd like the AIA_PREP call to align images to some reference ; image rather than the center pixel. If USE_REF is set and INDEX_REF ; is NOT set, then the first image in LIST is used as the reference. ; INDEX_REF - [Optional] (structure) ; Header structure corresponding to the image you'd like all others to ; be aligned to. If set, USE_REF is also automatically set. ; CROSS_CORREL - [Optional] (boolean) ; Set if you'd like images to be aligned to eachother using a cross ; correlation routine (CORREL_OPTIMIZE). This is not generally necessary ; and will slow the runtime considerably, but is useful if you suspect ; that AIA_PREP is not fully aligning the images, as may be the case with ; off-pointed observations in particular. If CROSS_CORREL is set and ; CORREL_IMG is NOT set, then the first image in LIST is used as the base. ; CORREL_IMG - [Optional] ([4096,4096] image array) ; Data array used as base for cross correlation alignment. If set, ; /CROSS_CORREL is also automatically set. ; JHELIO - [Optional] (boolean) ; Set to output jp2 files using the JHelioviewer naming convention. ; This is not the default because the files will not be named ; in a sequential fashion that movie-making programs like QuickTime ; Pro and FFmpeg will follow. ; DECONVOLVE - [Optional] (boolean) ; Set to apply image deconvolution; calls AIA_CALC_PSF() and ; AIA_DECONVOLVE_RICHARDSONLUCY(). Resultant images will be noticeably ; sharper, but the deconvolution is vvvery slow. ; NO_CAPT - [Optional] (boolean) ; Set to disable image captions. ; NO_SKIP - [Optional] (boolean) ; Set to disable skipping of short-exposure images. ; ERROR_THRESH - [Optional] (integer) ; Set to specify how many errors you'll tolerate within the loop that reads ; in the images. This error handling is designed to circumvent rare errors ; in READ_SDO.PRO when processing many files. Accepts any value greater ; then or equal to 0. See note 1. ; ; ; EXAMPLES: ; ; Basic usage: ; IDL> list = file_search('/data_directory/','*171.fits') ; IDL> aia_rfilter, list, /speed ; ; COMMON BLOCKS: ; ; none ; ; NOTES: ; ; 1) Regarding the use of CATCH error handling: ; ; Occasionally, READ_SDO.PRO will return an error and a .FITS file must be skipped ; to prevent this routine from crashing. When this happens, the next index in ; the input list is used and the routine continues as normal with the same cadence, ; so there is some overlap between the output that required the skip and the subsequent ; output. For instance, consider a list of 9 images to be used with 3-image sums. ; Normally, the output images would be composed of [0,1,2],[3,4,5],[6,7,8]. Now ; imagine that the 4th image is corrupted and must be skipped. In this scenario, the ; 3 output images would be composed of [0,1,2],[3,5,6],[6,7,8]. ; ; This type of error is fairly rare but is likely to crop up a few times if you're ; processing several days worth of AIA images (many thousands of images). Which files ; were skipped and the !ERROR_STATE information for each one are printed upon completion. ; Any more than 5 errors will cause the routine to abort, as this may be indicative of ; a different problem (this threshhold can be user-defined using the ERROR_THRESH ; keyword). This error handling is accomplished using CATCH, which will respond the ; same to any error that occurs within the file-reading loop. To disable it when ; editting or debugging that section, set ERROR_THRESH=0. ; ; CONTACT: ; ; Patrick McCauley - pmccauley@cfa.harvard.edu ; ; MODIFICATION HISTORY: ; progver = 'V1.0' ;--- Written by Patrick McCauley & Alec Engall ; ;- ; ========================================================================= progname = 'aia_rfilter' t0 = systime(1) ;start time ;Allows AIA_RFILTER to compile and run without having the jp2gen function ;available to it. forward_function aia_rfilter_jp2gen ;return to caller of program unit if error on_error, 2 ; ========================================================================= ; Setting unspecified keywords to default values ; ========================================================================= if not keyword_set(nsum) then nsum = 5 ;# of imgs to sum if not keyword_set(corscl) then corscl = 3.75 ;coronal scale factor if not keyword_set(bin) then bin = 4 ;factor to scale down full res imgs by ;# of rings to divide coronal into, 500 or less depending on binning if not keyword_set(nring) then nring = fix(500/sqrt(bin)) if n_elements(error_thresh) eq 0 then error_thresh = 5 ;# of errors allowed if n_elements(border) eq 0 then border = 15 ;# px border excluded from filter ;Compiles file type keyword information into an array type_out = [keyword_set(jp2), keyword_set(png), $ keyword_set(fits), keyword_set(idl_out)] if (total(type_out) eq 0) then type_out[0] = 1 ;defaults to jp2's ;Version number/tag if keyword_set(ver) then ver = '_'+strcompress(string(ver), /remove_all) if not keyword_set(ver) then ver = '' ; ========================================================================= ; Checking inputs/keywords for obvious errors ; ========================================================================= ;Is there is enough data in the input array? nl = n_elements(list) message, 'Number of FITS files found: '+strtrim(nl,2), /informational if (nl lt nsum) then begin box_message, ['Whoops, insufficent data found. Returned.'] return endif ;Does the user-specified output directory exist? if keyword_set(dir_out) then begin if (file_test(dir_out, /directory) eq 0) then begin print, dir_out box_message, ['Whoops, output directory above does not exist. Returned.'] return endif ;Sets output directory to current working directory if not specified. endif else begin cd, current = current dir_out = current+'/' endelse ;Does the user-specified .sav file exist? if keyword_set(sav) then begin if (file_test(sav) eq 0) then begin box_message, ['Whoops, specified .sav file not found. Returned.'] return endif endif ;Does the cutout region asked for make sense? if keyword_set(cutout) then begin if total(where(cutout ge 4096 OR cutout lt 0)) ne -1 then begin box_message, ['Whoops, cutout region is out of bounds. Returned.'] return endif endif ; ========================================================================= ; Initiates variables to be called or modified later ; ========================================================================= ;Reads in first image to gather some initial information read_sdo, list[0], hd, da, /silent, /uncomp_delete ;Use hd as reference index if USE_REF is set but no index specified if keyword_set(use_ref) AND not keyword_set(index_ref) then index_ref=hd ;Prep data if not already level 1.5 if (hd.lvl_num eq 1.) then aia_prep, temporary(hd), temporary(da), hd, da, $ use_ref=use_ref, index_ref=index_ref, /quiet ;Use prepped image as cross correlation base if CROSS_CORREL is set but no ;image speficied if keyword_set(cross_correl) AND not keyword_set(correl_img) then correl_img=da ;Some wavelength-specific values for byte scaling and ejecting short exposures ;mnmx = [min_corona, max_corona, min_disk, max_disk, min_exposure_time, normalization factor] case hd.wavelnth of 171: mnmx = [0.0, 1.1, 5.0, 9.5, 1.8, 4.99803] 211: mnmx = [0.0, 1.2, 4.0, 8.0, 2.7, 4.99801] 094: mnmx = [0.0, 1.3, 0.5, 4.5, 2.7, 4.99803] 335: mnmx = [0.0, 1.4, 2.0, 6.5, 2.7, 6.99734] 193: mnmx = [0.0, 1.2, 4.75, 8.75, 1.8, 2.99950] 304: mnmx = [0.0, 1.2, 3.75, 6.75, 2.7, 4.99441] 131: mnmx = [0.0, 1.2, 2.2, 6.0, 2.7, 6.99685] 1600: mnmx = [0.0, 0.8, 3.5, 8.5, 1.1, 2.99911] 1700: mnmx = [0.0, 0.8, 6.0, 8.0, 0.4, 1.00026] 4500: mnmx = [0.0, 1.0, 8.0, 10.0, 0.4, 1.00026] endcase ;Wavelenth / nsum strings: wv = strcompress(string(hd.wavelnth), /remove_all) nsum_str = strcompress(string(nsum), /remove_all) ;Restores user-specified sav file with scaling parameters. if keyword_set(sav) then restore, sav cen = double([hd.crpix1, hd.crpix2]) ;[x,y] center coords yy = (indgen(4096)-cen[1]) ## (1. + fltarr(4096)) ;array of only x-values wrt SUN center xx = (1. + fltarr(4096)) ## (indgen(4096)-cen[0]) ;array of only y-values wrt SUN center rr = sqrt(xx^2 + yy^2) ;array of radial distaces from SUN center for each pixel rsol = rr / hd.r_sun ;array of radial distances from center for each pixel in solar radii rmax = max(abs(rsol)) ;max radius ;Distance of the radial rings from the center in solar radii. rad = dindgen(nring)/double(nring-1)*(rmax-1.)+1. arad = alog10(rad) ;log scaled for polynomial fitting later ;Finds coefficients of a linear relationship for deciding which ring ;each pixel will be divided into. coefR = poly_fit(rad,dindgen(nring),1) ;If aligning to something other than the image center, then a distinction needs to be ;made between sun and image center to properly clip corners and exclude border. if keyword_set(use_ref) OR keyword_set(index_ref) then begin yy = (indgen(4096)-2048.5) ## (1. + fltarr(4096)) ;array of only x-values wrt IMAGE center xx = (1. + fltarr(4096)) ## (indgen(4096)-2048.5) ;array of only y-values wrt IMAGE center rr = sqrt(xx^2 + yy^2) ;array of radial distaces from IMAGE center for each pixel endif ;Determines indices beyond AIA's FOV to be clipped off of final image, ;otherwise corners are populated with 'static' that's amplified by the ;radial filtering corner_clip = where(rr gt 2400) ;Pixels corresponding to corona, excluding border to prevent incorporating ;the bars that aia_prep introduces when it shifts the image for alignment. masking = where(abs(xx) le 2048-border AND abs(yy) le 2048-border AND rsol gt 1.) ;Determines which ring a given pixel belongs in. Each array ;element corresponds to a coronal pixel and is populated with ;the ring # it belongs in. inow = fix((coefR[0] + coefR[1]*rsol[masking]) +0.5) ;Some values related to the binning if keyword_set(cutout) then res = [(cutout[1]-cutout[0]+1)/bin,(cutout[3]-cutout[2]+1)/bin] $ else res = [4096/bin,4096/bin] charsize = 8/bin & charthick = 4/bin ;for image captions ;define plot settings set_plot,'z' ;loads default AIA color schemes if /color is set if keyword_set(color) then aia_lct, rr, gg, bb, wavelnth=wv, /load if not keyword_set(color) then begin loadct,0 ;grayscale if /color not set tvlct, rr, gg, bb, /get endif ;set resolution and allow for true color output device, set_r=[res[0],res[1]], set_pixel_depth=24, decomposed=0 ;Point spread function for deconvolution if keyword_set(deconvolve) then psf = aia_calc_psf(hd.wavelnth, /use_preflightcore) ;avoids carrying uneeded variables in memory undefine, cen & undefine, coefr & undefine, xx & undefine, yy undefine, rr & undefine, rsol & undefine, rmax & undefine, rad ; ========================================================================= ; Main Loop ; ========================================================================= ;loop length = # elements in list minus list length modulo sum size -1 ;So the loop ends when there aren't enough images left for a full sum: loop_len = nl - (nl mod nsum) - 1 last = fix(nsum-1) ;# of last image in sum middle = fix(nsum/2) ;# of middle image in sum for kk = 0, loop_len, nsum do begin t1 = systime(1) ;Establishes an initial time for the current image. ;This is used to avoid modifying the loop variable when ejecting images ;for read_sdo errors or short exposures aa = kk message, 'Reading and summing '+nsum_str+' images...', /informational ;Reads in nsum fits files and sums them. for i=0, last do begin ;Error handling for read_sdo errors. See header note 1. catch, error_status if (error_status ne 0) then begin box_message, ['Error, image '+list[aa+i]+' skipped.'] boost_array, skipped_files, list[aa+i] ;collect skipped files ;Collect !error_state information: if n_elements(error_details) gt 0 then $ error_details = concat_struct(temporary(error_details), !error_state) if n_elements(error_details) eq 0 then error_details = !error_state aa = aa+1 ;skip offending file ;Abort if too many errors collect because that's probably ;indicative of a different problem. if n_elements(error_details) ge error_thresh then begin box_message, ['Too many errors. Returned.'] print, 'Skipped image | error message:' for l=0, n_elements(error_details)-1 do print, skipped_files[0,l],' | ', error_details[l].msg return endif error_status = 0 endif ;reads in data, testing for and skipping any short exposures: if not keyword_set(no_skip) then begin repeat begin read_sdo, list[aa+i], hd, da, /silent, /uncomp_delete if (hd.exptime lt mnmx[4]) then begin box_message, ['Skipped '+list[aa+i]+' for short exposure'] aa = aa+1 endif endrep until (hd.exptime ge mnmx[4]) endif ;preps data to ensure proper alignment if (hd.lvl_num eq 1.) then aia_prep, temporary(hd), temporary(da), hd, da, $ use_ref=use_ref, index_ref=index_ref, /quiet ;cross-correlate for even better alignment if desired if keyword_set(cross_correl) then begin correl_optimize, correl_img, da, xoff, yoff da = shift_img(temporary(da), [xoff,yoff]) endif ;normalize for exposure time da = (temporary(da)*mnmx[5]/(1.0*hd.exptime)) if (i eq 0) then begin d0 = hd.date_obs ;time of first observation in sum dataSUM = double(da) ;initiates sum, double to prevent overflow endif else begin dataSUM = temporary(dataSUM) + da ;creates sum endelse if (i eq middle) then begin if keyword_set(deconvolve) then $ img = aia_deconvolve_richardsonlucy(da, psf, niter=25) $ else img = da ;used to construct disk endif endfor ;Cancel CATCH error handling outside of the FITS reading loop because it ;is only designed to bypass unexpected read_sdo errors and would otherwise ;loop ad infinitum if the error occurred outside the reading loop. catch, /cancel if keyword_set(deconvolve) then dataSUM = $ aia_deconvolve_richardsonlucy(temporary(dataSUM), psf, niter=25) ; ========================================================================= ; Determining the observation time & filename ; ========================================================================= ;The date and time for the first and last fits files are averaged. ;The header date and time are reconstructed from the average. t_avg = (anytim2tai(d0)+anytim2tai(hd.date_obs))/2 t_a = anytim2cal(t_avg, form=7) t_a = '20'+strmid(t_a,0,8)+'T'+strmid(t_a,9,16) ;Constructs filename based on instrument, observation time, wavelenth, & version tag. filename = strmid(hd.instrume,0,3) + strmid(t_a,0,4) + strmid(t_a,5,2) + $ strmid(t_a,8,2) + '_' + strmid(t_a,11,2) + strmid(t_a,14,2) + $ strmid(t_a,17,2) + '_' + wv + ver ; ========================================================================= ; The radial filter ; ========================================================================= ;Creates scaling paramters if .sav not specified. Otherwise params evaluated ;either on each loop increment or just the 1st if the SPEED keyword is set. if (kk eq 0) OR not keyword_set(speed) AND not keyword_set(sav) then begin ring_avg = dblarr(nring) ;average intensity for given ring ring_min = dblarr(nring) ;min intensity for given ring ;Loop cycles through the rings. Note that max(inow)-1 is used instead ;of the # of rings because, depending on the border size, the outermost ;rings may not be populated. for k=0, max(inow)-1 do begin idx = where(inow eq k) ;finds pixels in ring 'k' ring_avg[k] = total(dataSUM[masking[idx]]) / n_elements(idx) ring_min[k] = min(dataSUM[masking[idx]]) endfor avg_min = avg(ring_min >1e-6) ;used for scaling up the lowest mins ring_min = alog10(temporary(ring_min) >avg_min/10) coefdummy = svdfit(arad,ring_min,5,yfit=yfit) ;polynomial fit accross mins min_fit = 10.^yfit max_fit = ring_avg*corscl ;increase corscl to decrease corona brightness ;Store pamaeters for later use if requested if keyword_set(create_sav) then begin save, filename=dir_out+filename+'_params.sav', min_fit, max_fit message, 'Created ' + filename+'_params.sav', /informational endif endif ;bytescales disk component img = bytscl(alog(temporary(img) >1e-6), min=mnmx[2], max=mnmx[3]) ;renormalizes, bytescales, and overlays the fancified coronal component img[masking] = bytscl((dataSUM[masking] - min_fit[inow]) / $ (max_fit[inow] - min_fit[inow]), $ min=mnmx[0], max=mnmx[1]) ; ========================================================================= ; Assembling and outputting the final image ; ========================================================================= ;clips off corners outside AIA's FOV img[corner_clip] = 0 ;creates cutout and resizes image if keyword_set(cutout) then begin img = temporary(img[cutout[0]:cutout[1],cutout[2]:cutout[3]]) if bin ne 1 then img = frebin(temporary(img),res[0],res[1]) endif else begin if bin ne 1 then img = frebin(temporary(img),res[0],res[1]) endelse tv, img ;thar she blows ;Creates the image captions. if not keyword_set(no_capt) then begin xyouts,0.82,0.97,strmid(t_a,0,10),/norm,charsize=charsize, charthick=charthick ;date xyouts,0.82,0.94,strmid(t_a,11,8)+' UT',/norm,charsize=charsize, charthick=charthick ;time xyouts,0.03,0.97,wv,/norm,charsize=charsize, charthick=charthick ;wavelength xyouts,0.72,0.02,'AIA NASA SAO LMSAL',/norm,charsize=charsize, charthick=charthick ;credits endif ;Update header info for jp2s/idl output if (type_out[0] eq 1) OR (type_out[3] eq 1) then begin hd.date_obs = t_a ;update header time hd.naxis1 = res[0] hd.naxis2 = res[1] hd.crpix1 = temporary(hd.crpix1)/bin hd.crpix2 = temporary(hd.crpix2)/bin hd.r_sun = temporary(hd.r_sun)/bin update_history, hd, version=progver endif ;Output jp2 if (type_out[0] eq 1) then begin jp2gen = aia_rfilter_jp2gen(hd) ;returns encoding paramters and xml-formatted header. ;Use the jhelioviewer naming convention if requested if keyword_set(jhelio) then jp2_filename = strmid(filename,3,4)+'_'+strmid(filename,7,2)+ $ '_'+strmid(filename,9,2)+'__'+strmid(filename,12,6)+ $ '__'+observation+ver+'.jp2' $ else jp2_filename = filename+'.jp2' ;initiate jp2 object using jp2gen info oJP2 = OBJ_NEW('IDLffJPEG2000',dir_out+jp2_filename,/WRITE, $ bit_rate=jp2gen.bit_rate, n_layers=jp2gen.n_layers, $ n_levels=jp2gen.n_levels, bit_depth=jp2gen.bit_depth, $ signed=0, PROGRESSION = 'PCRL', xml=jp2gen.header) oJP2->SetData,tvrd(true=1) OBJ_DESTROY, oJP2 ;memory management message, 'Created ' + jp2_filename, /informational endif ;Output png if (type_out[1] eq 1) then begin write_png,dir_out+filename+'.png',tvrd(true=1),rr,gg,bb message, 'Created ' + filename+'.png', /informational endif ;Output fits if (type_out[2] eq 1) then begin fits_write, dir_out+filename+'.fits', img, hd message, 'Created ' + filename+'.fits', /informational endif ;Output IDL data/index arrays if (type_out[3] eq 1) then begin boost_array, data_out, img if kk eq 0 then index_out = hd if kk ne 0 then index_out = concat_struct(temporary(index_out), hd) message, 'Added '+filename+' to output array', /informational endif ; ========================================================================= ; Elapsed time and estimating time left until completion ; ========================================================================= ;Calculates the total elapsed time and converts to hours, minutes, and seconds. t_total = anytim(systime(1) - t0, /atime) message, 'Elasped time: '+strmid(t_total,11,12,/reverse_offset), /informational ;Time until completion based on previous loop increment time. ;[(loop length - # of images processed) / loop increment]*tloop t_end = anytim(((nl-kk-nsum)/nsum)*(systime(1) - t1), /atime) message, 'Estimated time to completion: '+strmid(t_end,11,12,/reverse_offset), /informational endfor ;end main loop ;How many images were skipped due to read errors, which files, and what errors? if n_elements(error_details) eq 0 then begin message, 'Hurray! Finished without errors.', /informational endif else begin box_message, ['Finished with errors.'] print, 'Skipped image | error message:' for l=0, n_elements(error_details)-1 do print, skipped_files[0,l],' | ', error_details[l].msg endelse return end