Beispiel #1
0
    def getData(self,exten=None):
        """ Return just the data array from the specified extension
            fileutil is used instead of fits to account for non-
            FITS input images. openImage returns a fits object.
        """
        if exten.lower().find('sci') > -1:
            # For SCI extensions, the current file will have the data
            fname = self._filename
        else:
            # otherwise, the data being requested may need to come from a
            # separate file, as is the case with WFPC2 DQ data.
            #
            # convert exten to 'sci',extver to get the DQ info for that chip
            extn = exten.split(',')
            sci_chip = self._image[self.scienceExt,int(extn[1])]
            fname = sci_chip.dqfile

        extnum = self._interpretExten(exten)
        if self._image[extnum].data is None:
            if os.path.exists(fname):
                _image=fileutil.openImage(fname,clobber=False,memmap=0)
                _data=fileutil.getExtn(_image,extn=exten).data
                _image.close()
                del _image
                self._image[extnum].data = _data
            else:
                _data = None
        else:
            _data = self._image[extnum].data

        return _data
Beispiel #2
0
    def getdarkimg(self, chip):
        """
        Return an array representing the dark image for the detector.

        Returns
        -------
        dark: array
            Dark image array in the same shape as the input image with **units of cps**

        """
        sci_chip = self._image[self.scienceExt, chip]

        # First attempt to get the dark image specified by the "DARKFILE"
        # keyword in the primary keyword of the science data.
        try:
            filename = self.header["DARKFILE"]
            handle = fileutil.openImage(filename,
                                        mode='readonly',
                                        memmap=False)
            hdu = fileutil.getExtn(handle, extn="sci,1")
            darkobj = hdu.data[sci_chip.ltv2:sci_chip.size2,
                               sci_chip.ltv1:sci_chip.size1]

        # If the darkfile cannot be located, create the dark image from
        # what we know about the detector dark current and assume a
        # constant dark current for the whole image.
        except:
            darkobj = (
                np.ones(sci_chip.image_shape, dtype=sci_chip.image_dtype) *
                self.getdarkcurrent())
        return darkobj
Beispiel #3
0
 def __getitem__(self,exten):
     """ Overload  getitem to return the data and header
         these only work on the HDU list already in memory
         once the data has been zero's in self._image you should
         use getData or getHeader to re-read the file.
     """
     return fileutil.getExtn(self._image,extn=exten)
Beispiel #4
0
    def getdarkimg(self,chip):
        """
        Return an array representing the dark image for the detector.

        Returns
        -------
        dark: array
            Dark image array in the same shape as the input image with **units of cps**

        """
        sci_chip = self._image[self.scienceExt,chip]

        # First attempt to get the dark image specified by the "DARKFILE"
        # keyword in the primary keyword of the science data.
        try:
            filename = self.header["DARKFILE"]
            handle = fileutil.openImage(filename, mode='readonly', memmap=False)
            hdu = fileutil.getExtn(handle,extn="sci,1")
            darkobj = hdu.data[sci_chip.ltv2:sci_chip.size2,sci_chip.ltv1:sci_chip.size1]

        # If the darkfile cannot be located, create the dark image from
        # what we know about the detector dark current and assume a
        # constant dark current for the whole image.
        except:
            darkobj = np.ones(sci_chip.image_shape,dtype=sci_chip.image_dtype)*self.getdarkcurrent()


        return darkobj
Beispiel #5
0
    def getHeaderHandle(self):
        """ Sets up the PyFITS image handle and Primary header
            as self.image_handle and self.header.

            When Pattern being used for output product, filename will be
            set to None and this returns None for header and image_handle.
        """

        _numsci = 0
        if self.name:
            _handle = fileutil.openImage(self.name,mode='readonly',memmap=self.pars['memmap'])
            _fname,_extn = fileutil.parseFilename(self.name)
            _hdr = _handle['PRIMARY'].header.copy()
            # Count number of SCI extensions
            for _fext in _handle:
                if 'extname' in _fext.header and _fext.header['extname'] == 'SCI':
                    _numsci += 1

            if _extn and _extn > 0:
                # Append correct extension/chip/group header to PRIMARY...
                for _card in fileutil.getExtn(_handle,_extn).header.ascard:
                    _hdr.ascard.append(_card)
        else:
            # Default to None
            _handle = None
            _hdr = None

        # Set attribute to point to these products
        self.image_handle = None
        self.header = _hdr
        self.nmembers = _numsci

        return _handle
Beispiel #6
0
    def getDGEOArrays(self):
        """ Return numpy objects for the distortion correction
            image arrays.

            If no DGEOFILE is specified, it will return
            empty 2x2 arrays.
        """

        # Instantiate array objects for distortion correction image arrays
        if self.xgeoim == '':
            # No distortion image specified.
            # Defaulting to empty 2x2 array.
            xgdim = ygdim = 2
            _pxg = np.zeros((ygdim,xgdim),dtype=np.float32)
            _pyg = np.zeros((ygdim,xgdim),dtype=np.float32)
        else:
            # Open distortion correction FITS file
            _xgfile = fileutil.openImage(self.xgeoim)
            #_xgfile.info()

            # Access the extensions which correspond to this Exposure
            _xgname,_xgext = fileutil.parseFilename(self.xgeoim)
            _ygname,_ygext = fileutil.parseFilename(self.ygeoim)

            _pxgext = fileutil.getExtn(_xgfile,extn=_xgext)
            _pygext = fileutil.getExtn(_xgfile,extn=_ygext)

            # Copy out the numpy objects for output
            _ltv1 = int(self.geometry.wcs.offset_x)
            _ltv2 = int(self.geometry.wcs.offset_y)
            if _ltv1 != 0. or _ltv2 != 0.:
                # subarray section only
                _pxg = _pxgext.data[_ltv2:_ltv2+self.naxis2,_ltv1:_ltv1+self.naxis1].copy()
                _pyg = _pygext.data[_ltv2:_ltv2+self.naxis2,_ltv1:_ltv1+self.naxis1].copy()
            else:
                # full array
                _pxg = _pxgext.data.copy()
                _pyg = _pygext.data.copy()

            # Close file handles now...
            _xgfile.close()
            del _xgfile

        return _pxg,_pyg
Beispiel #7
0
 def getHeader(self,exten=None):
     """ Return just the specified header extension fileutil
         is used instead of fits to account for non-FITS
         input images. openImage returns a fits object.
     """
     _image=fileutil.openImage(self._filename,clobber=False,memmap=0)
     _header=fileutil.getExtn(_image,extn=exten).header
     _image.close()
     del _image
     return _header
