def create_output(filename): fileroot,extn = fileutil.parseFilename(filename) extname = fileutil.parseExtn(extn) if extname[0] == '': extname = "PRIMARY" if not os.path.exists(fileroot): # We need to create the new file pimg = fits.HDUList() phdu = fits.PrimaryHDU() phdu.header['NDRIZIM'] = 1 pimg.append(phdu) if extn is not None: # Create a MEF file with the specified extname ehdu = fits.ImageHDU(data=arr) ehdu.header['EXTNAME'] = extname[0] ehdu.header['EXTVER'] = extname[1] pimg.append(ehdu) log.info('Creating new output file: %s' % fileroot) pimg.writeto(fileroot) del pimg else: log.info('Updating existing output file: %s' % fileroot) handle = fits.open(fileroot, mode='update') return handle,extname
def write_image(self, filename, wcs, *args): """ Read the image from a fits file """ extarray = ['SCI', 'WHT', 'CTX'] pimg = fits.HDUList() phdu = fits.PrimaryHDU() phdu.header['NDRIZIM'] = 1 phdu.header['ROOTNAME'] = filename pimg.append(phdu) for img in args: # Create a MEF file with the specified extname extn = extarray.pop(0) extname = fileutil.parseExtn(extn) ehdu = fits.ImageHDU(data=img) ehdu.header['EXTNAME'] = extname[0] ehdu.header['EXTVER'] = extname[1] self.write_wcs(ehdu, wcs) pimg.append(ehdu) pimg.writeto(filename) del pimg
def create_output(filename): fileroot, extn = fileutil.parseFilename(filename) extname = fileutil.parseExtn(extn) if extname[0] == '': extname = "PRIMARY" if not os.path.exists(fileroot): # We need to create the new file pimg = fits.HDUList() phdu = fits.PrimaryHDU() phdu.header['NDRIZIM'] = 1 pimg.append(phdu) if extn is not None: # Create a MEF file with the specified extname ehdu = fits.ImageHDU(data=arr) ehdu.header['EXTNAME'] = extname[0] ehdu.header['EXTVER'] = extname[1] pimg.append(ehdu) log.info('Creating new output file: %s' % fileroot) pimg.writeto(fileroot) del pimg else: log.info('Updating existing output file: %s' % fileroot) handle = fits.open(fileroot, mode='update', memmap=False) return handle, extname
def get_data(filename): fileroot, extn = fileutil.parseFilename(filename) extname = fileutil.parseExtn(extn) if extname[0] == '': extname = "PRIMARY" if os.path.exists(fileroot): handle = fileutil.openImage(filename, memmap=False) data = handle[extname].data handle.close() else: data = None return data
def get_data(filename): fileroot,extn = fileutil.parseFilename(filename) extname = fileutil.parseExtn(extn) if extname[0] == '': extname = "PRIMARY" if os.path.exists(fileroot): handle = fileutil.openImage(filename) data = handle[extname].data handle.close() else: data = None return data
def generate_headerlet(outwcs,template,wcsname,outname=None): """ Create a headerlet based on the updated HSTWCS object This function uses 'template' as the basis for the headerlet. This file can either be the original wcspars['refimage'] or wcspars['coeffsfile'], in this order of preference. If 'template' is None, then a simple Headerlet will be generated with a single SIPWCS extension and no distortion """ # Create header object from HSTWCS object siphdr = True if outwcs.sip is None: siphdr = False outwcs_hdr = outwcs.wcs2header(sip2hdr=siphdr) outwcs_hdr['NPIX1'] = outwcs._naxis1 outwcs_hdr['NPIX2'] = outwcs._naxis2 # create headerlet object in memory; either from a file or from scratch if template is not None and siphdr: print('Creating headerlet from template...') fname,extn = fileutil.parseFilename(template) extnum = fileutil.parseExtn(extn) extname = ('sipwcs',extnum[1]) hdrlet = headerlet.createHeaderlet(fname,wcsname) # update hdrlet with header values from outwcs for kw in outwcs_hdr.items(): hdrlet[extname].header[kw[0]] = kw[1] hdrlet[extname].header['WCSNAME'] = wcsname else: print('Creating headerlet from scratch...') hdrlet = fits.HDUList() hdrlet.append(fits.PrimaryHDU()) siphdr = fits.ImageHDU(header=outwcs_hdr) siphdr.header['EXTNAME'] = 'SIPWCS' siphdr.header['WCSNAME'] = wcsname hdrlet.append(siphdr) # Write out header to a file as the final product if outname is not None: if outname.find('_hdr.fits') < 0: outname += '_hdr.fits' if os.path.exists(outname): print('Overwrite existing file "%s"'%outname) os.remove(outname) hdrlet.writeto(outname) print('Wrote out headerlet :',outname)
def generate_headerlet(outwcs, template, wcsname, outname=None): """ Create a headerlet based on the updated HSTWCS object This function uses 'template' as the basis for the headerlet. This file can either be the original wcspars['refimage'] or wcspars['coeffsfile'], in this order of preference. If 'template' is None, then a simple Headerlet will be generated with a single SIPWCS extension and no distortion """ # Create header object from HSTWCS object siphdr = True if outwcs.sip is None: siphdr = False outwcs_hdr = outwcs.wcs2header(sip2hdr=siphdr) outwcs_hdr['NPIX1'] = outwcs._naxis1 outwcs_hdr['NPIX2'] = outwcs._naxis2 # create headerlet object in memory; either from a file or from scratch if template is not None and siphdr: print('Creating headerlet from template...') fname, extn = fileutil.parseFilename(template) extnum = fileutil.parseExtn(extn) extname = ('sipwcs', extnum[1]) hdrlet = headerlet.createHeaderlet(fname, wcsname) # update hdrlet with header values from outwcs for kw in outwcs_hdr.items(): hdrlet[extname].header[kw[0]] = kw[1] hdrlet[extname].header['WCSNAME'] = wcsname else: print('Creating headerlet from scratch...') hdrlet = fits.HDUList() hdrlet.append(fits.PrimaryHDU()) siphdr = fits.ImageHDU(header=outwcs_hdr) siphdr.header['EXTNAME'] = 'SIPWCS' siphdr.header['WCSNAME'] = wcsname hdrlet.append(siphdr) # Write out header to a file as the final product if outname is not None: if outname.find('_hdr.fits') < 0: outname += '_hdr.fits' if os.path.exists(outname): print('Overwrite existing file "%s"' % outname) os.remove(outname) hdrlet.writeto(outname) print('Wrote out headerlet :', outname)
def parseSingleInput(f=None, ext=None): if isinstance(f, str): # create an HSTWCS object from a filename if ext is not None: filename = f if isinstance(ext, tuple): if ext[0] == '': extnum = ext[1] # handle ext=('',1) else: extnum = ext else: extnum = int(ext) elif ext is None: filename, ext = fileutil.parseFilename(f) ext = fileutil.parseExtn(ext) if ext[0] == '': extnum = int(ext[1]) # handle ext=('',extnum) else: extnum = ext phdu = fits.open(filename) hdr0 = phdu[0].header try: ehdr = phdu[extnum].header except (IndexError, KeyError) as e: raise e.__class__('Unable to get extension %s.' % extnum) elif isinstance(f, fits.HDUList): phdu = f if ext is None: extnum = 0 else: extnum = ext ehdr = f[extnum].header hdr0 = f[0].header filename = hdr0.get('FILENAME', "") else: raise ValueError('Input must be a file name string or a' '`astropy.io.fits.HDUList` object') return filename, hdr0, ehdr, phdu
def _drizCr(sciImage, virtual_outputs, paramDict): """mask blemishes in dithered data by comparison of an image with a model image and the derivative of the model image. sciImage is an imageObject which contains the science data blotImage is inferred from the sciImage object here which knows the name of its blotted image :) chip should be the science chip that corresponds to the blotted image that was sent paramDict contains the user parameters derived from the full configObj instance dgMask is inferred from the sciImage object, the name of the mask file to combine with the generated Cosmic ray mask here are the options you can override in configObj gain = 7 # Detector gain, e-/ADU grow = 1 # Radius around CR pixel to mask [default=1 for 3x3 for non-NICMOS] ctegrow = 0 # Length of CTE correction to be applied rn = 5 # Read noise in electrons snr = "4.0 3.0" # Signal-to-noise ratio scale = "0.5 0.4" # scaling factor applied to the derivative backg = 0 # Background value expkey = "exptime" # exposure time keyword blot images are saved out to simple fits files with 1 chip in them so for example in ACS, there will be 1 image file with 2 chips that is the original image and 2 blotted image files, each with 1 chip so I'm imagining calling this function twice, once for each chip, but both times with the same original science image file, output files and some input (output from previous steps) are referenced in the imageobject itself """ grow=paramDict["driz_cr_grow"] ctegrow=paramDict["driz_cr_ctegrow"] # try: # assert(chip != None), 'Please specify a chip to process for blotting' # assert(sciImage != None), 'Please specify a science image object for blotting' # except AssertionError: # print "Problem with value of chip or sciImage to drizCR" # print sciImage # raise # raise orig error crcorr_list =[] crMaskDict = {} for chip in range(1,sciImage._numchips+1,1): exten=sciImage.scienceExt + ',' +str(chip) scienceChip=sciImage[exten] if scienceChip.group_member: blotImagePar = 'blotImage' blotImageName = scienceChip.outputNames[blotImagePar] if sciImage.inmemory: __blotImage = sciImage.virtualOutputs[blotImageName] else: try: os.access(blotImageName,os.F_OK) except IOError: print("Could not find the Blotted image on disk:",blotImageName) raise # raise orig error try: __blotImage = fits.open(blotImageName,mode="readonly") # !!! ,memmap=False) ? except IOError: print("Problem opening blot images") raise #blotImageName=scienceChip.outputNames["blotImage"] # input file crMaskImage=scienceChip.outputNames["crmaskImage"] # output file ctedir=scienceChip.cte_dir #check that sciImage and blotImage are the same size? #grab the actual image from disk __inputImage=sciImage.getData(exten) # Apply any unit conversions to input image here for comparison # with blotted image in units of electrons __inputImage *= scienceChip._conversionFactor #make the derivative blot image __blotData=__blotImage[0].data*scienceChip._conversionFactor #simple fits __blotDeriv = quickDeriv.qderiv(__blotData) if not sciImage.inmemory: __blotImage.close() #this grabs the original dq mask from the science image # This mask needs to take into account any crbits values # specified by the user to be ignored. A call to the # buildMask() method may work better here... #__dq = sciImage.maskExt + ',' + str(chip) #__dqMask=sciImage.getData(__dq) __dqMask = sciImage.buildMask(chip,paramDict['crbit']) # both args are ints #parse out the SNR information __SNRList=(paramDict["driz_cr_snr"]).split() __snr1=float(__SNRList[0]) __snr2=float(__SNRList[1]) #parse out the scaling information __scaleList = (paramDict["driz_cr_scale"]).split() __mult1 = float(__scaleList[0]) __mult2 = float(__scaleList[1]) __gain=scienceChip._effGain __rn=scienceChip._rdnoise __backg = scienceChip.subtractedSky*scienceChip._conversionFactor # Define output cosmic ray mask to populate __crMask = np.zeros(__inputImage.shape,dtype=np.uint8) # Set scaling factor (used by MultiDrizzle) to 1 since scaling has # already been accounted for in blotted image __expmult = 1. ################## COMPUTATION PART I ################### # Create a temporary array mask __t1 = np.absolute(__inputImage - __blotData) __ta = np.sqrt(__gain * np.absolute(__blotData * __expmult + __backg * __expmult) + __rn * __rn) __tb = ( __mult1 * __blotDeriv + __snr1 * __ta / __gain ) del __ta __t2 = __tb / __expmult del __tb __tmp1 = np.logical_not(np.greater(__t1, __t2)) del __t1 del __t2 # Create a convolution kernel that is 3 x 3 of 1's __kernel = np.ones((3,3),dtype=np.uint8) # Create an output tmp file the same size as the input temp mask array __tmp2 = np.zeros(__tmp1.shape,dtype=np.int16) # Convolve the mask with the kernel NC.convolve2d(__tmp1,__kernel,output=__tmp2,fft=0,mode='nearest',cval=0) del __kernel del __tmp1 ################## COMPUTATION PART II ################### # Create the CR Mask __xt1 = np.absolute(__inputImage - __blotData) __xta = np.sqrt(__gain * np.absolute(__blotData * __expmult + __backg * __expmult) + __rn * __rn) __xtb = ( __mult2 *__blotDeriv + __snr2 * __xta / __gain ) del __xta __xt2 = __xtb / __expmult del __xtb # It is necessary to use a bitwise 'and' to create the mask with numarray objects. __crMask = np.logical_not(np.greater(__xt1, __xt2) & np.less(__tmp2,9) ) del __xt1 del __xt2 del __tmp2 ################## COMPUTATION PART III ################### #flag additional cte 'radial' and 'tail' pixels surrounding CR pixels as CRs # In both the 'radial' and 'length' kernels below, 0->good and 1->bad, so that upon # convolving the kernels with __crMask, the convolution output will have low->bad and high->good # from which 2 new arrays are created having 0->bad and 1->good. These 2 new arrays are then 'anded' # to create a new __crMask. # recast __crMask to int for manipulations below; will recast to Bool at end __crMask_orig_bool= __crMask.copy() __crMask= __crMask_orig_bool.astype( np.int8 ) # make radial convolution kernel and convolve it with original __crMask cr_grow_kernel = np.ones((grow, grow)) # kernel for radial masking of CR pixel cr_grow_kernel_conv = __crMask.copy() # for output of convolution NC.convolve2d( __crMask, cr_grow_kernel, output = cr_grow_kernel_conv) # make tail convolution kernel and convolve it with original __crMask cr_ctegrow_kernel = np.zeros((2*ctegrow+1,2*ctegrow+1)) # kernel for tail masking of CR pixel cr_ctegrow_kernel_conv = __crMask.copy() # for output convolution # which pixels are masked by tail kernel depends on sign of ctedir (i.e.,readout direction): if ( ctedir == 1 ): # HRC: amp C or D ; WFC: chip = sci,1 ; WFPC2 cr_ctegrow_kernel[ 0:ctegrow, ctegrow ]=1 # 'positive' direction if ( ctedir == -1 ): # HRC: amp A or B ; WFC: chip = sci,2 cr_ctegrow_kernel[ ctegrow+1:2*ctegrow+1, ctegrow ]=1 #'negative' direction if ( ctedir == 0 ): # NICMOS: no cte tail correction pass # do the convolution NC.convolve2d( __crMask, cr_ctegrow_kernel, output = cr_ctegrow_kernel_conv) # select high pixels from both convolution outputs; then 'and' them to create new __crMask where_cr_grow_kernel_conv = np.where( cr_grow_kernel_conv < grow*grow,0,1 ) # radial where_cr_ctegrow_kernel_conv = np.where( cr_ctegrow_kernel_conv < ctegrow, 0, 1 ) # length __crMask = np.logical_and( where_cr_ctegrow_kernel_conv, where_cr_grow_kernel_conv) # combine masks __crMask = __crMask.astype(np.uint8) # cast back to Bool del __crMask_orig_bool del cr_grow_kernel del cr_grow_kernel_conv del cr_ctegrow_kernel del cr_ctegrow_kernel_conv del where_cr_grow_kernel_conv del where_cr_ctegrow_kernel_conv # Apply CR mask to the DQ array in place np.bitwise_and(__dqMask,__crMask,__dqMask) ####### Create the corr file __corrFile = np.zeros(__inputImage.shape,dtype=__inputImage.dtype) __corrFile = np.where(np.equal(__dqMask,0),__blotData,__inputImage) __corrDQMask = np.where(np.equal(__dqMask,0), paramDict['crbit'],0).astype(np.uint16) if paramDict['driz_cr_corr']: crcorr_list.append({'sciext':fileutil.parseExtn(exten), 'corrFile':__corrFile.copy(), 'dqext':fileutil.parseExtn(scienceChip.dq_extn), 'dqMask':__corrDQMask.copy()}) ######## Save the cosmic ray mask file to disk _cr_file = np.zeros(__inputImage.shape,np.uint8) _cr_file = np.where(__crMask,1,0).astype(np.uint8) if not paramDict['inmemory']: outfile = crMaskImage # Always write out crmaskimage, as it is required input for # the final drizzle step. The final drizzle step combines this # image with the DQ information on-the-fly. # # Remove the existing mask file if it exists if(os.access(crMaskImage, os.F_OK)): os.remove(crMaskImage) print("Removed old cosmic ray mask file:",crMaskImage) print('Creating output : ',outfile) else: print('Creating in-memory(virtual) FITS file...') outfile = None _pf = util.createFile(_cr_file, outfile=outfile, header = None) if paramDict['inmemory']: crMaskDict[crMaskImage] = _pf if paramDict['driz_cr_corr']: #util.createFile(__corrFile,outfile=crCorImage,header=None) createCorrFile(sciImage.outputNames["crcorImage"], crcorr_list, sciImage._filename) del crcorr_list if paramDict['inmemory']: sciImage.saveVirtualOutputs(crMaskDict) virtual_outputs = sciImage.virtualOutputs
def getSingleTemplate(fname, extlist=['SCI', 'ERR', 'DQ']): """ # Obtain default headers for output file based on a single input file # (Copied from outputimage module.) # Returns ------- headers : tuple of `astropy.io.fits.Header` objects, not HDU objects! headers """ if fname is None: raise ValueError('No data files for creating FITS output.') froot, fextn = fileutil.parseFilename(fname) if fextn is not None: fnum = fileutil.parseExtn(fextn)[1] ftemplate = fileutil.openImage(froot, mode='readonly') prihdr = ftemplate['PRIMARY'].header.copy() try: del prihdr['pcount'] del prihdr['gcount'] except KeyError: pass if fname.find('.fits') > 0 and len(ftemplate) > 1: # Setup which keyword we will use to select each # extension... _extkey = 'EXTNAME' defnum = fileutil.findKeywordExtn(ftemplate, _extkey, extlist[0]) # # Now, extract the headers necessary for output (as copies) # 1. Find the SCI extension in the template image # 2. Make a COPY of the extension header for use in new output file if fextn is None: extnum = fileutil.findKeywordExtn(ftemplate, _extkey, extlist[0]) else: extnum = (extlist[0], fnum) #scihdr = fits.Header(cards=ftemplate[extnum].header.ascard.copy()) scihdr = fits.Header(ftemplate[extnum].header.copy()) #scihdr.update('extver',1) extnum_sci = extnum # Extract the header for additional extensions if len(extlist) > 1 and extlist[1] not in [ None, '', ' ', 'INDEF', 'None' ]: if fextn is None: extnum = fileutil.findKeywordExtn(ftemplate, _extkey, extlist[1]) else: # there may or may not be a second type of extension in the template count = 0 for f in ftemplate: if 'extname' in f.header and f.header[ 'extname'] == extlist[1]: count += 1 if count > 0: extnum = (extlist[1], fnum) else: # Use science header for remaining headers extnum = (extlist[0], fnum) else: extnum = extnum_sci #errhdr = fits.Header(cards=ftemplate[extnum].header.ascard.copy()) errhdr = fits.Header(ftemplate[extnum].header.copy()) #errhdr.update('extver',1) errhdr['bunit'] = 'UNITLESS' if len(extlist) > 2 and extlist[2] not in [ None, '', ' ', 'INDEF', 'None' ]: if fextn is None: extnum = fileutil.findKeywordExtn(ftemplate, _extkey, extlist[2]) else: count = 0 for f in ftemplate: if 'extname' in f.header and f.header[ 'extname'] == extlist[2]: count += 1 if count > 0: extnum = (extlist[2], fnum) else: # Use science header for remaining headers extnum = (extlist[0], fnum) else: extnum = extnum_sci #dqhdr = fits.Header(cards=ftemplate[extnum].header.ascard.copy()) dqhdr = fits.Header(ftemplate[extnum].header.copy()) #dqhdr.update('extver',1) dqhdr['bunit'] = 'UNITLESS' else: # Create default headers from scratch scihdr = None errhdr = None dqhdr = None ftemplate.close() del ftemplate return prihdr, scihdr, errhdr, dqhdr
def writeSingleFITS(data, wcs, output, template, clobber=True, verbose=True, rules_file=None): """ Write out a simple FITS file given a numpy array and the name of another FITS file to use as a template for the output image header. """ outname, outextn = fileutil.parseFilename(output) outextname, outextver = fileutil.parseExtn(outextn) if fileutil.findFile(outname): if clobber: log.info('Deleting previous output product: %s' % outname) fileutil.removeFile(outname) else: log.warning('Output file %s already exists and overwrite not ' 'specified!' % outname) log.error('Quitting... Please remove before resuming operations.') raise IOError # Now update WCS keywords with values from provided WCS if hasattr(wcs.sip, 'a_order'): siphdr = True else: siphdr = False wcshdr = wcs.wcs2header(sip2hdr=siphdr) if template is not None: # Get default headers from multi-extension FITS file # If input data is not in MEF FITS format, it will return 'None' # NOTE: These are HEADER objects, not HDUs (prihdr, scihdr, errhdr, dqhdr), newtab = getTemplates(template, EXTLIST, rules_file=rules_file) if scihdr is None: scihdr = fits.Header() indx = 0 for c in prihdr.cards: if c.keyword not in ['INHERIT', 'EXPNAME']: indx += 1 else: break for i in range(indx, len(prihdr)): scihdr.append(prihdr.cards[i]) for i in range(indx, len(prihdr)): del prihdr[indx] else: scihdr = fits.Header() prihdr = fits.Header() # Start by updating PRIMARY header keywords... prihdr.set('EXTEND', value=True, after='NAXIS') prihdr['FILENAME'] = outname if outextname == '': outextname = 'sci' if outextver == 0: outextver = 1 scihdr['EXTNAME'] = outextname.upper() scihdr['EXTVER'] = outextver scihdr.update(wcshdr) # Create PyFITS HDUList for all extensions outhdu = fits.HDUList() # Setup primary header as an HDU ready for appending to output FITS file prihdu = fits.PrimaryHDU(header=prihdr) scihdu = fits.ImageHDU(header=scihdr, data=data) outhdu.append(prihdu) outhdu.append(scihdu) outhdu.writeto(outname) if verbose: print('Created output image: %s' % outname)
def getTemplates(fname,extlist): # Obtain default headers for output file # If the output file already exists, use it # If not, use an input file for this information. # # NOTE: Returns 'pyfits.Header' objects, not HDU objects! # if fname == None: print('No data files for creating FITS output.') raise Exception froot,fextn = fileutil.parseFilename(fname) if fextn is not None: fnum = fileutil.parseExtn(fextn)[1] ftemplate = fileutil.openImage(froot,mode='readonly') prihdr = pyfits.Header(cards=ftemplate['PRIMARY'].header.ascard.copy()) del prihdr['pcount'] del prihdr['gcount'] if fname.find('.fits') > 0 and len(ftemplate) > 1: # Setup which keyword we will use to select each # extension... _extkey = 'EXTNAME' defnum = fileutil.findKeywordExtn(ftemplate,_extkey,extlist[0]) # # Now, extract the headers necessary for output (as copies) # 1. Find the SCI extension in the template image # 2. Make a COPY of the extension header for use in new output file if fextn in [None,1]: extnum = fileutil.findKeywordExtn(ftemplate,_extkey,extlist[0]) else: extnum = (extlist[0],fnum) scihdr = pyfits.Header(cards=ftemplate[extnum].header.ascard.copy()) scihdr.update('extver',1) if fextn in [None,1]: extnum = fileutil.findKeywordExtn(ftemplate,_extkey,extlist[1]) else: # there may or may not be a second type of extension in the template count = 0 for f in ftemplate: if 'extname' in f.header and f.header['extname'] == extlist[1]: count += 1 if count > 0: extnum = (extlist[1],fnum) else: # Use science header for remaining headers extnum = (extlist[0],fnum) errhdr = pyfits.Header(cards=ftemplate[extnum].header.ascard.copy()) errhdr.update('extver',1) if fextn in [None,1]: extnum = fileutil.findKeywordExtn(ftemplate,_extkey,extlist[2]) else: count = 0 for f in ftemplate: if 'extname' in f.header and f.header['extname'] == extlist[2]: count += 1 if count > 0: extnum = (extlist[2],fnum) else: # Use science header for remaining headers extnum = (extlist[0],fnum) dqhdr = pyfits.Header(cards=ftemplate[extnum].header.ascard.copy()) dqhdr.update('extver',1) else: # Create default headers from scratch scihdr = None errhdr = None dqhdr = None ftemplate.close() del ftemplate # Now, safeguard against having BSCALE and BZERO try: del scihdr['bscale'] del scihdr['bzero'] del errhdr['bscale'] del errhdr['bzero'] del dqhdr['bscale'] del dqhdr['bzero'] except: # If these don't work, they didn't exist to start with... pass # At this point, check errhdr and dqhdr to make sure they # have all the requisite keywords (as listed in updateDTHKeywords). # Simply copy them from scihdr if they don't exist... if errhdr != None and dqhdr != None: for keyword in DTH_KEYWORDS: if keyword not in errhdr: errhdr.update(keyword,scihdr[keyword]) if keyword not in dqhdr: dqhdr.update(keyword,scihdr[keyword]) return prihdr,scihdr,errhdr,dqhdr
def _drizCr(sciImage, virtual_outputs, paramDict): """mask blemishes in dithered data by comparison of an image with a model image and the derivative of the model image. sciImage is an imageObject which contains the science data blotImage is inferred from the sciImage object here which knows the name of its blotted image :) chip should be the science chip that corresponds to the blotted image that was sent paramDict contains the user parameters derived from the full configObj instance dgMask is inferred from the sciImage object, the name of the mask file to combine with the generated Cosmic ray mask here are the options you can override in configObj gain = 7 # Detector gain, e-/ADU grow = 1 # Radius around CR pixel to mask [default=1 for 3x3 for non-NICMOS] ctegrow = 0 # Length of CTE correction to be applied rn = 5 # Read noise in electrons snr = "4.0 3.0" # Signal-to-noise ratio scale = "0.5 0.4" # scaling factor applied to the derivative backg = 0 # Background value expkey = "exptime" # exposure time keyword blot images are saved out to simple fits files with 1 chip in them so for example in ACS, there will be 1 image file with 2 chips that is the original image and 2 blotted image files, each with 1 chip so I'm imagining calling this function twice, once for each chip, but both times with the same original science image file, output files and some input (output from previous steps) are referenced in the imageobject itself """ grow = paramDict["driz_cr_grow"] ctegrow = paramDict["driz_cr_ctegrow"] # try: # assert(chip is not None), 'Please specify a chip to process for blotting' # assert(sciImage is not None), 'Please specify a science image object for blotting' # except AssertionError: # print "Problem with value of chip or sciImage to drizCR" # print sciImage # raise # raise orig error crcorr_list =[] crMaskDict = {} for chip in range(1, sciImage._numchips + 1, 1): exten = sciImage.scienceExt + ',' +str(chip) scienceChip = sciImage[exten] if scienceChip.group_member: blotImagePar = 'blotImage' blotImageName = scienceChip.outputNames[blotImagePar] if sciImage.inmemory: __blotImage = sciImage.virtualOutputs[blotImageName] else: try: os.access(blotImageName,os.F_OK) except IOError: print("Could not find the Blotted image on disk:",blotImageName) raise # raise orig error try: __blotImage = fits.open(blotImageName, mode="readonly", memmap=False) except IOError: print("Problem opening blot images") raise #blotImageName=scienceChip.outputNames["blotImage"] # input file crMaskImage=scienceChip.outputNames["crmaskImage"] # output file ctedir=scienceChip.cte_dir #check that sciImage and blotImage are the same size? #grab the actual image from disk __inputImage=sciImage.getData(exten) # Apply any unit conversions to input image here for comparison # with blotted image in units of electrons __inputImage *= scienceChip._conversionFactor #make the derivative blot image __blotData=__blotImage[0].data*scienceChip._conversionFactor #simple fits __blotDeriv = quickDeriv.qderiv(__blotData) if not sciImage.inmemory: __blotImage.close() #this grabs the original dq mask from the science image # This mask needs to take into account any crbits values # specified by the user to be ignored. A call to the # buildMask() method may work better here... #__dq = sciImage.maskExt + ',' + str(chip) #__dqMask=sciImage.getData(__dq) __dqMask = sciImage.buildMask(chip,paramDict['crbit']) # both args are ints #parse out the SNR information __SNRList=(paramDict["driz_cr_snr"]).split() __snr1=float(__SNRList[0]) __snr2=float(__SNRList[1]) #parse out the scaling information __scaleList = (paramDict["driz_cr_scale"]).split() __mult1 = float(__scaleList[0]) __mult2 = float(__scaleList[1]) __gain=scienceChip._effGain __rn=scienceChip._rdnoise __backg = scienceChip.subtractedSky*scienceChip._conversionFactor # Define output cosmic ray mask to populate __crMask = np.zeros(__inputImage.shape,dtype=np.uint8) # Set scaling factor (used by MultiDrizzle) to 1 since scaling has # already been accounted for in blotted image __expmult = 1. ################## COMPUTATION PART I ################### # Create a temporary array mask __t1 = np.absolute(__inputImage - __blotData) __ta = np.sqrt(__gain * np.absolute(__blotData * __expmult + __backg * __expmult) + __rn * __rn) __tb = ( __mult1 * __blotDeriv + __snr1 * __ta / __gain ) del __ta __t2 = __tb / __expmult del __tb __tmp1 = np.logical_not(np.greater(__t1, __t2)) del __t1 del __t2 # Create a convolution kernel that is 3 x 3 of 1's __kernel = np.ones((3,3),dtype=np.uint8) # Create an output tmp file the same size as the input temp mask array __tmp2 = np.zeros(__tmp1.shape,dtype=np.int16) # Convolve the mask with the kernel NC.convolve2d(__tmp1,__kernel,output=__tmp2,fft=0,mode='nearest',cval=0) del __kernel del __tmp1 ################## COMPUTATION PART II ################### # Create the CR Mask __xt1 = np.absolute(__inputImage - __blotData) __xta = np.sqrt(__gain * np.absolute(__blotData * __expmult + __backg * __expmult) + __rn * __rn) __xtb = ( __mult2 *__blotDeriv + __snr2 * __xta / __gain ) del __xta __xt2 = __xtb / __expmult del __xtb # It is necessary to use a bitwise 'and' to create the mask with numarray objects. __crMask = np.logical_not(np.greater(__xt1, __xt2) & np.less(__tmp2,9) ) del __xt1 del __xt2 del __tmp2 ################## COMPUTATION PART III ################### #flag additional cte 'radial' and 'tail' pixels surrounding CR pixels as CRs # In both the 'radial' and 'length' kernels below, 0->good and 1->bad, so that upon # convolving the kernels with __crMask, the convolution output will have low->bad and high->good # from which 2 new arrays are created having 0->bad and 1->good. These 2 new arrays are then 'anded' # to create a new __crMask. # recast __crMask to int for manipulations below; will recast to Bool at end __crMask_orig_bool= __crMask.copy() __crMask= __crMask_orig_bool.astype( np.int8 ) # make radial convolution kernel and convolve it with original __crMask cr_grow_kernel = np.ones((grow, grow)) # kernel for radial masking of CR pixel cr_grow_kernel_conv = __crMask.copy() # for output of convolution NC.convolve2d( __crMask, cr_grow_kernel, output = cr_grow_kernel_conv) # make tail convolution kernel and convolve it with original __crMask cr_ctegrow_kernel = np.zeros((2*ctegrow+1,2*ctegrow+1)) # kernel for tail masking of CR pixel cr_ctegrow_kernel_conv = __crMask.copy() # for output convolution # which pixels are masked by tail kernel depends on sign of ctedir (i.e.,readout direction): if ( ctedir == 1 ): # HRC: amp C or D ; WFC: chip = sci,1 ; WFPC2 cr_ctegrow_kernel[ 0:ctegrow, ctegrow ]=1 # 'positive' direction if ( ctedir == -1 ): # HRC: amp A or B ; WFC: chip = sci,2 cr_ctegrow_kernel[ ctegrow+1:2*ctegrow+1, ctegrow ]=1 #'negative' direction if ( ctedir == 0 ): # NICMOS: no cte tail correction pass # do the convolution NC.convolve2d( __crMask, cr_ctegrow_kernel, output = cr_ctegrow_kernel_conv) # select high pixels from both convolution outputs; then 'and' them to create new __crMask where_cr_grow_kernel_conv = np.where( cr_grow_kernel_conv < grow*grow,0,1 ) # radial where_cr_ctegrow_kernel_conv = np.where( cr_ctegrow_kernel_conv < ctegrow, 0, 1 ) # length __crMask = np.logical_and( where_cr_ctegrow_kernel_conv, where_cr_grow_kernel_conv) # combine masks __crMask = __crMask.astype(np.uint8) # cast back to Bool del __crMask_orig_bool del cr_grow_kernel del cr_grow_kernel_conv del cr_ctegrow_kernel del cr_ctegrow_kernel_conv del where_cr_grow_kernel_conv del where_cr_ctegrow_kernel_conv # Apply CR mask to the DQ array in place np.bitwise_and(__dqMask,__crMask,__dqMask) ####### Create the corr file __corrFile = np.zeros(__inputImage.shape,dtype=__inputImage.dtype) __corrFile = np.where(np.equal(__dqMask,0),__blotData,__inputImage) __corrDQMask = np.where(np.equal(__dqMask,0), paramDict['crbit'],0).astype(np.uint16) if paramDict['driz_cr_corr']: crcorr_list.append({'sciext':fileutil.parseExtn(exten), 'corrFile':__corrFile.copy(), 'dqext':fileutil.parseExtn(scienceChip.dq_extn), 'dqMask':__corrDQMask.copy()}) ######## Save the cosmic ray mask file to disk _cr_file = np.zeros(__inputImage.shape,np.uint8) _cr_file = np.where(__crMask,1,0).astype(np.uint8) if not paramDict['inmemory']: outfile = crMaskImage # Always write out crmaskimage, as it is required input for # the final drizzle step. The final drizzle step combines this # image with the DQ information on-the-fly. # # Remove the existing mask file if it exists if(os.access(crMaskImage, os.F_OK)): os.remove(crMaskImage) print("Removed old cosmic ray mask file:",crMaskImage) print('Creating output : ',outfile) else: print('Creating in-memory(virtual) FITS file...') outfile = None _pf = util.createFile(_cr_file, outfile=outfile, header = None) if paramDict['inmemory']: crMaskDict[crMaskImage] = _pf if paramDict['driz_cr_corr']: #util.createFile(__corrFile,outfile=crCorImage,header=None) createCorrFile(sciImage.outputNames["crcorImage"], crcorr_list, sciImage._filename) del crcorr_list if paramDict['inmemory']: sciImage.saveVirtualOutputs(crMaskDict) virtual_outputs = sciImage.virtualOutputs
def writeSingleFITS(data,wcs,output,template,clobber=True,verbose=True): """ Write out a simple FITS file given a numpy array and the name of another FITS file to use as a template for the output image header. """ outname,outextn = fileutil.parseFilename(output) outextname,outextver = fileutil.parseExtn(outextn) if fileutil.findFile(outname): if clobber: log.info('Deleting previous output product: %s' % outname) fileutil.removeFile(outname) else: log.warning('Output file %s already exists and overwrite not ' 'specified!' % outname) log.error('Quitting... Please remove before resuming operations.') raise IOError # Now update WCS keywords with values from provided WCS if hasattr(wcs.sip,'a_order'): siphdr = True else: siphdr = False wcshdr = wcs.wcs2header(sip2hdr=siphdr) if template is not None: # Get default headers from multi-extension FITS file # If input data is not in MEF FITS format, it will return 'None' # NOTE: These are HEADER objects, not HDUs (prihdr,scihdr,errhdr,dqhdr),newtab = getTemplates(template,EXTLIST) if scihdr is None: scihdr = fits.Header() indx = 0 for c in prihdr.cards: if c.keyword not in ['INHERIT','EXPNAME']: indx += 1 else: break for i in range(indx,len(prihdr)): scihdr.append(prihdr.cards[i]) for i in range(indx, len(prihdr)): del prihdr[indx] else: scihdr = fits.Header() prihdr = fits.Header() # Start by updating PRIMARY header keywords... prihdr.set('EXTEND', value=True, after='NAXIS') prihdr['FILENAME'] = outname if outextname == '': outextname = 'sci' if outextver == 0: outextver = 1 scihdr['EXTNAME'] = outextname.upper() scihdr['EXTVER'] = outextver for card in wcshdr.cards: scihdr[card.keyword] = (card.value, card.comment) # Create PyFITS HDUList for all extensions outhdu = fits.HDUList() # Setup primary header as an HDU ready for appending to output FITS file prihdu = fits.PrimaryHDU(header=prihdr) scihdu = fits.ImageHDU(header=scihdr,data=data) outhdu.append(prihdu) outhdu.append(scihdu) outhdu.writeto(outname) if verbose: print('Created output image: %s' % outname)
def _driz_cr(sciImage, virtual_outputs, paramDict): """mask blemishes in dithered data by comparison of an image with a model image and the derivative of the model image. - ``sciImage`` is an imageObject which contains the science data - ``blotImage`` is inferred from the ``sciImage`` object here which knows the name of its blotted image - ``chip`` should be the science chip that corresponds to the blotted image that was sent - ``paramDict`` contains the user parameters derived from the full ``configObj`` instance - ``dqMask`` is inferred from the ``sciImage`` object, the name of the mask file to combine with the generated Cosmic ray mask Here are the options you can override in ``configObj`` ``gain`` = 7 # Detector gain, e-/ADU ``grow`` = 1 # Radius around CR pixel to mask # [default=1 for 3x3 for non-NICMOS] ``ctegrow`` = 0 # Length of CTE correction to be applied ``rn`` = 5 # Read noise in electrons ``snr`` = "4.0 3.0" # Signal-to-noise ratio ``scale`` = "0.5 0.4" # scaling factor applied to the derivative ``backg`` = 0 # Background value ``expkey`` = "exptime" # exposure time keyword Blot images are saved out to simple fits files with 1 chip in them so for example in ACS, there will be 1 image file with 2 chips that is the original image and 2 blotted image files, each with 1 chip So I'm imagining calling this function twice, once for each chip, but both times with the same original science image file, output files and some input (output from previous steps) are referenced in the imageobject itself """ grow = paramDict["driz_cr_grow"] ctegrow = paramDict["driz_cr_ctegrow"] crcorr_list = [] cr_mask_dict = {} for chip in range(1, sciImage._numchips + 1, 1): exten = sciImage.scienceExt + ',' + str(chip) sci_chip = sciImage[exten] if not sci_chip.group_member: continue blot_image_name = sci_chip.outputNames['blotImage'] if sciImage.inmemory: blot_data = sciImage.virtualOutputs[blot_image_name][0].data else: if not os.path.isfile(blot_image_name): raise IOError( "Blotted image not found: {:s}".format(blot_image_name)) try: blot_data = fits.getdata(blot_image_name, ext=0) except IOError: print("Problem opening blot images") raise # Scale blot image, as needed, to match original input data units. blot_data *= sci_chip._conversionFactor input_image = sciImage.getData(exten) # Apply any unit conversions to input image here for comparison # with blotted image in units of electrons input_image *= sci_chip._conversionFactor # make the derivative blot image blot_deriv = quickDeriv.qderiv(blot_data) # Boolean mask needs to take into account any crbits values # specified by the user to be ignored when converting DQ array. dq_mask = sciImage.buildMask(chip, paramDict['crbit']) # parse out the SNR information snr1, snr2 = map( float, filter(None, re.split("[,;\s]+", paramDict["driz_cr_snr"]))) # parse out the scaling information mult1, mult2 = map( float, filter(None, re.split("[,;\s]+", paramDict["driz_cr_scale"]))) gain = sci_chip._effGain rn = sci_chip._rdnoise backg = sci_chip.subtractedSky * sci_chip._conversionFactor # Set scaling factor (used by MultiDrizzle) to 1 since scaling has # already been accounted for in blotted image # expmult = 1. # ################# COMPUTATION PART I ################### # Create a temporary array mask t1 = np.absolute(input_image - blot_data) # ta = np.sqrt(gain * np.abs((blot_data + backg) * expmult) + rn**2) ta = np.sqrt(gain * np.abs(blot_data + backg) + rn**2) t2 = (mult1 * blot_deriv + snr1 * ta / gain) # / expmult tmp1 = t1 <= t2 # Create a convolution kernel that is 3 x 3 of 1's kernel = np.ones((3, 3), dtype=np.uint16) # Convolve the mask with the kernel tmp2 = signal.convolve2d(tmp1, kernel, boundary='symm', mode='same') # ################# COMPUTATION PART II ################### # Create the CR Mask t2 = (mult2 * blot_deriv + snr2 * ta / gain) # / expmult cr_mask = (t1 <= t2) | (tmp2 >= 9) # ################# COMPUTATION PART III ################## # flag additional cte 'radial' and 'tail' pixels surrounding CR pixels # as CRs # In both the 'radial' and 'length' kernels below, 0->good and 1->bad, # so that upon convolving the kernels with cr_mask, the convolution # output will have low->bad and high->good from which 2 new arrays are # created having 0->bad and 1->good. These 2 new arrays are then # 'anded' to create a new cr_mask. # make radial convolution kernel and convolve it with original cr_mask cr_grow_kernel = np.ones((grow, grow), dtype=np.uint16) cr_grow_kernel_conv = signal.convolve2d(cr_mask, cr_grow_kernel, boundary='symm', mode='same') # make tail convolution kernel and convolve it with original cr_mask cr_ctegrow_kernel = np.zeros((2 * ctegrow + 1, 2 * ctegrow + 1)) # which pixels are masked by tail kernel depends on sign of # sci_chip.cte_dir (i.e.,readout direction): if sci_chip.cte_dir == 1: # 'positive' direction: HRC: amp C or D; WFC: chip = sci,1; WFPC2 cr_ctegrow_kernel[0:ctegrow, ctegrow] = 1 elif sci_chip.cte_dir == -1: # 'negative' direction: HRC: amp A or B; WFC: chip = sci,2 cr_ctegrow_kernel[ctegrow + 1:2 * ctegrow + 1, ctegrow] = 1 # do the convolution cr_ctegrow_kernel_conv = signal.convolve2d(cr_mask, cr_ctegrow_kernel, boundary='symm', mode='same') # select high pixels from both convolution outputs; # then 'and' them to create new cr_mask cr_grow_mask = cr_grow_kernel_conv >= grow**2 # radial cr_ctegrow_mask = cr_ctegrow_kernel_conv >= ctegrow # length cr_mask = cr_grow_mask & cr_ctegrow_mask # Apply CR mask to the DQ array in place dq_mask &= cr_mask # Create the corr file corrFile = np.where(dq_mask, input_image, blot_data) corrFile /= sci_chip._conversionFactor corrDQMask = np.where(dq_mask, 0, paramDict['crbit']).astype(np.uint16) if paramDict['driz_cr_corr']: crcorr_list.append({ 'sciext': fileutil.parseExtn(exten), 'corrFile': corrFile.copy(), 'dqext': fileutil.parseExtn(sci_chip.dq_extn), 'dqMask': corrDQMask }) # Save the cosmic ray mask file to disk cr_mask_image = sci_chip.outputNames["crmaskImage"] if paramDict['inmemory']: print('Creating in-memory(virtual) FITS file...') _pf = util.createFile(cr_mask.astype(np.uint8), outfile=None, header=None) cr_mask_dict[cr_mask_image] = _pf sciImage.saveVirtualOutputs(cr_mask_dict) else: # Always write out crmaskimage, as it is required input for # the final drizzle step. The final drizzle step combines this # image with the DQ information on-the-fly. # # Remove the existing mask file if it exists if os.path.isfile(cr_mask_image): os.remove(cr_mask_image) print("Removed old cosmic ray mask file: '{:s}'".format( cr_mask_image)) print("Creating output: {:s}".format(cr_mask_image)) util.createFile(cr_mask.astype(np.uint8), outfile=cr_mask_image, header=None) if paramDict['driz_cr_corr']: createCorrFile(sciImage.outputNames["crcorImage"], crcorr_list, sciImage._filename)
def getSingleTemplate(fname, extlist=['SCI', 'ERR', 'DQ']): """ # Obtain default headers for output file based on a single input file # (Copied from outputimage module.) # Returns ------- headers : tuple of `astropy.io.fits.Header` objects, not HDU objects! headers """ if fname is None: raise ValueError('No data files for creating FITS output.') froot,fextn = fileutil.parseFilename(fname) if fextn is not None: fnum = fileutil.parseExtn(fextn)[1] ftemplate = fileutil.openImage(froot,mode='readonly') prihdr = ftemplate['PRIMARY'].header.copy() try: del prihdr['pcount'] del prihdr['gcount'] except KeyError: pass if fname.find('.fits') > 0 and len(ftemplate) > 1: # Setup which keyword we will use to select each # extension... _extkey = 'EXTNAME' defnum = fileutil.findKeywordExtn(ftemplate,_extkey,extlist[0]) # # Now, extract the headers necessary for output (as copies) # 1. Find the SCI extension in the template image # 2. Make a COPY of the extension header for use in new output file if fextn is None: extnum = fileutil.findKeywordExtn(ftemplate,_extkey,extlist[0]) else: extnum = (extlist[0],fnum) #scihdr = fits.Header(cards=ftemplate[extnum].header.ascard.copy()) scihdr = fits.Header(ftemplate[extnum].header.copy()) #scihdr.update('extver',1) extnum_sci = extnum # Extract the header for additional extensions if len(extlist) > 1 and extlist[1] not in [None,'',' ','INDEF','None']: if fextn is None: extnum = fileutil.findKeywordExtn(ftemplate,_extkey,extlist[1]) else: # there may or may not be a second type of extension in the template count = 0 for f in ftemplate: if 'extname' in f.header and f.header['extname'] == extlist[1]: count += 1 if count > 0: extnum = (extlist[1],fnum) else: # Use science header for remaining headers extnum = (extlist[0],fnum) else: extnum = extnum_sci #errhdr = fits.Header(cards=ftemplate[extnum].header.ascard.copy()) errhdr = fits.Header(ftemplate[extnum].header.copy()) #errhdr.update('extver',1) errhdr['bunit'] = 'UNITLESS' if len(extlist) > 2 and extlist[2] not in [None,'',' ','INDEF','None']: if fextn is None: extnum = fileutil.findKeywordExtn(ftemplate,_extkey,extlist[2]) else: count = 0 for f in ftemplate: if 'extname' in f.header and f.header['extname'] == extlist[2]: count += 1 if count > 0: extnum = (extlist[2],fnum) else: # Use science header for remaining headers extnum = (extlist[0],fnum) else: extnum = extnum_sci #dqhdr = fits.Header(cards=ftemplate[extnum].header.ascard.copy()) dqhdr = fits.Header(ftemplate[extnum].header.copy()) #dqhdr.update('extver',1) dqhdr['bunit'] = 'UNITLESS' else: # Create default headers from scratch scihdr = None errhdr = None dqhdr = None ftemplate.close() del ftemplate return prihdr, scihdr, errhdr, dqhdr
def _driz_cr(sciImage, virtual_outputs, paramDict): """mask blemishes in dithered data by comparison of an image with a model image and the derivative of the model image. - ``sciImage`` is an imageObject which contains the science data - ``blotImage`` is inferred from the ``sciImage`` object here which knows the name of its blotted image - ``chip`` should be the science chip that corresponds to the blotted image that was sent - ``paramDict`` contains the user parameters derived from the full ``configObj`` instance - ``dqMask`` is inferred from the ``sciImage`` object, the name of the mask file to combine with the generated Cosmic ray mask Here are the options you can override in ``configObj`` ``gain`` = 7 # Detector gain, e-/ADU ``grow`` = 1 # Radius around CR pixel to mask # [default=1 for 3x3 for non-NICMOS] ``ctegrow`` = 0 # Length of CTE correction to be applied ``rn`` = 5 # Read noise in electrons ``snr`` = "4.0 3.0" # Signal-to-noise ratio ``scale`` = "0.5 0.4" # scaling factor applied to the derivative ``backg`` = 0 # Background value ``expkey`` = "exptime" # exposure time keyword Blot images are saved out to simple fits files with 1 chip in them so for example in ACS, there will be 1 image file with 2 chips that is the original image and 2 blotted image files, each with 1 chip So I'm imagining calling this function twice, once for each chip, but both times with the same original science image file, output files and some input (output from previous steps) are referenced in the imageobject itself """ grow = paramDict["driz_cr_grow"] ctegrow = paramDict["driz_cr_ctegrow"] crcorr_list = [] cr_mask_dict = {} for chip in range(1, sciImage._numchips + 1, 1): exten = sciImage.scienceExt + ',' + str(chip) sci_chip = sciImage[exten] if not sci_chip.group_member: continue blot_image_name = sci_chip.outputNames['blotImage'] if sciImage.inmemory: blot_data = sciImage.virtualOutputs[blot_image_name][0].data else: if not os.path.isfile(blot_image_name): raise IOError("Blotted image not found: {:s}" .format(blot_image_name)) try: blot_data = fits.getdata(blot_image_name, ext=0) except IOError: print("Problem opening blot images") raise # Scale blot image, as needed, to match original input data units. blot_data *= sci_chip._conversionFactor input_image = sciImage.getData(exten) # Apply any unit conversions to input image here for comparison # with blotted image in units of electrons input_image *= sci_chip._conversionFactor # make the derivative blot image blot_deriv = quickDeriv.qderiv(blot_data) # Boolean mask needs to take into account any crbits values # specified by the user to be ignored when converting DQ array. dq_mask = sciImage.buildMask(chip, paramDict['crbit']) # parse out the SNR information snr1, snr2 = map( float, filter(None, re.split("[,;\s]+", paramDict["driz_cr_snr"])) ) # parse out the scaling information mult1, mult2 = map( float, filter( None, re.split("[,;\s]+", paramDict["driz_cr_scale"]) ) ) gain = sci_chip._effGain rn = sci_chip._rdnoise backg = sci_chip.subtractedSky * sci_chip._conversionFactor # Set scaling factor (used by MultiDrizzle) to 1 since scaling has # already been accounted for in blotted image # expmult = 1. # ################# COMPUTATION PART I ################### # Create a temporary array mask t1 = np.absolute(input_image - blot_data) # ta = np.sqrt(gain * np.abs((blot_data + backg) * expmult) + rn**2) ta = np.sqrt(gain * np.abs(blot_data + backg) + rn**2) t2 = (mult1 * blot_deriv + snr1 * ta / gain) # / expmult tmp1 = t1 <= t2 # Create a convolution kernel that is 3 x 3 of 1's kernel = np.ones((3, 3), dtype=np.uint16) # Convolve the mask with the kernel tmp2 = signal.convolve2d(tmp1, kernel, boundary='symm', mode='same') # ################# COMPUTATION PART II ################### # Create the CR Mask t2 = (mult2 * blot_deriv + snr2 * ta / gain) # / expmult cr_mask = (t1 <= t2) | (tmp2 >= 9) # ################# COMPUTATION PART III ################## # flag additional cte 'radial' and 'tail' pixels surrounding CR pixels # as CRs # In both the 'radial' and 'length' kernels below, 0->good and 1->bad, # so that upon convolving the kernels with cr_mask, the convolution # output will have low->bad and high->good from which 2 new arrays are # created having 0->bad and 1->good. These 2 new arrays are then # 'anded' to create a new cr_mask. # make radial convolution kernel and convolve it with original cr_mask cr_grow_kernel = np.ones((grow, grow), dtype=np.uint16) cr_grow_kernel_conv = signal.convolve2d( cr_mask, cr_grow_kernel, boundary='symm', mode='same' ) # make tail convolution kernel and convolve it with original cr_mask cr_ctegrow_kernel = np.zeros((2 * ctegrow + 1, 2 * ctegrow + 1)) # which pixels are masked by tail kernel depends on sign of # sci_chip.cte_dir (i.e.,readout direction): if sci_chip.cte_dir == 1: # 'positive' direction: HRC: amp C or D; WFC: chip = sci,1; WFPC2 cr_ctegrow_kernel[0:ctegrow, ctegrow] = 1 elif sci_chip.cte_dir == -1: # 'negative' direction: HRC: amp A or B; WFC: chip = sci,2 cr_ctegrow_kernel[ctegrow+1:2*ctegrow+1, ctegrow] = 1 # do the convolution cr_ctegrow_kernel_conv = signal.convolve2d( cr_mask, cr_ctegrow_kernel, boundary='symm', mode='same' ) # select high pixels from both convolution outputs; # then 'and' them to create new cr_mask cr_grow_mask = cr_grow_kernel_conv >= grow**2 # radial cr_ctegrow_mask = cr_ctegrow_kernel_conv >= ctegrow # length cr_mask = cr_grow_mask & cr_ctegrow_mask # Apply CR mask to the DQ array in place dq_mask &= cr_mask # Create the corr file corrFile = np.where(dq_mask, input_image, blot_data) corrFile /= sci_chip._conversionFactor corrDQMask = np.where(dq_mask, 0, paramDict['crbit']).astype(np.uint16) if paramDict['driz_cr_corr']: crcorr_list.append({ 'sciext': fileutil.parseExtn(exten), 'corrFile': corrFile.copy(), 'dqext': fileutil.parseExtn(sci_chip.dq_extn), 'dqMask': corrDQMask }) # Save the cosmic ray mask file to disk cr_mask_image = sci_chip.outputNames["crmaskImage"] if paramDict['inmemory']: print('Creating in-memory(virtual) FITS file...') _pf = util.createFile(cr_mask.astype(np.uint8), outfile=None, header=None) cr_mask_dict[cr_mask_image] = _pf sciImage.saveVirtualOutputs(cr_mask_dict) else: # Always write out crmaskimage, as it is required input for # the final drizzle step. The final drizzle step combines this # image with the DQ information on-the-fly. # # Remove the existing mask file if it exists if os.path.isfile(cr_mask_image): os.remove(cr_mask_image) print("Removed old cosmic ray mask file: '{:s}'" .format(cr_mask_image)) print("Creating output: {:s}".format(cr_mask_image)) util.createFile(cr_mask.astype(np.uint8), outfile=cr_mask_image, header=None) if paramDict['driz_cr_corr']: createCorrFile(sciImage.outputNames["crcorImage"], crcorr_list, sciImage._filename)