Beispiel #8
0
    def getflat(self, chip):
        """
        Method for retrieving a detector's flat field. For STIS there are three.
        This method will return an array the same shape as the image.

        """
        sci_chip = self._image[self.scienceExt, chip]
        exten = self.errExt + ',' + str(chip)

        # The keyword for STIS flat fields in the primary header of the flt

        lflatfile = fileutil.osfn(self._image["PRIMARY"].header['LFLTFILE'])
        pflatfile = fileutil.osfn(self._image["PRIMARY"].header['PFLTFILE'])

        # Try to open the file in the location specified by LFLTFILE.
        try:
            handle = fileutil.openImage(lflatfile,
                                        mode='readonly',
                                        memmap=False)
            hdu = fileutil.getExtn(handle, extn=exten)
            lfltdata = hdu.data
            if lfltdata.shape != self.full_shape:
                lfltdata = interp2d.expand2d(lfltdata, self.full_shape)
        except IOError:
            lfltdata = np.ones(self.full_shape, dtype=sci_chip.data.dtype)
            print("Cannot find file '{:s}'. Treating flatfield constant value "
                  "of '1'.\n".format(lflatfile))

        # Try to open the file in the location specified by PFLTFILE.
        try:
            handle = fileutil.openImage(pflatfile,
                                        mode='readonly',
                                        memmap=False)
            hdu = fileutil.getExtn(handle, extn=exten)
            pfltdata = hdu.data
        except IOError:
            pfltdata = np.ones(self.full_shape, dtype=sci_chip.data.dtype)
            print("Cannot find file '{:s}'. Treating flatfield constant value "
                  "of '1'.\n".format(pflatfile))

        flat = lfltdata * pfltdata

        return flat
Beispiel #9
0
    def getflat(self,chip):
        """
        Method for retrieving a detector's flat field. For STIS there are three.
        This method will return an array the same shape as the image.

        """
        sci_chip = self._image[self.scienceExt,chip]
        exten = self.errExt+','+str(chip)

        # The keyword for STIS flat fields in the primary header of the flt

        lflatfile = fileutil.osfn(self._image["PRIMARY"].header['LFLTFILE'])
        pflatfile = fileutil.osfn(self._image["PRIMARY"].header['PFLTFILE'])

        # Try to open the file in the location specified by LFLTFILE.
        try:
            handle = fileutil.openImage(lflatfile,mode='readonly',memmap=0)
            hdu = fileutil.getExtn(handle,extn=exten)
            lfltdata = hdu.data
            if lfltdata.shape != self.full_shape:
                lfltdata = interp2d.expand2d(lfltdata,self.full_shape)
        except:
            lfltdata = np.ones(self.full_shape,dtype=sci_chip.image_dtype)
            str = "Cannot find file "+filename+".  Treating flatfield constant value of '1'.\n"
            print(str)

        # Try to open the file in the location specified by PFLTFILE.
        try:
            handle = fileutil.openImage(pflatfile,mode='readonly',memmap=0)
            hdu = fileutil.getExtn(handle,extn=exten)
            pfltdata = hdu.data
        except:
            pfltdata = np.ones(self.image_shape,dtype=sci_chip.image_dtype)
            str = "Cannot find file "+filename+".  Treating flatfield constant value of '1'.\n"
            print(str)

        print("lfltdata shape: ",lfltdata.shape)
        print("pfltdata shape: ",pfltdata.shape)
        flat = lfltdata * pfltdata

        return flat
Beispiel #10
0
    def buildIVMmask(self,chip,dqarr,scale):
        """ Builds a weight mask from an input DQ array and either an IVM array
        provided by the user or a self-generated IVM array derived from the
        flat-field reference file associated with the input image.
        """
        sci_chip = self._image[self.scienceExt,chip]
        ivmname = self.outputNames['ivmFile']

        if ivmname != None:
            log.info("Applying user supplied IVM files for chip %s" % chip)
            #Parse the input file name to get the extension we are working on
            extn = "IVM,{}".format(chip)

            #Open the mask image for updating and the IVM image
            ivm =  fileutil.openImage(ivmname, mode='readonly')
            ivmfile = fileutil.getExtn(ivm, extn)

            # Multiply the IVM file by the input mask in place.
            ivmarr = ivmfile.data * dqarr

            ivm.close()

        else:

            log.info("Automatically creating IVM files for chip %s" % chip)
            # If no IVM files were provided by the user we will
            # need to automatically generate them based upon
            # instrument specific information.

            flat = self.getflat(chip)
            RN = self.getReadNoiseImage(chip)
            darkimg = self.getdarkimg(chip)
            skyimg = self.getskyimg(chip)

            #exptime = self.getexptimeimg(chip)
            #exptime = sci_chip._exptime
            #ivm = (flat*exptime)**2/(darkimg+(skyimg*flat)+RN**2)
            ivm = (flat)**2/(darkimg+(skyimg*flat)+RN**2)

           # Multiply the IVM file by the input mask in place.
            ivmarr = ivm * dqarr

        # Update 'wt_scl' parameter to match use of IVM file
        sci_chip._wtscl = pow(sci_chip._exptime,2)/pow(scale,4)
        #sci_chip._wtscl = 1.0/pow(scale,4)

        return ivmarr.astype(np.float32)
Beispiel #11
0
    def getflat(self, chip):
        """
        Method for retrieving a detector's flat field.

        Returns
        -------
        flat: array
            This method will return an array the same shape as the image in
            **units of electrons**.

        """

        sci_chip = self._image[self.scienceExt, chip]
        exten = '%s,%d' % (self.scienceExt, chip)
        # The keyword for ACS flat fields in the primary header of the flt
        # file is pfltfile.  This flat file is already in the required
        # units of electrons.

        # The use of fileutil.osfn interprets any environment variable, such as jref$,
        # used in the specification of the reference filename
        filename = fileutil.osfn(self._image["PRIMARY"].header[self.flatkey])

        try:
            handle = fileutil.openImage(filename,
                                        mode='readonly',
                                        memmap=False)
            hdu = fileutil.getExtn(handle, extn=exten)
            if hdu.data.shape[0] != sci_chip.image_shape[0]:
                _ltv2 = np.round(sci_chip.ltv2)
            else:
                _ltv2 = 0
            _size2 = sci_chip.image_shape[0] + _ltv2
            if hdu.data.shape[1] != sci_chip.image_shape[1]:
                _ltv1 = np.round(sci_chip.ltv1)
            else:
                _ltv1 = 0
            _size1 = sci_chip.image_shape[1] + _ltv1

            data = hdu.data[_ltv2:_size2, _ltv1:_size1]
            handle.close()
        except:
            data = np.ones(sci_chip.image_shape, dtype=sci_chip.image_dtype)
            log.warning("Cannot find file %s.\n    Treating flatfield "
                        "constant value of '1'." % filename)
        flat = data
        return flat
    def getflat(self, chip):
        """
        Method for retrieving a detector's flat field.

        Returns
        -------
        flat: array
            This method will return an array the same shape as the image in
            **units of electrons**.

        """

        sci_chip = self._image[self.scienceExt, chip]
        exten = '%s,%d' % (self.scienceExt, chip)
        # The keyword for ACS flat fields in the primary header of the flt
        # file is pfltfile.  This flat file is already in the required
        # units of electrons.

        # The use of fileutil.osfn interprets any environment variable, such as jref$,
        # used in the specification of the reference filename
        filename = fileutil.osfn(self._image["PRIMARY"].header[self.flatkey])

        try:
            handle = fileutil.openImage(filename, mode='readonly', memmap=0)
            hdu = fileutil.getExtn(handle,extn=exten)
            if hdu.data.shape[0] != sci_chip.image_shape[0]:
                _ltv2 = np.round(sci_chip.ltv2)
            else:
                _ltv2 = 0
            _size2 = sci_chip.image_shape[0]+_ltv2
            if hdu.data.shape[1] != sci_chip.image_shape[1]:
                _ltv1 = np.round(sci_chip.ltv1)
            else:
                _ltv1 = 0
            _size1 = sci_chip.image_shape[1]+_ltv1

            data = hdu.data[_ltv2:_size2, _ltv1:_size1]
            handle.close()
        except:
            data = np.ones(sci_chip.image_shape, dtype=sci_chip.image_dtype)
            log.warning("Cannot find file %s.\n    Treating flatfield "
                        "constant value of '1'." % filename)
        flat = data
        return flat
Beispiel #13
0
def _update(image,idctab,nimsets,apply_tdd=False,
            quiet=None,instrument=None,prepend=None,nrchip=None, nrext=None):

    tdd_xyref = {1: [2048, 3072], 2:[2048, 1024]}
    _prepend = prepend
    _dqname = None
    # Make a copy of the header for keyword access
    # This copy includes both Primary header and
    # extension header
    hdr = fileutil.getHeader(image)

    # Try to get the instrument if we don't have it already
    instrument = readKeyword(hdr,'INSTRUME')

    binned = 1
    # Read in any specified OFFTAB, if present (WFPC2)
    offtab = readKeyword(hdr,'OFFTAB')
    dateobs = readKeyword(hdr,'DATE-OBS')
    if not quiet:
        print("OFFTAB, DATE-OBS: ",offtab,dateobs)

    print("-Updating image ",image)

    if not quiet:
        print("-Reading IDCTAB file ",idctab)

    # Get telescope orientation from image header
    # If PA_V# is not present of header, try to get it from the spt file
    pvt = readKeyword(hdr,'PA_V3')
    if pvt == None:
        sptfile = fileutil.buildNewRootname(image, extn='_spt.fits')
        if os.path.exists(sptfile):
            spthdr = fileutil.getHeader(sptfile)
            pvt = readKeyword(spthdr,'PA_V3')
    if pvt != None:
        pvt = float(pvt)
    else:
        print('PA_V3 keyword not found, WCS cannot be updated. Quitting ...')
        raise ValueError

    # Find out about instrument, detector & filters
    detector = readKeyword(hdr,'DETECTOR')

    Nrefchip=1
    if instrument == 'WFPC2':
        filter1 = readKeyword(hdr,'FILTNAM1')
        filter2 = readKeyword(hdr,'FILTNAM2')
        mode = readKeyword(hdr,'MODE')
        if os.path.exists(fileutil.buildNewRootname(image, extn='_c1h.fits')):
            _dqname = fileutil.buildNewRootname(image, extn='_c1h.fits')
            dqhdr = pyfits.getheader(_dqname,1)
            dqext = readKeyword(dqhdr, 'EXTNAME')
        if mode == 'AREA':
            binned = 2
        Nrefchip=nrchip
    elif instrument == 'NICMOS':
        filter1 = readKeyword(hdr,'FILTER')
        filter2 = None
    elif instrument == 'WFC3':
        filter1 = readKeyword(hdr,'FILTER')
        filter2 = None
        # use value of 'BINAXIS' keyword to set binning value for WFC3 data
        binned = readKeyword(hdr,'BINAXIS1')
    else:
        filter1 = readKeyword(hdr,'FILTER1')
        filter2 = readKeyword(hdr,'FILTER2')

    if filter1 == None or filter1.strip() == '': filter1 = 'CLEAR'
    else: filter1 = filter1.strip()
    if filter2 == None or filter2.strip() == '': filter2 = 'CLEAR'
    else: filter2 = filter2.strip()

    if filter1.find('CLEAR') == 0: filter1 = 'CLEAR'
    if filter2.find('CLEAR') == 0: filter2 = 'CLEAR'

    # Set up parity matrix for chip
    if instrument == 'WFPC2' or instrument =='STIS' or instrument == 'NICMOS':
        parity = PARITY[instrument]
    elif detector in PARITY:
        parity = PARITY[detector]
    else:
        raise ValueError('Detector ',detector,
                         ' Not supported at this time. Exiting...')

    # Get the VAFACTOR keyword if it exists, otherwise set to 1.0
    # we also need the reference pointing position of the target
    # as this is where
    _va_key = readKeyword(hdr,'VAFACTOR')
    if _va_key != None:
        VA_fac = float(_va_key)
    else:
        VA_fac=1.0

    if not quiet:
        print('VA factor: ',VA_fac)

    #ra_targ = float(readKeyword(hdr,'RA_TARG'))
    #dec_targ = float(readKeyword(hdr,'DEC_TARG'))

    # Get the chip number
    _c = readKeyword(hdr,'CAMERA')
    _s = readKeyword(hdr,'CCDCHIP')
    _d = readKeyword(hdr,'DETECTOR')
    if _c != None and str(_c).isdigit():
        chip = int(_c)
    elif _s == None and _d == None:
        chip = 1
    else:
        if _s:
            chip = int(_s)
        elif str(_d).isdigit():
            chip = int(_d)
        else:
            chip = 1
    # For the ACS/WFC case the chip number doesn't match the image
    # extension
    nr = 1
    if (instrument == 'ACS' and detector == 'WFC') or (instrument == 'WFC3' and detector == 'UVIS'):
        if nimsets > 1:
            Nrefchip = 2
        else:
            Nrefchip = chip
    elif instrument == 'NICMOS':
        Nrefchip = readKeyword(hdr,'CAMERA')
    elif instrument == 'WFPC2':
        nr = nrext
    else:
        if nimsets > 1:
            nr = Nrefchip

    if not quiet:
        print("-PA_V3 : ",pvt," CHIP #",chip)


    # Extract the appropriate information from the IDCTAB
    #fx,fy,refpix,order=fileutil.readIDCtab(idctab,chip=chip,direction='forward',
    #            filter1=filter1,filter2=filter2,offtab=offtab,date=dateobs)
    idcmodel = models.IDCModel(idctab,
                               chip=chip, direction='forward', date=dateobs,
                               filter1=filter1, filter2=filter2, offtab=offtab, binned=binned,
                               tddcorr=apply_tdd)
    fx = idcmodel.cx
    fy = idcmodel.cy
    refpix = idcmodel.refpix
    order = idcmodel.norder

    # Determine whether to perform time-dependent correction
    # Construct matrices neded to correct the zero points for TDD
    if apply_tdd:
        #alpha,beta = mutil.compute_wfc_tdd_coeffs(dateobs,skew_coeffs)
        alpha = refpix['TDDALPHA']
        beta = refpix['TDDBETA']
        tdd = N.array([[beta, alpha], [alpha, -beta]])
        mrotp = fileutil.buildRotMatrix(2.234529)/2048.

    else:
        alpha = 0.0
        beta = 0.0

    # Get the original image WCS
    Old=wcsutil.WCSObject(image,prefix=_prepend)

    # Reset the WCS keywords to original archived values.
    Old.restore()

    #
    # Look for any subarray offset
    #
    ltv1,ltv2 = drutil.getLTVOffsets(image)
    #
    # If reference point is not centered on distortion model
    # shift coefficients to be applied relative to observation
    # reference position
    #
    offsetx = Old.crpix1 - ltv1 - refpix['XREF']
    offsety = Old.crpix2 - ltv2 - refpix['YREF']
    shiftx = refpix['XREF'] + ltv1
    shifty = refpix['YREF'] + ltv2
    if ltv1 != 0. or ltv2 != 0.:
        ltvoffx = ltv1 + offsetx
        ltvoffy = ltv2 + offsety
        offshiftx = offsetx + shiftx
        offshifty = offsety + shifty
    else:
        ltvoffx = 0.
        ltvoffy = 0.
        offshiftx = 0.
        offshifty = 0.

    if ltv1 != 0. or ltv2 != 0.:
        fx,fy = idcmodel.shift(idcmodel.cx,idcmodel.cy,offsetx,offsety)

    # Extract the appropriate information for reference chip

    ridcmodel = models.IDCModel(idctab,
                                chip=Nrefchip, direction='forward', date=dateobs,
                                filter1=filter1, filter2=filter2, offtab=offtab, binned=binned,
                                tddcorr=apply_tdd)
    rfx = ridcmodel.cx
    rfy = ridcmodel.cy
    rrefpix = ridcmodel.refpix
    rorder = ridcmodel.norder
    """
    rfx,rfy,rrefpix,rorder=mutil.readIDCtab(idctab,chip=Nrefchip,
        direction='forward', filter1=filter1,filter2=filter2,offtab=offtab,
        date=dateobs,tddcorr=apply_tdd)
    """
    # Create the reference image name
    rimage = image.split('[')[0]+"[sci,%d]" % nr
    if not quiet:
        print("Reference image: ",rimage)

    # Create the tangent plane WCS on which the images are defined
    # This is close to that of the reference chip
    R=wcsutil.WCSObject(rimage)
    R.write_archive(rimage)
    R.restore()

    # Reacd in declination of target (for computing orientation at aperture)
    # Note that this is from the reference image
    #dec = float(fileutil.getKeyword(rimage,'CRVAL2'))
    #crval1 = float(fileutil.getKeyword(rimage,'CRVAL1'))
    #crval1 = float(R.crval1)
    #crval2 = dec
    dec = float(R.crval2)

    # Get an approximate reference position on the sky
    rref = (rrefpix['XREF']+ltvoffx, rrefpix['YREF']+ltvoffy)

    crval1,crval2=R.xy2rd(rref)

    if apply_tdd:
        # Correct zero points for TDD
        tddscale = (R.pscale/fx[1][1])
        rxy0 = N.array([[tdd_xyref[Nrefchip][0]-2048.],[ tdd_xyref[Nrefchip][1]-2048.]])
        xy0 = N.array([[tdd_xyref[chip][0]-2048.], [tdd_xyref[chip][1]-2048.]])
        rv23_corr = N.dot(mrotp,N.dot(tdd,rxy0))*tddscale
        v23_corr = N.dot(mrotp,N.dot(tdd,xy0))*tddscale
    else:
        rv23_corr = N.array([[0],[0]])
        v23_corr = N.array([[0],[0]])

    # Convert the PA_V3 orientation to the orientation at the aperture
    # This is for the reference chip only - we use this for the
    # reference tangent plane definition
    # It has the same orientation as the reference chip
    v2ref = rrefpix['V2REF'] +  rv23_corr[0][0]*0.05
    v3ref = rrefpix['V3REF'] - rv23_corr[1][0]*0.05
    v2 = refpix['V2REF'] + v23_corr[0][0]*0.05
    v3 = refpix['V3REF'] - v23_corr[1][0] *0.05

    pv = wcsutil.troll(pvt,dec,v2ref,v3ref)

    # Add the chip rotation angle
    if rrefpix['THETA']:
        pv += rrefpix['THETA']


    # Set values for the rest of the reference WCS
    R.crval1=crval1
    R.crval2=crval2
    R.crpix1=0.0 + offshiftx
    R.crpix2=0.0 + offshifty

    R_scale=rrefpix['PSCALE']/3600.0
    R.cd11=parity[0][0] *  cos(pv*pi/180.0)*R_scale
    R.cd12=parity[0][0] * -sin(pv*pi/180.0)*R_scale
    R.cd21=parity[1][1] *  sin(pv*pi/180.0)*R_scale
    R.cd22=parity[1][1] *  cos(pv*pi/180.0)*R_scale

    ##print R
    R_cdmat = N.array([[R.cd11,R.cd12],[R.cd21,R.cd22]])

    if not quiet:
        print("  Reference Chip Scale (arcsec/pix): ",rrefpix['PSCALE'])

    # Offset and angle in V2/V3 from reference chip to
    # new chip(s) - converted to reference image pixels

    off = sqrt((v2-v2ref)**2 + (v3-v3ref)**2)/(R_scale*3600.0)

    # Here we must include the PARITY
    if v3 == v3ref:
        theta=0.0
    else:
        theta = atan2(parity[0][0]*(v2-v2ref),parity[1][1]*(v3-v3ref))

    if rrefpix['THETA']: theta += rrefpix['THETA']*pi/180.0

    dX=(off*sin(theta)) + offshiftx
    dY=(off*cos(theta)) + offshifty

    # Check to see whether we are working with GEIS or FITS input
    _fname,_iextn = fileutil.parseFilename(image)

    if _fname.find('.fits') < 0:
        # Input image is NOT a FITS file, so
        #     build a FITS name for it's copy.
        _fitsname = fileutil.buildFITSName(_fname)
    else:
        _fitsname = None
    # Create a new instance of a WCS
    if _fitsname == None:
        _new_name = image
    else:
        _new_name = _fitsname+'['+str(_iextn)+']'

    #New=wcsutil.WCSObject(_new_name,new=yes)
    New = Old.copy()

    # Calculate new CRVALs and CRPIXs
    New.crval1,New.crval2=R.xy2rd((dX,dY))
    New.crpix1=refpix['XREF'] + ltvoffx
    New.crpix2=refpix['YREF'] + ltvoffy

    # Account for subarray offset
    # Angle of chip relative to chip
    if refpix['THETA']:
        dtheta = refpix['THETA'] - rrefpix['THETA']
    else:
        dtheta = 0.0

    # Create a small vector, in reference image pixel scale
    # There is no parity effect here ???
    delXX=fx[1,1]/R_scale/3600.
    delYX=fy[1,1]/R_scale/3600.
    delXY=fx[1,0]/R_scale/3600.
    delYY=fy[1,0]/R_scale/3600.

    # Convert to radians
    rr=dtheta*pi/180.0

    # Rotate the vectors
    dXX= cos(rr)*delXX - sin(rr)*delYX
    dYX= sin(rr)*delXX + cos(rr)*delYX

    dXY= cos(rr)*delXY - sin(rr)*delYY
    dYY= sin(rr)*delXY + cos(rr)*delYY

    # Transform to sky coordinates
    a,b=R.xy2rd((dX+dXX,dY+dYX))
    c,d=R.xy2rd((dX+dXY,dY+dYY))

    # Calculate the new CDs and convert to degrees
    New.cd11=diff_angles(a,New.crval1)*cos(New.crval2*pi/180.0)
    New.cd12=diff_angles(c,New.crval1)*cos(New.crval2*pi/180.0)
    New.cd21=diff_angles(b,New.crval2)
    New.cd22=diff_angles(d,New.crval2)

    # Apply the velocity aberration effect if applicable
    if VA_fac != 1.0:

        # First shift the CRVALs apart
#       New.crval1 = ra_targ + VA_fac*(New.crval1 - ra_targ)
#       New.crval2 = dec_targ + VA_fac*(New.crval2 - dec_targ)
        # First shift the CRVALs apart
        # This is now relative to the reference chip, not the
        # target position.
        New.crval1 = R.crval1 + VA_fac*diff_angles(New.crval1, R.crval1)
        New.crval2 = R.crval2 + VA_fac*diff_angles(New.crval2, R.crval2)

        # and scale the CDs
        New.cd11 = New.cd11*VA_fac
        New.cd12 = New.cd12*VA_fac
        New.cd21 = New.cd21*VA_fac
        New.cd22 = New.cd22*VA_fac

    New_cdmat = N.array([[New.cd11,New.cd12],[New.cd21,New.cd22]])

    # Store new one
    # archive=yes specifies to also write out archived WCS keywords
    # overwrite=no specifies do not overwrite any pre-existing archived keywords

    New.write(fitsname=_new_name,overwrite=no,quiet=quiet,archive=yes)
    if _dqname:
        _dq_iextn = _iextn.replace('sci', dqext.lower())
        _new_dqname = _dqname +'['+_dq_iextn+']'
        dqwcs = wcsutil.WCSObject(_new_dqname)
        dqwcs.write(fitsname=_new_dqname, wcs=New,overwrite=no,quiet=quiet, archive=yes)

    """ Convert distortion coefficients into SIP style
        values and write out to image (assumed to be FITS).
    """
    #First the CD matrix:
    f = refpix['PSCALE']/3600.0
    a = fx[1,1]/3600.0
    b = fx[1,0]/3600.0
    c = fy[1,1]/3600.0
    d = fy[1,0]/3600.0
    det = (a*d - b*c)*refpix['PSCALE']

    # Write to header
    fimg = fileutil.openImage(_new_name,mode='update')
    _new_root,_nextn = fileutil.parseFilename(_new_name)
    _new_extn = fileutil.getExtn(fimg,_nextn)


    # Transform the higher-order coefficients
    for n in range(order+1):
        for m in range(order+1):
            if n >= m and n>=2:

                # Form SIP-style keyword names
                Akey="A_%d_%d" % (m,n-m)
                Bkey="B_%d_%d" % (m,n-m)

                # Assign them values
                Aval= f*(d*fx[n,m]-b*fy[n,m])/det
                Bval= f*(a*fy[n,m]-c*fx[n,m])/det

                _new_extn.header.update(Akey,Aval)
                _new_extn.header.update(Bkey,Bval)

    # Update the SIP flag keywords as well
    #iraf.hedit(image,"CTYPE1","RA---TAN-SIP",verify=no,show=no)
    #iraf.hedit(image,"CTYPE2","DEC--TAN-SIP",verify=no,show=no)
    _new_extn.header.update("CTYPE1","RA---TAN-SIP")
    _new_extn.header.update("CTYPE2","DEC--TAN-SIP")

    # Finally we also need the order
    #iraf.hedit(image,"A_ORDER","%d" % order,add=yes,verify=no,show=no)
    #iraf.hedit(image,"B_ORDER","%d" % order,add=yes,verify=no,show=no)
    _new_extn.header.update("A_ORDER",order)
    _new_extn.header.update("B_ORDER",order)

    # Update header with additional keywords required for proper
    # interpretation of SIP coefficients by PyDrizzle.

    _new_extn.header.update("IDCSCALE",refpix['PSCALE'])
    _new_extn.header.update("IDCV2REF",refpix['V2REF'])
    _new_extn.header.update("IDCV3REF",refpix['V3REF'])
    _new_extn.header.update("IDCTHETA",refpix['THETA'])
    _new_extn.header.update("OCX10",fx[1][0])
    _new_extn.header.update("OCX11",fx[1][1])
    _new_extn.header.update("OCY10",fy[1][0])
    _new_extn.header.update("OCY11",fy[1][1])
    #_new_extn.header.update("TDDXOFF",rv23_corr[0][0] - v23_corr[0][0])
    #_new_extn.header.update("TDDYOFF",-(rv23_corr[1][0] - v23_corr[1][0]))

    # Report time-dependent coeffs, if computed
    if instrument == 'ACS' and detector == 'WFC':
        _new_extn.header.update("TDDALPHA",alpha)
        _new_extn.header.update("TDDBETA",beta)


    # Close image now
    fimg.close()
    del fimg
Beispiel #14
0
    def runDriz(self,pixfrac=1.0,kernel='turbo',fillval='INDEF'):
        """ Runs the 'drizzle' algorithm on this specific chip to create
            a numpy object of the undistorted image.

            The resulting drizzled image gets returned as a numpy object.
        """
        #
        # Perform drizzling...
        #
        _wcs = self.geometry.wcs
        _wcsout = self.product_wcs

        # Rigorously compute the orientation changes from WCS
        # information using algorithm provided by R. Hook from WDRIZZLE.
        abxt,cdyt = drutil.wcsfit(self.geometry, self.product_wcs)

        # Compute the rotation and shifts between input and reference WCS.
        xsh = abxt[2]
        ysh = cdyt[2]
        rot = fileutil.RADTODEG(np.arctan2(abxt[1],cdyt[0]))
        scale = self.product_wcs.pscale / self.geometry.wcslin.pscale

        # Now, trim the final output to only match this chip
        _out_naxis1,_out_naxis2 = self.chip_shape

        #
        # Insure that the coeffs file was created
        #
        if not os.path.exists(self.coeffs):
            self.writeCoeffs()

        # A image buffer needs to be setup for converting the input
        # arrays (sci and wht) from FITS format to native format
        # with respect to byteorder and byteswapping.
        # This buffer should be reused for each input.
        #
        _outsci = np.zeros((_out_naxis2,_out_naxis1),dtype=np.float32)
        _outwht = np.zeros((_out_naxis2,_out_naxis1),dtype=np.float32)
        _inwcs = np.zeros([8],dtype=np.float64)

        # Only one chip will ever be drizzled using this method, so
        # the context image will only ever contain 1 bit-plane
        _outctx = np.zeros((_out_naxis2,_out_naxis1),dtype=np.int32)

        # Read in the distortion correction arrays, if specifij8cw08n4q_raw.fitsed
        _pxg,_pyg = self.getDGEOArrays()

        # Open the SCI image
        _expname = self.name
        _handle = fileutil.openImage(_expname,mode='readonly',memmap=0)
        _fname,_extn = fileutil.parseFilename(_expname)
        _sciext = fileutil.getExtn(_handle,extn=_extn)

        # Make a local copy of SCI array and WCS info
        #_insci = _sciext.data.copy()
        _inwcs = drutil.convertWCS(wcsutil.WCSObject(_fname,header=_sciext.header),_inwcs)

        # Compute what plane of the context image this input would
        # correspond to:
        _planeid = 1

        # Select which mask needs to be read in for drizzling
        _inwht = np.ones((self.naxis2,self.naxis1),dtype=np.float32)

        # Default case: wt_scl = exptime
        _wtscl = self.exptime

        # Set additional parameters needed by 'drizzle'
        _expin = self.exptime
        #_in_un = 'counts'
        #_shift_fr = 'output'
        #_shift_un = 'output'
        _uniqid = 1
        ystart = 0
        nmiss = 0
        nskip = 0
        _vers = ''

        #
        # This call to 'arrdriz.tdriz' uses the F2C syntax
        #
        _dny = self.naxis2
        # Call 'drizzle' to perform image combination
        _vers,nmiss,nskip = arrdriz.tdriz(_sciext.data.copy(),_inwht,
                    _outsci, _outwht, _outctx,
                    _uniqid, ystart, 1, 1, _dny,
                    xsh,ysh, 'output','output', rot,scale,
                    self.xsh2,self.ysh2, 1.0, 1.0, 0.0, 'output',
                    _pxg,_pyg,
                    'center', pixfrac, kernel,
                    self.coeffs, 'counts', _expin,_wtscl,
                    fillval, _inwcs, nmiss, nskip, 1,0.,0.)
        #
        # End of F2C syntax
        #

        if nmiss > 0:
            print('! Warning, ',nmiss,' points were outside the output image.')
        if nskip > 0:
            print('! Note, ',nskip,' input lines were skipped completely.')

        # Close image handle
        _handle.close()
        del _handle,_fname,_extn,_sciext
        del _inwht

        del _pxg,_pyg

        del _outwht,_outctx

        return _outsci
Beispiel #15
0
def run_blot(imageObjectList,output_wcs,paramDict,wcsmap=wcs_functions.WCSMap):
    """
    run_blot(imageObjectList, output_wcs, paramDict, wcsmap=wcs_functions.WCSMap)

    Perform the blot operation on the list of images.
    """
    # Insure that input imageObject is a list
    if not isinstance(imageObjectList, list):
        imageObjectList = [imageObjectList]
    #
    # Setup the versions info dictionary for output to PRIMARY header
    # The keys will be used as the name reported in the header, as-is
    #
    _versions = {'AstroDrizzle':__version__,
                 'PyFITS':util.__fits_version__,
                 'Numpy':util.__numpy_version__}

    _hdrlist = []

    for img in imageObjectList:

        for chip in img.returnAllChips(extname=img.scienceExt):

            print('    Blot: creating blotted image: ',chip.outputNames['data'])

            #### Check to see what names need to be included here for use in _hdrlist
            chip.outputNames['driz_version'] = _versions['AstroDrizzle']
            outputvals = chip.outputNames.copy()
            outputvals.update(img.outputValues)
            outputvals['blotnx'] = chip.wcs.naxis1
            outputvals['blotny'] = chip.wcs.naxis2
            _hdrlist.append(outputvals)

            plist = outputvals.copy()
            plist.update(paramDict)

            # PyFITS can be used here as it will always operate on
            # output from PyDrizzle (which will always be a FITS file)
            # Open the input science file
            medianPar = 'outMedian'
            outMedianObj = img.getOutputName(medianPar)
            if img.inmemory:
                outMedian = img.outputNames[medianPar]
                _fname,_sciextn = fileutil.parseFilename(outMedian)
                _inimg = outMedianObj
            else:
                outMedian = outMedianObj
                _fname,_sciextn = fileutil.parseFilename(outMedian)
                _inimg = fileutil.openImage(_fname)

            # Return the PyFITS HDU corresponding to the named extension
            _scihdu = fileutil.getExtn(_inimg,_sciextn)
            _insci = _scihdu.data.copy()
            _inimg.close()
            del _inimg, _scihdu

            _outsci = do_blot(_insci, output_wcs,
                   chip.wcs, chip._exptime, coeffs=paramDict['coeffs'],
                   interp=paramDict['blot_interp'], sinscl=paramDict['blot_sinscl'],
                   wcsmap=wcsmap)
            # Apply sky subtraction and unit conversion to blotted array to
            # match un-modified input array
            if paramDict['blot_addsky']:
                skyval = chip.computedSky
            else:
                skyval = paramDict['blot_skyval']
            _outsci /= chip._conversionFactor
            _outsci += skyval
            log.info('Applying sky value of %0.6f to blotted image %s'%
                        (skyval,chip.outputNames['data']))

            # Write output Numpy objects to a PyFITS file
            # Blotting only occurs from a drizzled SCI extension
            # to a blotted SCI extension...

            _outimg = outputimage.OutputImage(_hdrlist, paramDict, build=False, wcs=chip.wcs, blot=True)
            _outimg.outweight = None
            _outimg.outcontext = None
            outimgs = _outimg.writeFITS(plist['data'],_outsci,None,
                                versions=_versions,blend=False,
                                virtual=img.inmemory)

            img.saveVirtualOutputs(outimgs)
            #_buildOutputFits(_outsci,None,plist['outblot'])
            _hdrlist = []

            del _outsci

        del _outimg
Beispiel #16
0
def run(configObj, wcsmap=None):
    """
    Run the blot task based on parameters provided interactively by the user.

    """

    # Insure all output filenames specified have .fits extensions
    if configObj['outdata'][-5:] != '.fits': configObj['outdata'] += '.fits'

    scale_pars = configObj['Data Scaling Parameters']
    user_wcs_pars = configObj['User WCS Parameters']

    # PyFITS can be used here as it will always operate on
    # output from PyDrizzle (which will always be a FITS file)
    # Open the input (drizzled?) image
    _fname, _sciextn = fileutil.parseFilename(configObj['data'])
    _inimg = fileutil.openImage(_fname, memmap=False)
    _expin = fileutil.getKeyword(configObj['data'],
                                 scale_pars['expkey'],
                                 handle=_inimg)

    # Return the PyFITS HDU corresponding to the named extension
    _scihdu = fileutil.getExtn(_inimg, _sciextn)
    _insci = _scihdu.data.copy()

    _inexptime = 1.0
    if scale_pars['in_units'] == 'counts':
        if scale_pars['expkey'] in _inimg['PRIMARY'].header:
            _inexptime = _inimg['PRIMARY'].header[scale_pars['expkey']]
        elif 'DRIZEXPT' in _inimg['PRIMARY'].header:
            # Try keyword written out by new 'drizzle' if no valid 'expkey' was given
            _inexptime = _inimg['PRIMARY'].header['DRIZEXPT']
        else:
            raise ValueError('No valid exposure time keyword could be found '
                             'for input %s' % configObj['data'])
    # always convert input to 'cps' for blot() algorithm
    if _inexptime != 0.0 or _inexptime != 1.0:
        np.divide(_insci, _inexptime, _insci)

    _inimg.close()
    del _inimg

    # read in WCS from source (drizzled) image
    source_wcs = stwcs.wcsutil.HSTWCS(configObj['data'])
    if source_wcs.wcs.is_unity():
        print(
            "WARNING: No valid WCS found for input drizzled image: {}!".format(
                configObj['data']))

    # define blot_wcs
    blot_wcs = None
    _refname, _refextn = fileutil.parseFilename(configObj['reference'])
    if os.path.exists(_refname):
        # read in WCS from pre-existing output image
        blot_wcs = stwcs.wcsutil.HSTWCS(configObj['reference'])
        if blot_wcs.wcs.is_unity():
            print("WARNING: No valid WCS found for output image: {} !".format(
                configObj['reference']))

    # define blot WCS based on input images or specified reference WCS values
    if user_wcs_pars['user_wcs']:
        blot_wcs = wcs_functions.build_hstwcs(user_wcs_pars['raref'],
                                              user_wcs_pars['decref'],
                                              user_wcs_pars['xrefpix'],
                                              user_wcs_pars['yrefpix'],
                                              int(user_wcs_pars['outnx']),
                                              int(user_wcs_pars['outny']),
                                              user_wcs_pars['outscale'],
                                              user_wcs_pars['orient'])
        configObj['coeffs'] = None

    # If blot_wcs is still not defined at this point, we have a problem...
    if blot_wcs is None:
        blot_wcs = stwcs.distortion.utils.output_wcs([source_wcs],
                                                     undistort=False)

    out_wcs = blot_wcs.copy()
    # perform blotting operation now
    _outsci = do_blot(_insci,
                      source_wcs,
                      out_wcs,
                      _expin,
                      coeffs=configObj['coeffs'],
                      interp=configObj['interpol'],
                      sinscl=configObj['sinscl'],
                      stepsize=configObj['stepsize'],
                      wcsmap=wcsmap)
    # create output with proper units and exptime-scaling
    if scale_pars['out_units'] == 'counts':
        if scale_pars['expout'] == 'input':
            _outscale = fileutil.getKeyword(configObj['reference'],
                                            scale_pars['expkey'])
            #_outscale = _expin
        else:
            _outscale = float(scale_pars['expout'])
        print(
            "Output blotted images scaled by exptime of {}".format(_outscale))
        np.multiply(_outsci, _outscale, _outsci)

    # Add sky back in to the blotted image, as specified by the user
    if configObj['addsky']:
        skyval = _scihdu.header['MDRIZSKY']
    else:
        skyval = configObj['skyval']
    print("Added {} counts back in to blotted image as sky.".format(skyval))
    _outsci += skyval

    del _scihdu

    # Write output Numpy objects to a PyFITS file
    # Blotting only occurs from a drizzled SCI extension
    # to a blotted SCI extension...
    outputimage.writeSingleFITS(_outsci, blot_wcs, configObj['outdata'],
                                configObj['reference'])
Beispiel #17
0
def run_blot(imageObjectList,
             output_wcs,
             paramDict,
             wcsmap=wcs_functions.WCSMap):
    """
    run_blot(imageObjectList, output_wcs, paramDict, wcsmap=wcs_functions.WCSMap)

    Perform the blot operation on the list of images.
    """
    # Insure that input imageObject is a list
    if not isinstance(imageObjectList, list):
        imageObjectList = [imageObjectList]
    #
    # Setup the versions info dictionary for output to PRIMARY header
    # The keys will be used as the name reported in the header, as-is
    #
    _versions = {
        'AstroDrizzle': __version__,
        'PyFITS': util.__fits_version__,
        'Numpy': util.__numpy_version__
    }

    _hdrlist = []

    for img in imageObjectList:

        for chip in img.returnAllChips(extname=img.scienceExt):

            print('    Blot: creating blotted image: ',
                  chip.outputNames['data'])

            #### Check to see what names need to be included here for use in _hdrlist
            chip.outputNames['driz_version'] = _versions['AstroDrizzle']
            outputvals = chip.outputNames.copy()
            outputvals.update(img.outputValues)
            outputvals['blotnx'] = chip.wcs.naxis1
            outputvals['blotny'] = chip.wcs.naxis2
            _hdrlist.append(outputvals)

            plist = outputvals.copy()
            plist.update(paramDict)

            # PyFITS can be used here as it will always operate on
            # output from PyDrizzle (which will always be a FITS file)
            # Open the input science file
            medianPar = 'outMedian'
            outMedianObj = img.getOutputName(medianPar)
            if img.inmemory:
                outMedian = img.outputNames[medianPar]
                _fname, _sciextn = fileutil.parseFilename(outMedian)
                _inimg = outMedianObj
            else:
                outMedian = outMedianObj
                _fname, _sciextn = fileutil.parseFilename(outMedian)
                _inimg = fileutil.openImage(_fname, memmap=False)

            # Return the PyFITS HDU corresponding to the named extension
            _scihdu = fileutil.getExtn(_inimg, _sciextn)
            _insci = _scihdu.data.copy()
            _inimg.close()
            del _inimg, _scihdu

            _outsci = do_blot(_insci,
                              output_wcs,
                              chip.wcs,
                              chip._exptime,
                              coeffs=paramDict['coeffs'],
                              interp=paramDict['blot_interp'],
                              sinscl=paramDict['blot_sinscl'],
                              wcsmap=wcsmap)
            # Apply sky subtraction and unit conversion to blotted array to
            # match un-modified input array
            if paramDict['blot_addsky']:
                skyval = chip.computedSky
            else:
                skyval = paramDict['blot_skyval']
            _outsci /= chip._conversionFactor
            if skyval is not None:
                _outsci += skyval
                log.info('Applying sky value of %0.6f to blotted image %s' %
                         (skyval, chip.outputNames['data']))

            # Write output Numpy objects to a PyFITS file
            # Blotting only occurs from a drizzled SCI extension
            # to a blotted SCI extension...

            _outimg = outputimage.OutputImage(_hdrlist,
                                              paramDict,
                                              build=False,
                                              wcs=chip.wcs,
                                              blot=True)
            _outimg.outweight = None
            _outimg.outcontext = None
            outimgs = _outimg.writeFITS(plist['data'],
                                        _outsci,
                                        None,
                                        versions=_versions,
                                        blend=False,
                                        virtual=img.inmemory)

            img.saveVirtualOutputs(outimgs)
            #_buildOutputFits(_outsci,None,plist['outblot'])
            _hdrlist = []

            del _outsci

        del _outimg
Beispiel #18
0
def run(configObj,wcsmap=None):
    """
    Run the blot task based on parameters provided interactively by the user.

    """

    # Insure all output filenames specified have .fits extensions
    if configObj['outdata'][-5:] != '.fits': configObj['outdata'] += '.fits'

    scale_pars = configObj['Data Scaling Parameters']
    user_wcs_pars = configObj['User WCS Parameters']

    # PyFITS can be used here as it will always operate on
    # output from PyDrizzle (which will always be a FITS file)
    # Open the input (drizzled?) image
    _fname,_sciextn = fileutil.parseFilename(configObj['data'])
    _inimg = fileutil.openImage(_fname)
    _expin = fileutil.getKeyword(configObj['data'],scale_pars['expkey'],handle=_inimg)

    # Return the PyFITS HDU corresponding to the named extension
    _scihdu = fileutil.getExtn(_inimg,_sciextn)
    _insci = _scihdu.data.copy()

    _inexptime = 1.0
    if scale_pars['in_units'] == 'counts':
        if scale_pars['expkey'] in _inimg['PRIMARY'].header:
            _inexptime = _inimg['PRIMARY'].header[scale_pars['expkey']]
        elif 'DRIZEXPT' in _inimg['PRIMARY'].header:
            # Try keyword written out by new 'drizzle' if no valid 'expkey' was given
            _inexptime = _inimg['PRIMARY'].header['DRIZEXPT']
        else:
            raise ValueError('No valid exposure time keyword could be found '
                             'for input %s' % configObj['data'])
    # always convert input to 'cps' for blot() algorithm
    if _inexptime != 0.0 or _inexptime != 1.0:
        np.divide(_insci, _inexptime, _insci)

    _inimg.close()
    del _inimg

    # read in WCS from source (drizzled) image
    source_wcs = stwcs.wcsutil.HSTWCS(configObj['data'])
    if source_wcs.wcs.is_unity():
        print("WARNING: No valid WCS found for input drizzled image: {}!".format(configObj['data']))

    # define blot_wcs
    blot_wcs = None
    _refname,_refextn = fileutil.parseFilename(configObj['reference'])
    if os.path.exists(_refname):
        # read in WCS from pre-existing output image
        blot_wcs = stwcs.wcsutil.HSTWCS(configObj['reference'])
        if blot_wcs.wcs.is_unity():
            print("WARNING: No valid WCS found for output image: {} !".format(configObj['reference']))

    # define blot WCS based on input images or specified reference WCS values
    if user_wcs_pars['user_wcs']:
        blot_wcs = wcs_functions.build_hstwcs(
            user_wcs_pars['raref'], user_wcs_pars['decref'],
            user_wcs_pars['xrefpix'], user_wcs_pars['yrefpix'],
            user_wcs_pars['outnx'], user_wcs_pars['outny'],
            user_wcs_pars['outscale'], user_wcs_pars['orient'] )
        configObj['coeffs'] = None

    # If blot_wcs is still not defined at this point, we have a problem...
    if blot_wcs is None:
        blot_wcs = stwcs.distortion.utils.output_wcs([source_wcs],undistort=False)

    out_wcs = blot_wcs.copy()
    # perform blotting operation now
    _outsci = do_blot(_insci, source_wcs, out_wcs, _expin, coeffs=configObj['coeffs'],
                    interp=configObj['interpol'], sinscl=configObj['sinscl'],
            stepsize=configObj['stepsize'], wcsmap=wcsmap)
    # create output with proper units and exptime-scaling
    if scale_pars['out_units'] == 'counts':
        if scale_pars['expout'] == 'input':
            _outscale = fileutil.getKeyword(configObj['reference'],scale_pars['expkey'])
            #_outscale = _expin
        else:
            _outscale = float(scale_pars['expout'])
        print("Output blotted images scaled by exptime of {}".format(_outscale))
        np.multiply(_outsci, _outscale, _outsci)

    # Add sky back in to the blotted image, as specified by the user
    if configObj['addsky']:
        skyval = _scihdu.header['MDRIZSKY']
    else:
        skyval = configObj['skyval']
    print("Added {} counts back in to blotted image as sky.".format(skyval))
    _outsci += skyval

    del _scihdu

    # Write output Numpy objects to a PyFITS file
    # Blotting only occurs from a drizzled SCI extension
    # to a blotted SCI extension...
    outputimage.writeSingleFITS(_outsci,blot_wcs, configObj['outdata'],configObj['reference'])