Instruction:
Can you generate a brief explanation for the following Python 3 code
def close(self):
        if self._image is None:
            return

        # mcara: I think the code below is not necessary but in order to
        #        preserve the same functionality as the code removed below,
        #        I make an empty copy of the image object:
        empty_image = fits.HDUList()
        for u in self._image:
            empty_image.append(u.__class__(data=None, header=None))
        # mcara: END unnecessary code

        self._image.close()  #calls fits.close()

        self._image = empty_image

Response: Close the image object and release all the data arrays.


Instruction:
Make a summary of the following Python 3 code
def clean(self):
        clean_files = ['blotImage','crmaskImage','finalMask',
                        'staticMask','singleDrizMask','outSky',
                        'outSContext','outSWeight','outSingle',
                        'outMedian','dqmask','tmpmask',
                        'skyMatchMask']

        log.info('Removing intermediate files for %s' % self._filename)
        # We need to remove the combined products first; namely, median image
        util.removeFileSafely(self.outputNames['outMedian'])
        # Now remove chip-specific intermediate files, if any were created.
        for chip in self.returnAllChips(extname='SCI'):
            for fname in clean_files:
                if fname in chip.outputNames:
                    util.removeFileSafely(chip.outputNames[fname])

Response: Deletes intermediate products generated for this imageObject.


Instruction:
Can you create a Python 3 function that
returns just the data array from the specified extension fileutil is used instead of fits to account for non - accurate FITS input images.

Response:
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=False)
                _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


Instruction:
Can you generate the documentation for the following Python 3 function
def getHeader(self,exten=None):
        _image=fileutil.openImage(self._filename, clobber=False, memmap=False)
        _header=fileutil.getExtn(_image,extn=exten).header
        _image.close()
        del _image
        return _header

Response:
Return just the specified header extension fileutil
            is used instead of fits.


Instruction:
Can you write a function in Python 3 where it
writes out updated data and header to the original input file for this object.

Response:
def updateData(self,exten,data):
        """ Write out updated data and header to
            the original input file for this object.
        """
        _extnum=self._interpretExten(exten)
        fimg = fileutil.openImage(self._filename, mode='update', memmap=False)
        fimg[_extnum].data = data
        fimg[_extnum].header = self._image[_extnum].header
        fimg.close()


Instruction:
Here you have a function in Python 3, explain what it does
def getAllData(self,extname=None,exclude=None):

        extensions = self._findExtnames(extname=extname,exclude=exclude)

        for i in range(1,self._nextend+1,1):
            if hasattr(self._image[i],'_extension') and \
                "IMAGE" in self._image[i]._extension:
                extver = self._image[i].header['extver']
                if (self._image[i].extname in extensions) and self._image[self.scienceExt,extver].group_member:
                    self._image[i].data=self.getData(self._image[i].extname + ','+str(self._image[i].extver))

Response:
This function gets all the data from the original
            file and attaches it to the image object.


Instruction:
Can you implement a function in Python 3 that
returns a list containing all the chips which match the given extname minus those specified for exclusion.

Response:
def returnAllChips(self,extname=None,exclude=None):
        """ Returns a list containing all the chips which match the
            extname given minus those specified for exclusion (if any).
        """
        extensions = self._findExtnames(extname=extname,exclude=exclude)
        chiplist = []
        for i in range(1,self._nextend+1,1):
            if 'extver' in self._image[i].header:
                extver = self._image[i].header['extver']
            else:
                extver = 1
            if hasattr(self._image[i],'_extension') and \
                "IMAGE" in self._image[i]._extension:
                if (self._image[i].extname in extensions) and self._image[self.scienceExt,extver].group_member:
                    chiplist.append(self._image[i])
        return chiplist


Instruction:
How would you explain what the following Python 3 function does
def _findExtnames(self, extname=None, exclude=None):
        #make a list of the available extension names for the object
        extensions=[]
        if extname is not None:
            if not isinstance(extname,list): extname=[extname]
            for extn in extname:
                extensions.append(extn.upper())
        else:
        #restore all the extensions data from the original file, be careful here
        #if you've altered data in memory you want to keep!
            for i in range(1,self._nextend+1,1):
                if hasattr(self._image[i],'_extension') and \
                    "IMAGE" in self._image[i]._extension:
                    if self._image[i].extname.upper() not in extensions:
                        extensions.append(self._image[i].extname)
        #remove this extension from the list
        if exclude is not None:
            exclude.upper()
            if exclude in extensions:
                newExt=[]
                for item in extensions:
                    if item != exclude:
                        newExt.append(item)
            extensions=newExt
            del newExt
        return extensions

Response: This method finds all the available extensions for the image and returns a list of all the available extensions for the image.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def findExtNum(self, extname=None, extver=1):
        extnum = None
        extname = extname.upper()

        if not self._isSimpleFits:
            for ext in self._image:
                if (hasattr(ext,'_extension') and 'IMAGE' in ext._extension and
                    (ext.extname == extname) and (ext.extver == extver)):
                    extnum = ext.extnum
        else:
            log.info("Image is simple fits")

        return extnum

Response: Find the extension number of the give extname and extver.


Instruction:
Write a Python 3 script for
assigning a unique rootname for the image based in the expname.

Response:
def _assignRootname(self, chip):
        """ Assign a unique rootname for the image based in the expname. """
        extname=self._image[self.scienceExt,chip].header["EXTNAME"].lower()
        extver=self._image[self.scienceExt,chip].header["EXTVER"]
        expname = self._rootname

        # record extension-based name to reflect what extension a mask file corresponds to
        self._image[self.scienceExt,chip].rootname=expname + "_" + extname + str(extver)
        self._image[self.scienceExt,chip].sciname=self._filename + "[" + extname +","+str(extver)+"]"
        self._image[self.scienceExt,chip].dqrootname=self._rootname + "_" + extname + str(extver)
        # Needed to keep EXPNAMEs associated properly (1 EXPNAME for all chips)
        self._image[self.scienceExt,chip]._expname=expname
        self._image[self.scienceExt,chip]._chip =chip


Instruction:
Can you generate the documentation for the following Python 3 function
def _setOutputNames(self,rootname,suffix='_drz'):
        # Define FITS output filenames for intermediate products

        # Build names based on final DRIZZLE output name
        # where 'output' normally would have been created
        #   by 'process_input()'
        #
        outFinal = rootname+suffix+'.fits'
        outSci = rootname+suffix+'_sci.fits'
        outWeight = rootname+suffix+'_wht.fits'
        outContext = rootname+suffix+'_ctx.fits'
        outMedian = rootname+'_med.fits'

        # Build names based on input name
        origFilename = self._filename.replace('.fits','_OrIg.fits')
        outSky = rootname + '_sky.fits'
        outSingle = rootname+'_single_sci.fits'
        outSWeight = rootname+'_single_wht.fits'
        crCorImage = rootname+'_crclean.fits'

        # Build outputNames dictionary
        fnames={
            'origFilename': origFilename,
            'outFinal': outFinal,
            'outMedian': outMedian,
            'outSci': outSci,
            'outWeight': outWeight,
            'outContext': outContext,
            'outSingle': outSingle,
            'outSWeight': outSWeight,
            'outSContext': None,
            'outSky': outSky,
            'crcorImage': crCorImage,
            'ivmFile': None
        }

        return fnames

Response: Define the default output names for drizzle products and their intermediate products.


Instruction:
How would you code a function in Python 3 to
initialize the virtual output structures for this image.

Response:
def _initVirtualOutputs(self):
        """ Sets up the structure to hold all the output data arrays for
        this image in memory.
        """
        self.virtualOutputs = {}
        for product in self.outputNames:
            self.virtualOutputs[product] = None


Instruction:
Can you generate a brief explanation for the following Python 3 code
def saveVirtualOutputs(self,outdict):
        if not self.inmemory:
            return
        for outname in outdict:
            self.virtualOutputs[outname] = outdict[outname]

Response: Assign in - memory versions of generated products based on dictionary outdict.


Instruction:
How would you implement a function in Python 3 that
returns the name of the file or PyFITS object associated with that name depending on the setting of self. inmemory.

Response:
def getOutputName(self,name):
        """ Return the name of the file or PyFITS object associated with that
        name, depending on the setting of self.inmemory.
        """
        val = self.outputNames[name]
        if self.inmemory: # if inmemory was turned on...
            # return virtualOutput object saved with that name
            val = self.virtualOutputs[val]
        return val


Instruction:
Given the following Python 3 function, write the documentation
def updateOutputValues(self,output_wcs):
        outputvals = self.outputValues

        outputvals['output'] = output_wcs.outputNames['outFinal']
        outputvals['outnx'], outputvals['outny'] = output_wcs.wcs.pixel_shape
        outputvals['texptime'] = output_wcs._exptime
        outputvals['texpstart'] = output_wcs._expstart
        outputvals['texpend'] = output_wcs._expend
        outputvals['nimages'] = output_wcs.nimages

        outputvals['scale'] = output_wcs.wcs.pscale #/ self._image[self.scienceExt,1].wcs.pscale
        outputvals['exptime'] = self._exptime

        outnames = self.outputNames
        outnames['outMedian'] = output_wcs.outputNames['outMedian']
        outnames['outFinal'] = output_wcs.outputNames['outFinal']
        outnames['outSci'] = output_wcs.outputNames['outSci']
        outnames['outWeight'] = output_wcs.outputNames['outWeight']
        outnames['outContext'] = output_wcs.outputNames['outContext']

Response: Update the output values for each chip in the image.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def updateContextImage(self, contextpar):
        self.createContext = contextpar
        if not contextpar:
            log.info('No context image will be created for %s' %
                     self._filename)
            self.outputNames['outContext'] = None

Response: Update the name of the context image to None.


Instruction:
Explain what the following Python 3 code does
def find_DQ_extension(self):
        dqfile = None
        dq_suffix=None
        if(self.maskExt is not None):
            for hdu in self._image:
                # Look for DQ extension in input file
                if 'extname' in hdu.header and hdu.header['extname'].lower() == self.maskExt.lower():
                    dqfile = self._filename
                    dq_suffix=self.maskExt
                    break

        return dqfile,dq_suffix

Response:
Return the suffix for the data quality extension and the name of
        the file which that DQ extension should be read from.


Instruction:
Explain what the following Python 3 code does
def getKeywordList(self, kw):
        kwlist = []
        for chip in range(1,self._numchips+1,1):
            sci_chip = self._image[self.scienceExt,chip]
            if sci_chip.group_member:
                kwlist.append(sci_chip.__dict__[kw])

        return kwlist

Response:
Returns a list of all attribute values for all active chips in the
           .


Instruction:
Given the following Python 3 function, write the documentation
def getflat(self, chip):
        sci_chip = self._image[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])
        hdulist = None
        try:
            hdulist = fileutil.openImage(filename, mode='readonly',
                                         memmap=False)
            data = hdulist[(self.scienceExt, chip)].data

            if data.shape[0] != sci_chip.image_shape[0]:
                ltv2 = int(np.round(sci_chip.ltv2))
            else:
                ltv2 = 0
            size2 = sci_chip.image_shape[0] + ltv2

            if data.shape[1] != sci_chip.image_shape[1]:
                ltv1 = int(np.round(sci_chip.ltv1))
            else:
                ltv1 = 0
            size1 = sci_chip.image_shape[1] + ltv1

            flat = data[ltv2:size2, ltv1:size1]

        except FileNotFoundError:
            flat = np.ones(sci_chip.image_shape, dtype=sci_chip.image_dtype)
            log.warning("Cannot find flat field file '{}'".format(filename))
            log.warning("Treating flatfield as a constant value of '1'.")

        finally:
            if hdulist is not None:
                hdulist.close()

        return flat

Response: Method for retrieving a detector s flat field.


Instruction:
Explain what the following Python 3 code does
def getReadNoiseImage(self, chip):
        sci_chip = self._image[self.scienceExt,chip]
        return np.ones(sci_chip.image_shape,dtype=sci_chip.image_dtype) * sci_chip._rdnoise

Response: Method for returning the read noise image of a specific chip.


Instruction:
How would you code a function in Python 3 to
note ===== Return an array representing the exposure time per pixel for the detector. This method will be overloaded for IR detectors which have their own EXP arrays, namely, WFC3/IR and NICMOS images. :units: None Returns ======= exptimeimg : numpy array The method will return an array of the same shape as the image.

Response:
def getexptimeimg(self,chip):
        """
        Notes
        =====
        Return an array representing the exposure time per pixel for the detector.
        This method will be overloaded for IR detectors which have their own
        EXP arrays, namely, WFC3/IR and NICMOS images.

        :units:
          None

        Returns
        =======
        exptimeimg : numpy array
            The method will return an array of the same shape as the image.

        """
        sci_chip = self._image[self.scienceExt,chip]
        if sci_chip._wtscl_par == 'expsq':
            wtscl = sci_chip._exptime*sci_chip._exptime
        else:
            wtscl = sci_chip._exptime

        return np.ones(sci_chip.image_shape,dtype=sci_chip.image_dtype)*wtscl


Instruction:
Can you create a Python 3 function that
returns an array representing the dark image for the detector.

Response:
def getdarkimg(self,chip):
        """
        Notes
        =====
        Return an array representing the dark image for the detector.

        The method will return an array of the same shape as the image.

        :units: electrons
        """
        sci_chip = self._image[self.scienceExt,chip]
        return np.ones(sci_chip.image_shape,dtype=sci_chip.image_dtype)*sci_chip.darkcurrent


Instruction:
Write a Python 3 script for
returning the sky image for the detector.

Response:
def getskyimg(self,chip):
        """
        Notes
        =====
        Return an array representing the sky image for the detector.  The value
        of the sky is what would actually be subtracted from the exposure by
        the skysub step.

        :units: electrons

        """
        sci_chip = self._image[self.scienceExt,chip]
        return np.ones(sci_chip.image_shape,dtype=sci_chip.image_dtype)*sci_chip.subtractedSky


Instruction:
Write a Python 3 script to
return the list of EXTVER values for extensions with name specified in extname.

Response:
def getExtensions(self, extname='SCI', section=None):
        """ Return the list of EXTVER values for extensions with name specified
        in extname.

        """
        if section is None:
            numext = 0
            section = []
            for hdu in self._image:
                if 'extname' in hdu.header and hdu.header['extname'] == extname:
                    section.append(hdu.header['extver'])
        else:
            if not isinstance(section,list):
                section = [section]

        return section


Instruction:
Can you write a function in Python 3 where it
counts the number of extensions in the given file.

Response:
def _countEXT(self,extname="SCI"):
        """ Count the number of extensions in the file with the given name
        (``EXTNAME``).

        """
        count=0 #simple fits image

        if (self._image['PRIMARY'].header["EXTEND"]):
            for i,hdu in enumerate(self._image):
                if i > 0:
                    hduExtname = False
                    if 'EXTNAME' in hdu.header:
                        self._image[i].extnum=i
                        self._image[i].extname=hdu.header["EXTNAME"]
                        hduExtname = True
                    if 'EXTVER' in hdu.header:
                        self._image[i].extver=hdu.header["EXTVER"]
                    else:
                        self._image[i].extver = 1

                    if ((extname is not None) and \
                            (hduExtname and (hdu.header["EXTNAME"] == extname))) \
                            or extname is None:
                        count=count+1
        return count


Instruction:
Can you tell what is the following Python 3 function doing
def buildMask(self,chip,bits=0,write=False):
        dqarr = self.getData(exten=self.maskExt+','+str(chip))
        dqmask = buildmask.buildMask(dqarr,bits)

        if write:
            phdu = fits.PrimaryHDU(data=dqmask,header=self._image[self.maskExt,chip].header)
            dqmask_name = self._image[self.scienceExt,chip].dqrootname+'_dqmask.fits'
            log.info('Writing out DQ/weight mask: %s' % dqmask_name)
            if os.path.exists(dqmask_name): os.remove(dqmask_name)
            phdu.writeto(dqmask_name)
            del phdu
            self._image[self.scienceExt,chip].dqmaskname = dqmask_name
            # record the name of this mask file that was created for later
            # removal by the 'clean()' method
            self._image[self.scienceExt,chip].outputNames['dqmask'] = dqmask_name
        del dqarr
        return dqmask

Response: Build a mask for a particular chip and return it.


Instruction:
How would you explain what the following Python 3 function does
def buildEXPmask(self, chip, dqarr):
        log.info("Applying EXPTIME weighting to DQ mask for chip %s" %
                 chip)
        #exparr = self.getexptimeimg(chip)
        exparr = self._image[self.scienceExt,chip]._exptime
        expmask = exparr*dqarr

        return expmask.astype(np.float32)

Response:
Builds a weight mask from an input DQ array and the exposure time
        per pixel for this chip.


Instruction:
Can you tell what is the following Python 3 function doing
def buildIVMmask(self ,chip, dqarr, scale):
        sci_chip = self._image[self.scienceExt,chip]
        ivmname = self.outputNames['ivmFile']

        if ivmname is not 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', memmap=False)
            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)

Response: Builds a weight mask from an input DQ array and an IVM array derived from the input image.


Instruction:
How would you code a function in Python 3 to
build a weight mask from an input DQ array and an ERR array and an exposure time.

Response:
def buildERRmask(self,chip,dqarr,scale):
        """
        Builds a weight mask from an input DQ array and an ERR array
        associated with the input image.
        """
        sci_chip = self._image[self.scienceExt,chip]

        # Set default value in case of error, or lack of ERR array
        errmask = dqarr

        if self.errExt is not None:
            try:
                # Attempt to open the ERR image.
                err = self.getData(exten=self.errExt+','+str(chip))

                log.info("Applying ERR weighting to DQ mask for chip %s" %
                         chip)

                # Multiply the scaled ERR file by the input mask in place.
                #exptime = self.getexptimeimg(chip)
                exptime = sci_chip._exptime
                errmask = (exptime/err)**2 * 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)

                del err

            except:
                # We cannot find an 'ERR' extension and the data isn't WFPC2.
                # Print a generic warning message and continue on with the
                # final drizzle step.

                print(textutil.textbox(
                    'WARNING: No ERR weighting will be applied to the mask '
                    'used in the final drizzle step!  Weighting will be only '
                    'by exposure time.\n\nThe data provided as input does not '
                    'contain an ERR extension'), file=sys.stderr)
                print('\n Continue with final drizzle step...', sys.stderr)
        else:
            # If we were unable to find an 'ERR' extension to apply, one
            # possible reason was that the input was a 'standard' WFPC2 data
            # file that does not actually contain an error array.  Test for
            # this condition and issue a Warning to the user and continue on to
            # the final drizzle.

            print(textutil.textbox(
                "WARNING: No ERR weighting will be applied to the mask used "
                "in the final drizzle step!  Weighting will be only by "
                "exposure time.\n\nThe WFPC2 data provided as input does not "
                "contain ERR arrays.  WFPC2 data is not supported by this "
                "weighting type.\n\nA workaround would be to create inverse "
                "variance maps and use 'IVM' as the final_wht_type.  See the "
                "HELP file for more details on using inverse variance maps."),
                file=sys.stderr)
            print("\n Continue with final drizzle step...", file=sys.stderr)

        return errmask.astype(np.float32)


Instruction:
How would you explain what the following Python 3 function does
def set_mt_wcs(self, image):
        for chip in range(1,self._numchips+1,1):
            sci_chip = self._image[self.scienceExt,chip]
            ref_chip = image._image[image.scienceExt,chip]
            # Do we want to keep track of original WCS or not? No reason now...
            sci_chip.wcs = ref_chip.wcs.copy()

Response: Reset the WCS for this image based on the WCS information from the WCS information from another imageObject.


Instruction:
Can you tell what is the following Python 3 function doing
def set_wtscl(self, chip, wtscl_par):
        sci_chip = self._image[self.scienceExt,chip]

        exptime = 1 #sci_chip._exptime
        _parval = 'unity'
        if wtscl_par is not None:
            if type(wtscl_par) == type(''):
                if not wtscl_par.isdigit():
                    # String passed in as value, check for 'exptime' or 'expsq'
                    _wtscl_float = None
                    try:
                        _wtscl_float = float(wtscl_par)
                    except ValueError:
                        _wtscl_float = None
                    if _wtscl_float is not None:
                        _wtscl = _wtscl_float
                    elif wtscl_par == 'expsq':
                        _wtscl = exptime*exptime
                        _parval = 'expsq'
                    else:
                        # Default to the case of 'exptime', if
                        #   not explicitly specified as 'expsq'
                        _wtscl = exptime
                else:
                    # int value passed in as a string, convert to float
                    _wtscl = float(wtscl_par)
            else:
                # We have a non-string value passed in...
                _wtscl = float(wtscl_par)
        else:
            # Default case: wt_scl = exptime
            _wtscl = exptime

        sci_chip._wtscl_par = _parval
        sci_chip._wtscl = _wtscl

Response: Sets the value of the wt_scl parameter as needed for drizzling.


Instruction:
Given the following Python 3 function, write the documentation
def getInstrParameter(self, value, header, keyword):
        if isinstance(value, str) and value in ['None', '', ' ', 'INDEF']:
            value = None

        if value and (keyword is not None and keyword.strip() != ''):
            exceptionMessage = "ERROR: Your input is ambiguous!  Please specify either a value or a keyword.\n  You specifed both " + str(value) + " and " + str(keyword)
            raise ValueError(exceptionMessage)

        elif value is not None and value != '':
            return self._averageFromList(value)

        elif keyword is not None and keyword.strip() != '':
            return self._averageFromHeader(header, keyword)

        else:
            return None

Response:
This method gets the instrument parameter from the a
            pair of task parameters.


Instruction:
Create a Python 3 function for
averaging out values taken from header. The keywords where to read values from are passed as a comma - separated list.

Response:
def _averageFromHeader(self, header, keyword):
        """ Averages out values taken from header. The keywords where
            to read values from are passed as a comma-separated list.
        """
        _list = ''
        for _kw in keyword.split(','):
            if _kw in header:
                _list = _list + ',' + str(header[_kw])
            else:
                return None
        return self._averageFromList(_list)


Instruction:
Can you tell what is the following Python 3 function doing
def _averageFromList(self, param):
        _result = 0.0
        _count = 0

        for _param in param.split(','):
            if _param != '' and float(_param) != 0.0:
                _result = _result + float(_param)
                _count  += 1

        if _count >= 1:
            _result = _result / _count
        return _result

Response:
Averages out values passed as a comma - separated
            list disregarding the zero - valued entries.


Instruction:
Write a Python 3 function for
computing the undistorted WCS based solely on the known distortion model information associated with the WCS.

Response:
def compute_wcslin(self,undistort=True):
        """ Compute the undistorted WCS based solely on the known distortion
            model information associated with the WCS.
        """
        for chip in range(1,self._numchips+1,1):
            sci_chip = self._image[self.scienceExt,chip]
            chip_wcs = sci_chip.wcs.copy()

            if chip_wcs.sip is None or not undistort or chip_wcs.instrument=='DEFAULT':
                chip_wcs.sip = None
                chip_wcs.cpdis1 = None
                chip_wcs.cpdis2 = None
                chip_wcs.det2im = None
                undistort=False

            # compute the undistorted 'natural' plate scale for this chip
            wcslin = distortion.utils.output_wcs([chip_wcs],undistort=undistort)
            sci_chip.wcslin_pscale = wcslin.pscale


Instruction:
Can you write a function in Python 3 where it
defines units for this image.

Response:
def set_units(self,chip):
        """ Define units for this image.
        """
        # Determine output value of BUNITS
        # and make sure it is not specified as 'ergs/cm...'
        sci_chip = self._image[self.scienceExt,chip]

        _bunit = None
        if 'BUNIT' in sci_chip.header and sci_chip.header['BUNIT'].find('ergs') < 0:
            _bunit = sci_chip.header['BUNIT']
        else:
            _bunit = 'ELECTRONS/S'
        sci_chip._bunit = _bunit
        #
        if '/s' in _bunit.lower():
            _in_units = 'cps'
        else:
            _in_units = 'counts'
        sci_chip.in_units = _in_units


Instruction:
Write a Python 3 function that can
process all headers to produce a set of combined headers that follows the rules defined by each instrument.

Response:
def getTemplates(fnames, blend=True):
    """ Process all headers to produce a set of combined headers
        that follows the rules defined by each instrument.

    """
    if not blend:
        newhdrs =  blendheaders.getSingleTemplate(fnames[0])
        newtab = None
    else:
        # apply rules to create final version of headers, plus table
        newhdrs, newtab = blendheaders.get_blended_headers(inputs=fnames)

    cleanTemplates(newhdrs[1],newhdrs[2],newhdrs[3])

    return newhdrs, newtab


Instruction:
Can you implement a function in Python 3 that
adds WCS keywords to header hdr.

Response:
def addWCSKeywords(wcs,hdr,blot=False,single=False,after=None):
    """ Update input header 'hdr' with WCS keywords.
    """
    wname = wcs.wcs.name
    if not single:
        wname = 'DRZWCS'

    # Update WCS Keywords based on PyDrizzle product's value
    # since 'drizzle' itself doesn't update that keyword.
    hdr['WCSNAME'] = wname
    hdr.set('VAFACTOR', value=1.0, after=after)
    hdr.set('ORIENTAT', value=wcs.orientat, after=after)

    # Use of 'after' not needed if these keywords already exist in the header
    if after in WCS_KEYWORDS:
        after = None

    if 'CTYPE1' not in hdr:
        hdr.set('CTYPE2', value=wcs.wcs.ctype[1], after=after)
        hdr.set('CTYPE1', value=wcs.wcs.ctype[0], after=after)
    hdr.set('CRPIX2', value=wcs.wcs.crpix[1], after=after)
    hdr.set('CRPIX1', value=wcs.wcs.crpix[0], after=after)
    hdr.set('CRVAL2', value=wcs.wcs.crval[1], after=after)
    hdr.set('CRVAL1', value=wcs.wcs.crval[0], after=after)
    hdr.set('CD2_2', value=wcs.wcs.cd[1][1], after=after)
    hdr.set('CD2_1', value=wcs.wcs.cd[1][0], after=after)
    hdr.set('CD1_2', value=wcs.wcs.cd[0][1], after=after)
    hdr.set('CD1_1', value=wcs.wcs.cd[0][0], after=after)

    # delete distortion model related keywords
    deleteDistortionKeywords(hdr)

    if not blot:
        blendheaders.remove_distortion_keywords(hdr)


Instruction:
Implement a function in Python 3 to
write out a simple FITS file given a numpy array and a name of another FITS file.

Response:
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)


Instruction:
Create a Python 3 function for
writing basic drizzle - related keywords out to the header.

Response:
def writeDrizKeywords(hdr,imgnum,drizdict):
    """ Write basic drizzle-related keywords out to image header as a record
        of the processing performed to create the image

        The dictionary 'drizdict' will contain the keywords and values to be
        written out to the header.
    """
    _keyprefix = 'D%03d'%imgnum

    for key in drizdict:
        val = drizdict[key]['value']
        if val is None: val = ""
        comment = drizdict[key]['comment']
        if comment is None: comment = ""
        hdr[_keyprefix+key] = (val, drizdict[key]['comment'])


Instruction:
Make a summary of the following Python 3 code
def writeFITS(self, template, sciarr, whtarr, ctxarr=None,
                versions=None, overwrite=yes, blend=True, virtual=False):
        """
        Generate PyFITS objects for each output extension
        using the file given by 'template' for populating
        headers.

        The arrays will have the size specified by 'shape'.
        """
        if not isinstance(template, list):
            template = [template]

        if fileutil.findFile(self.output):
            if overwrite:
                log.info('Deleting previous output product: %s' % self.output)
                fileutil.removeFile(self.output)

            else:
                log.warning('Output file %s already exists and overwrite not '
                            'specified!' % self.output)
                log.error('Quitting... Please remove before resuming '
                          'operations.')
                raise IOError

        # initialize output value for this method
        outputFITS = {}
        # Default value for NEXTEND when 'build'== True
        nextend = 3
        if not self.build:
            nextend = 0
            if self.outweight:
                if overwrite:
                    if fileutil.findFile(self.outweight):
                        log.info('Deleting previous output WHT product: %s' %
                                 self.outweight)
                    fileutil.removeFile(self.outweight)
                else:
                    log.warning('Output file %s already exists and overwrite '
                                'not specified!' % self.outweight)
                    log.error('Quitting... Please remove before resuming '
                              'operations.')
                    raise IOError

            if self.outcontext:
                if overwrite:
                    if fileutil.findFile(self.outcontext):
                        log.info('Deleting previous output CTX product: %s' %
                                 self.outcontext)
                    fileutil.removeFile(self.outcontext)
                else:
                    log.warning('Output file %s already exists and overwrite '
                                'not specified!' % self.outcontext)
                    log.error('Quitting... Please remove before resuming '
                              'operations.')
                    raise IOError

        # Get default headers from multi-extension FITS file
        # If only writing out single drizzle product, blending needs to be
        # forced off as there is only 1 input to report, no blending needed
        if self.single:
            blend=False

        # If input data is not in MEF FITS format, it will return 'None'
        # and those headers will have to be generated from drizzle output
        # file FITS headers.
        # NOTE: These are HEADER objects, not HDUs
        #prihdr,scihdr,errhdr,dqhdr = getTemplates(template)
        self.fullhdrs, intab = getTemplates(template, blend=False)

        newhdrs, newtab = getTemplates(template,blend=blend)
        if newtab is not None: nextend += 1 # account for new table extn

        prihdr = newhdrs[0]
        scihdr = newhdrs[1]
        errhdr = newhdrs[2]
        dqhdr = newhdrs[3]

        # Setup primary header as an HDU ready for appending to output FITS file
        prihdu = fits.PrimaryHDU(header=prihdr, data=None)

        # Start by updating PRIMARY header keywords...
        prihdu.header.set('EXTEND', value=True, after='NAXIS')
        prihdu.header['NEXTEND'] = nextend
        prihdu.header['FILENAME'] = self.output
        prihdu.header['PROD_VER'] = 'DrizzlePac {}'.format(version.__version__)

        # Update the ROOTNAME with the new value as well
        _indx = self.output.find('_drz')
        if _indx < 0:
            rootname_val = self.output
        else:
            rootname_val = self.output[:_indx]
        prihdu.header['ROOTNAME'] = rootname_val

        # Get the total exposure time for the image
        # If not calculated by PyDrizzle and passed through
        # the pardict, then leave value from the template image.
        if self.texptime:
            prihdu.header['EXPTIME'] = self.texptime
            prihdu.header.set('TEXPTIME', value=self.texptime, after='EXPTIME')
            prihdu.header['EXPSTART'] = self.expstart
            prihdu.header['EXPEND'] = self.expend

        #Update ASN_MTYPE to reflect the fact that this is a product
        # Currently hard-wired to always output 'PROD-DTH' as MTYPE
        prihdu.header['ASN_MTYP'] = 'PROD-DTH'

        # Update DITHCORR calibration keyword if present
        # Remove when we can modify FITS headers in place...
        if 'DRIZCORR' in prihdu.header:
            prihdu.header['DRIZCORR'] = 'COMPLETE'
        if 'DITHCORR' in prihdu.header:
            prihdu.header['DITHCORR'] = 'COMPLETE'

        prihdu.header['NDRIZIM'] =(len(self.parlist),
                                   'Drizzle, No. images drizzled onto output')

        # Only a subset of these keywords makes sense for the new WCS based
        # transformations. They need to be reviewed to decide what to keep
        # and what to leave out.
        if not self.blot:
            self.addDrizKeywords(prihdu.header,versions)

        if scihdr:
            try:
                del scihdr['OBJECT']
            except KeyError:
                pass

            if 'CCDCHIP' in scihdr: scihdr['CCDCHIP'] = '-999'
            if 'NCOMBINE' in scihdr:
                scihdr['NCOMBINE'] = self.parlist[0]['nimages']

            # If BUNIT keyword was found and reset, then
            bunit_last_kw = self.find_kwupdate_location(scihdr,'bunit')
            if self.bunit is not None:
                comment_str = "Units of science product"
                if self.bunit.lower()[:5] == 'count':
                    comment_str = "counts * gain = electrons"
                scihdr.set('BUNIT', value=self.bunit,
                           comment=comment_str,
                           after=bunit_last_kw)
            else:
                # check to see whether to update already present BUNIT comment
                if 'bunit' in scihdr and scihdr['bunit'].lower()[:5] == 'count':
                    comment_str = "counts * gain = electrons"
                    scihdr.set('BUNIT', value=scihdr['bunit'],
                               comment=comment_str,
                               after=bunit_last_kw)

            # Add WCS keywords to SCI header
            if self.wcs:
                pre_wcs_kw = self.find_kwupdate_location(scihdr,'CD1_1')
                addWCSKeywords(self.wcs,scihdr,blot=self.blot,
                                single=self.single, after=pre_wcs_kw)
                # Recompute this after removing distortion kws
                pre_wcs_kw = self.find_kwupdate_location(scihdr,'CD1_1')

        ##########
        # Now, build the output file
        ##########
        if self.build:
            print('-Generating multi-extension output file: ',self.output)
            fo = fits.HDUList()

            # Add primary header to output file...
            fo.append(prihdu)

            if self.single and self.compress:
                hdu = fits.CompImageHDU(data=sciarr, header=scihdr, name=EXTLIST[0])
            else:
                hdu = fits.ImageHDU(data=sciarr, header=scihdr, name=EXTLIST[0])
            last_kw = self.find_kwupdate_location(scihdr,'EXTNAME')
            hdu.header.set('EXTNAME', value='SCI', after=last_kw)
            hdu.header.set('EXTVER', value=1, after='EXTNAME')
            fo.append(hdu)

            # Build WHT extension here, if requested...
            if errhdr:
                errhdr['CCDCHIP'] = '-999'

            if self.single and self.compress:
                hdu = fits.CompImageHDU(data=whtarr, header=errhdr, name=EXTLIST[1])
            else:
                hdu = fits.ImageHDU(data=whtarr, header=errhdr, name=EXTLIST[1])
            last_kw = self.find_kwupdate_location(errhdr,'EXTNAME')
            hdu.header.set('EXTNAME', value='WHT', after=last_kw)
            hdu.header.set('EXTVER', value=1, after='EXTNAME')
            if self.wcs:
                pre_wcs_kw = self.find_kwupdate_location(hdu.header,'CD1_1')
                # Update WCS Keywords based on PyDrizzle product's value
                # since 'drizzle' itself doesn't update that keyword.
                addWCSKeywords(self.wcs,hdu.header,blot=self.blot,
                               single=self.single, after=pre_wcs_kw)
            fo.append(hdu)

            # Build CTX extension here
            # If there is only 1 plane, write it out as a 2-D extension
            if self.outcontext:
                if ctxarr.shape[0] == 1:
                    _ctxarr = ctxarr[0]
                else:
                    _ctxarr = ctxarr
            else:
                _ctxarr = None

            if self.single and self.compress:
                hdu = fits.CompImageHDU(data=_ctxarr, header=dqhdr, name=EXTLIST[2])
            else:
                hdu = fits.ImageHDU(data=_ctxarr, header=dqhdr, name=EXTLIST[2])
            last_kw = self.find_kwupdate_location(dqhdr,'EXTNAME')
            hdu.header.set('EXTNAME', value='CTX', after=last_kw)
            hdu.header.set('EXTVER', value=1, after='EXTNAME')

            if self.wcs:
                pre_wcs_kw = self.find_kwupdate_location(hdu.header,'CD1_1')
                # Update WCS Keywords based on PyDrizzle product's value
                # since 'drizzle' itself doesn't update that keyword.
                addWCSKeywords(self.wcs,hdu.header,blot=self.blot,
                               single=self.single, after=pre_wcs_kw)
            fo.append(hdu)

            # remove all alternate WCS solutions from headers of this product
            wcs_functions.removeAllAltWCS(fo,[1])

            # add table of combined header keyword values to FITS file
            if newtab is not None:
                fo.append(newtab)

            if not virtual:
                print('Writing out to disk:',self.output)
                # write out file to disk
                fo.writeto(self.output)
                fo.close()
                del fo, hdu
                fo = None
            # End 'if not virtual'
            outputFITS[self.output]= fo

        else:
            print('-Generating simple FITS output: %s' % self.outdata)

            fo = fits.HDUList()
            hdu_header = prihdu.header.copy()
            del hdu_header['nextend']

            # Append remaining unique header keywords from template DQ
            # header to Primary header...
            if scihdr:
                for _card in scihdr.cards:
                    if _card.keyword not in RESERVED_KEYS and _card.keyword not in hdu_header:
                        hdu_header.append(_card)
            for kw in ['PCOUNT', 'GCOUNT']:
                try:
                    del kw
                except KeyError:
                    pass
            hdu_header['filename'] = self.outdata

            if self.compress:
                hdu = fits.CompImageHDU(data=sciarr, header=hdu_header)
                wcs_ext = [1]
            else:
                hdu = fits.ImageHDU(data=sciarr, header=hdu_header)
                wcs_ext = [0]

            # explicitly set EXTEND to FALSE for simple FITS files.
            dim = len(sciarr.shape)
            hdu.header.set('extend', value=False, after='NAXIS%s'%dim)

            # Add primary header to output file...
            fo.append(hdu)

            # remove all alternate WCS solutions from headers of this product
            logutil.logging.disable(logutil.logging.INFO)
            wcs_functions.removeAllAltWCS(fo,wcs_ext)
            logutil.logging.disable(logutil.logging.NOTSET)

            # add table of combined header keyword values to FITS file
            if newtab is not None:
                fo.append(newtab)

            if not virtual:
                print('Writing out image to disk:',self.outdata)
                # write out file to disk
                fo.writeto(self.outdata)
                del fo,hdu
                fo = None
            # End 'if not virtual'
            outputFITS[self.outdata]= fo

            if self.outweight and whtarr is not None:
                # We need to build new PyFITS objects for each WHT array
                fwht = fits.HDUList()

                if errhdr:
                    errhdr['CCDCHIP'] = '-999'

                if self.compress:
                    hdu = fits.CompImageHDU(data=whtarr, header=prihdu.header)
                else:
                    hdu = fits.ImageHDU(data=whtarr, header=prihdu.header)
                # Append remaining unique header keywords from template DQ
                # header to Primary header...
                if errhdr:
                    for _card in errhdr.cards:
                        if _card.keyword not in RESERVED_KEYS and _card.keyword not in hdu.header:
                            hdu.header.append(_card)
                hdu.header['filename'] = self.outweight
                hdu.header['CCDCHIP'] = '-999'
                if self.wcs:
                    pre_wcs_kw = self.find_kwupdate_location(hdu.header,'CD1_1')
                    # Update WCS Keywords based on PyDrizzle product's value
                    # since 'drizzle' itself doesn't update that keyword.
                    addWCSKeywords(self.wcs,hdu.header, blot=self.blot,
                                   single=self.single, after=pre_wcs_kw)

                # Add primary header to output file...
                fwht.append(hdu)
                # remove all alternate WCS solutions from headers of this product
                wcs_functions.removeAllAltWCS(fwht,wcs_ext)

                if not virtual:
                    print('Writing out image to disk:',self.outweight)
                    fwht.writeto(self.outweight)
                    del fwht,hdu
                    fwht = None
                # End 'if not virtual'
                outputFITS[self.outweight]= fwht

            # If a context image was specified, build a PyFITS object
            # for it as well...
            if self.outcontext and ctxarr is not None:
                fctx = fits.HDUList()

                # If there is only 1 plane, write it out as a 2-D extension
                if ctxarr.shape[0] == 1:
                    _ctxarr = ctxarr[0]
                else:
                    _ctxarr = ctxarr

                if self.compress:
                    hdu = fits.CompImageHDU(data=_ctxarr, header=prihdu.header)
                else:
                    hdu = fits.ImageHDU(data=_ctxarr, header=prihdu.header)
                # Append remaining unique header keywords from template DQ
                # header to Primary header...
                if dqhdr:
                    for _card in dqhdr.cards:
                        if ( (_card.keyword not in RESERVED_KEYS) and
                             _card.keyword not in hdu.header):
                            hdu.header.append(_card)
                hdu.header['filename'] = self.outcontext
                if self.wcs:
                    pre_wcs_kw = self.find_kwupdate_location(hdu.header,'CD1_1')
                    # Update WCS Keywords based on PyDrizzle product's value
                    # since 'drizzle' itself doesn't update that keyword.
                    addWCSKeywords(self.wcs,hdu.header, blot=self.blot,
                                   single=self.single, after=pre_wcs_kw)

                fctx.append(hdu)
                # remove all alternate WCS solutions from headers of this product
                wcs_functions.removeAllAltWCS(fctx,wcs_ext)
                if not virtual:
                    print('Writing out image to disk:',self.outcontext)
                    fctx.writeto(self.outcontext)
                    del fctx,hdu
                    fctx = None
                # End 'if not virtual'

                outputFITS[self.outcontext]= fctx

        return outputFITS

Response: Write the FITS file for each output extension.


Instruction:
How would you implement a function in Python 3 that
finds the last keyword in the output header that comes before the new keyword in the original full input headers.

Response:
def find_kwupdate_location(self,hdr,keyword):
        """
        Find the last keyword in the output header that comes before the new
        keyword in the original, full input headers.
        This will rely on the original ordering of keywords from the original input
        files in order to place the updated keyword in the correct location in case
        the keyword was removed from the output header prior to calling this method.
        """
        # start by looping through the full templates
        kw_list = None
        last_kw = None
        for extn in self.fullhdrs:
            if keyword in extn:
                #indx = extn.ascard.index_of(keyword)
                indx = extn.index(keyword)
                kw_list = list(extn.keys())[:indx]
                break
        if kw_list:
            # find which keyword from this list exists in header to be updated
            for kw in kw_list[::-1]:
                if kw in hdr:
                    last_kw = kw
                    break
        # determine new value for the last keyword found before the HISTORY kws
        if last_kw is None:
            hdrkeys = list(hdr.keys())
            i = -1
            last_kw = hdrkeys[i]
            while last_kw == 'HISTORY':
                i -= 1
                last_kw = hdrkeys[i]

        return last_kw


Instruction:
Make a summary of the following Python 3 code
def addDrizKeywords(self,hdr,versions):

        # Extract some global information for the keywords
        _geom = 'User parameters'

        _imgnum = 0
        for pl in self.parlist:

            # Start by building up the keyword prefix based
            # on the image number for the chip
            #_keyprefix = 'D%03d'%_imgnum
            _imgnum += 1

            drizdict = DRIZ_KEYWORDS.copy()
            # Update drizdict with current values
            drizdict['VER']['value'] = pl['driz_version'][:44]
            drizdict['DATA']['value'] = pl['data'][:64]
            drizdict['DEXP']['value'] = pl['exptime']
            drizdict['OUDA']['value'] = pl['outFinal'][:64]
            drizdict['OUWE']['value'] = pl['outWeight'][:64]
            if pl['outContext'] is None:
                outcontext = ""
            else:
                outcontext = pl['outContext'][:64]
            drizdict['OUCO']['value'] = outcontext
            if self.single:
                drizdict['MASK']['value'] = pl['singleDrizMask'][:64]
            else:
                drizdict['MASK']['value'] = pl['finalMask'][:64]

            # Process the values of WT_SCL to be consistent with
            # what IRAF Drizzle would output
            if 'wt_scl_val' in pl:
                _wtscl = pl['wt_scl_val']
            else:
                if pl['wt_scl'] == 'exptime': _wtscl = pl['exptime']
                elif pl['wt_scl'] == 'expsq': _wtscl = pl['exptime']*pl['exptime']
                else: _wtscl = pl['wt_scl']

            drizdict['WTSC']['value'] = _wtscl
            drizdict['KERN']['value'] = pl['kernel']
            drizdict['PIXF']['value'] = pl['pixfrac']
            drizdict['OUUN']['value'] = self.units
            if pl['fillval'] is None:
                _fillval = 'INDEF'
            else:
                _fillval = pl['fillval']
            drizdict['FVAL']['value'] = _fillval
            drizdict['WKEY']['value'] = pl['driz_wcskey']

            drizdict['SCAL'] = {'value':pl['scale'],'comment':'Drizzle, pixel size (arcsec) of output image'}
            drizdict['ISCL'] = {'value':pl['idcscale'],'comment':'Drizzle, default IDCTAB pixel size(arcsec)'}

            # Now update header with values
            writeDrizKeywords(hdr,_imgnum,drizdict)
            del drizdict

        # Add version information as HISTORY cards to the header
        if versions is not None:
            ver_str = "AstroDrizzle processing performed using: "
            hdr.add_history(ver_str)
            for k in versions.keys():
                ver_str = '    '+str(k)+' Version '+str(versions[k])
                hdr.add_history(ver_str)

Response: Add the drizzle parameter keywords to the header.


Instruction:
Can you create a Python 3 function that
performs an iterative - fit with nclip iterations

Response:
def iter_fit_shifts(xy,uv,nclip=3,sigma=3.0):
    """ Perform an iterative-fit with 'nclip' iterations
    """
    fit = fit_shifts(xy,uv)
    if nclip is None: nclip = 0
    # define index to initially include all points
    for n in range(nclip):
        resids = compute_resids(xy,uv,fit)
        resids1d = np.sqrt(np.power(resids[:,0],2)+np.power(resids[:,1],2))
        sig = resids1d.std()
        # redefine what pixels will be included in next iteration
        goodpix = resids1d < sigma*sig
        xy = xy[goodpix]
        uv = uv[goodpix]
        fit = fit_shifts(xy,uv)

    fit['img_coords'] = xy
    fit['ref_coords'] = uv

    return fit


Instruction:
Can you implement a function in Python 3 that
performs an rscale fit between matched lists of pixel positions xy and uv.

Response:
def fit_all(xy,uv,mode='rscale',center=None,verbose=True):
    """ Performs an 'rscale' fit between matched lists of pixel positions xy and uv"""
    if mode not in ['general', 'shift', 'rscale']:
        mode = 'rscale'
    if not isinstance(xy,np.ndarray):
        # cast input list as numpy ndarray for fitting
        xy = np.array(xy)
    if not isinstance(uv,np.ndarray):
        # cast input list as numpy ndarray for fitting
        uv = np.array(uv)

    if mode == 'shift':
        logstr = 'Performing "shift" fit'
        if verbose:
            print(logstr)
        else:
            log.info(logstr)
        result = fit_shifts(xy, uv)

    elif mode == 'general':
        logstr = 'Performing "general" fit'
        if verbose:
            print(logstr)
        else:
            log.info(logstr)
        result = fit_general(xy, uv)

    else:
        logstr = 'Performing "rscale" fit'
        if verbose:
            print(logstr)
        else:
            log.info(logstr)
        result = geomap_rscale(xy, uv, center=center)

    return result


Instruction:
How would you explain what the following Python 3 function does
def fit_shifts(xy, uv):
    diff_pts = xy - uv
    Pcoeffs = np.array([1.0,0.0,diff_pts[:,0].mean(dtype=np.float64)])
    Qcoeffs = np.array([0.0,1.0,diff_pts[:,1].mean(dtype=np.float64)])

    fit = build_fit(Pcoeffs, Qcoeffs, 'shift')
    resids = diff_pts - fit['offset']
    fit['resids'] = resids
    fit['rms'] = resids.std(axis=0)
    fit['rmse'] = float(np.sqrt(np.mean(2 * resids**2)))
    fit['mae'] = float(np.mean(np.linalg.norm(resids, axis=1)))

    return fit

Response: This function calculates the fit for the shift only between two lists of positions xy and uv.


Instruction:
Explain what the following Python 3 code does
def fit_general(xy, uv):
    # Set up products used for computing the fit
    gxy = uv.astype(ndfloat128)
    guv = xy.astype(ndfloat128)
    Sx = gxy[:,0].sum()
    Sy = gxy[:,1].sum()
    Su = guv[:,0].sum()
    Sv = guv[:,1].sum()

    Sux = np.dot(guv[:,0], gxy[:,0])
    Svx = np.dot(guv[:,1], gxy[:,0])
    Suy = np.dot(guv[:,0], gxy[:,1])
    Svy = np.dot(guv[:,1], gxy[:,1])
    Sxx = np.dot(gxy[:,0], gxy[:,0])
    Syy = np.dot(gxy[:,1], gxy[:,1])
    Sxy = np.dot(gxy[:,0], gxy[:,1])

    n = len(xy[:,0])
    M = np.array([[Sx, Sy, n], [Sxx, Sxy, Sx], [Sxy, Syy, Sy]])
    U = np.array([Su, Sux, Suy])
    V = np.array([Sv, Svx, Svy])

    # The fit solutioN...
    # where
    #   u = P0 + P1*x + P2*y
    #   v = Q0 + Q1*x + Q2*y
    #
    try:
        invM = np.linalg.inv(M.astype(np.float64))
    except np.linalg.LinAlgError:
        raise SingularMatrixError(
            "Singular matrix: suspected colinear points."
        )
    P = np.dot(invM, U).astype(np.float64)
    Q = np.dot(invM, V).astype(np.float64)
    if not (np.all(np.isfinite(P)) and np.all(np.isfinite(Q))):
        raise ArithmeticError('Singular matrix.')

    # Return the shift, rotation, and scale changes
    result = build_fit(P, Q, 'general')
    resids = xy - np.dot(uv, result['fit_matrix']) - result['offset']
    result['rms'] = resids.std(axis=0)
    result['resids'] = resids
    result['rmse'] = float(np.sqrt(np.mean(2 * resids**2)))
    result['mae'] = float(np.mean(np.linalg.norm(resids, axis=1)))

    return result

Response: This function computes a simple fit for the shift only between two lists of positions xy and uv.


Instruction:
How would you code a function in Python 3 to
perform a generalized fit between matched lists of positions given by the 2 column arrays xy and uv. This function fits for translation, rotation, and scale changes between 'xy' and 'uv', allowing for different scales and orientations for X and Y axes. ================================= DEVELOPMENT NOTE: Checks need to be put in place to verify that enough objects are available for a fit. ================================= Output: (Xo,Yo),Rot,(Scale,Sx,Sy) where Xo,Yo: offset, Rot: rotation, Scale: average scale change, and Sx,Sy: scale changes in X and Y separately. Algorithm and nomenclature provided by: Colin Cox (11 Nov 2004)

Response:
def fit_arrays(uv, xy):
    """ Performs a generalized fit between matched lists of positions
        given by the 2 column arrays xy and uv.

        This function fits for translation, rotation, and scale changes
        between 'xy' and 'uv', allowing for different scales and
        orientations for X and Y axes.

        =================================
        DEVELOPMENT NOTE:
            Checks need to be put in place to verify that
            enough objects are available for a fit.
        =================================

        Output:
           (Xo,Yo),Rot,(Scale,Sx,Sy)
           where
                Xo,Yo:  offset,
                Rot:    rotation,
                Scale:  average scale change, and
                Sx,Sy:  scale changes in X and Y separately.

        Algorithm and nomenclature provided by: Colin Cox (11 Nov 2004)
    """

    if not isinstance(xy,np.ndarray):
        # cast input list as numpy ndarray for fitting
        xy = np.array(xy)
    if not isinstance(uv,np.ndarray):
        # cast input list as numpy ndarray for fitting
        uv = np.array(uv)

    # Set up products used for computing the fit
    Sx = xy[:,0].sum()
    Sy = xy[:,1].sum()
    Su = uv[:,0].sum()
    Sv = uv[:,1].sum()

    Sux = np.dot(uv[:,0], xy[:,0])
    Svx = np.dot(uv[:,1], xy[:,0])
    Suy = np.dot(uv[:,0], xy[:,1])
    Svy = np.dot(uv[:,1], xy[:,1])
    Sxx = np.dot(xy[:,0], xy[:,0])
    Syy = np.dot(xy[:,1], xy[:,1])
    Sxy = np.dot(xy[:,0], xy[:,1])

    n = len(xy[:,0])
    M = np.array([[Sx, Sy, n], [Sxx, Sxy, Sx], [Sxy, Syy, Sy]])
    U = np.array([Su, Sux, Suy])
    V = np.array([Sv, Svx, Svy])

    # The fit solutioN...
    # where
    #   u = P0 + P1*x + P2*y
    #   v = Q0 + Q1*x + Q2*y
    #
    try:
        invM = np.linalg.inv(M.astype(np.float64))
    except np.linalg.LinAlgError:
        raise SingularMatrixError(
            "Singular matrix: suspected colinear points."
        )
    P = np.dot(invM, U).astype(np.float64)
    Q = np.dot(invM, V).astype(np.float64)
    if not (np.all(np.isfinite(P)) and np.all(np.isfinite(Q))):
        raise ArithmeticError('Singular matrix.')

    # Return the shift, rotation, and scale changes
    return build_fit(P, Q, 'general')


Instruction:
How would you explain what the following Python 3 function does
def apply_old_coeffs(xy,coeffs):
    _theta = np.deg2rad(coeffs[1])
    _mrot = np.zeros(shape=(2,2),dtype=np.float64)
    _mrot[0] = (np.cos(_theta),np.sin(_theta))
    _mrot[1] = (-np.sin(_theta),np.cos(_theta))

    new_pos = (np.dot(xy,_mrot)/coeffs[2][0]) + coeffs[0]

    return new_pos

Response:
Apply the offset shift and rotation values from a linear fit
        to an array of x y positions.


Instruction:
Can you create a Python 3 function that
applies the coefficients from a linear fit to an array of x y positions.

Response:
def apply_fit(xy,coeffs):
    """ Apply the coefficients from a linear fit to
        an array of x,y positions.

        The coeffs come from the 'coeffs' member of the
        'fit_arrays()' output.
    """
    x_new = coeffs[0][2] + coeffs[0][0]*xy[:,0] + coeffs[0][1]*xy[:,1]
    y_new = coeffs[1][2] + coeffs[1][0]*xy[:,0] + coeffs[1][1]*xy[:,1]

    return x_new,y_new


Instruction:
Write a Python 3 script to
compute the residuals based on fit and input arrays to the fit

Response:
def compute_resids(xy,uv,fit):
    """ Compute the residuals based on fit and input arrays to the fit
    """
    print('FIT coeffs: ',fit['coeffs'])
    xn,yn = apply_fit(uv,fit['coeffs'])
    resids = xy - np.transpose([xn,yn])
    return resids


Instruction:
Given the following Python 3 function, write the documentation
def geomap_rscale(xyin,xyref,center=None):
    if center is not None:
        xcen = center[0]
        ycen = center[1]
    else:
        xcen = xyref[:,0].mean()
        ycen = xyref[:,1].mean()

    dx = xyref[:,0].astype(ndfloat128)
    dy = xyref[:,1].astype(ndfloat128)
    du = xyin[:,0].astype(ndfloat128)
    dv = xyin[:,1].astype(ndfloat128)

    n = xyref.shape[0]
    Sx = dx.sum()
    Sy = dy.sum()
    Su = du.sum()
    Sv = dv.sum()
    xr0 = Sx/n
    yr0 = Sy/n
    xi0 = Su/n
    yi0 = Sv/n
    Sxrxr = np.power((dx-xr0),2).sum()
    Syryr = np.power((dy-yr0),2).sum()
    Syrxi = ((dy-yr0)*(du-xi0)).sum()
    Sxryi = ((dx-xr0)*(dv-yi0)).sum()
    Sxrxi = ((dx-xr0)*(du-xi0)).sum()
    Syryi = ((dy-yr0)*(dv-yi0)).sum()

    rot_num = Sxrxi * Syryi
    rot_denom = Syrxi * Sxryi
    if rot_num == rot_denom: det = 0.0
    else: det = rot_num - rot_denom
    if (det < 0):
        rot_num = Syrxi + Sxryi
        rot_denom = Sxrxi - Syryi
    else:
        rot_num = Syrxi - Sxryi
        rot_denom = Sxrxi + Syryi
    if rot_num == rot_denom: theta = 0.0
    else:
        theta = np.rad2deg(np.arctan2(rot_num,rot_denom))
        if theta < 0:
            theta += 360.0

    ctheta = np.cos(np.deg2rad(theta))
    stheta = np.sin(np.deg2rad(theta))
    s_num = rot_denom*ctheta + rot_num*stheta
    s_denom = Sxrxr + Syryr
    if s_denom < 0:
        mag = 1.0
    else:
        mag = s_num/s_denom

    if det < 0:
        # "flip" y-axis (reflection about x-axis *after* rotation)
        # NOTE: keep in mind that 'fit_matrix'
        #       is the transposed rotation matrix.
        sthetax = -mag*stheta
        cthetay = -mag*ctheta
    else:
        sthetax = mag*stheta
        cthetay = mag*ctheta
    cthetax = mag*ctheta
    sthetay = mag*stheta

    sdet = np.sign(det)
    xshift = (xi0 - (xr0*cthetax + sdet*yr0*sthetax)).astype(np.float64)
    yshift = (yi0 - (-sdet*xr0*sthetay + yr0*cthetay)).astype(np.float64)

    P = np.array([ cthetax, sthetay, xshift],dtype=np.float64)
    Q = np.array([ -sthetax, cthetay, yshift],dtype=np.float64)

    # Return the shift, rotation, and scale changes
    result = build_fit(P, Q, fitgeom='rscale')
    resids = xyin - np.dot((xyref), result['fit_matrix']) - result['offset']
    result['rms'] = resids.std(axis=0)
    result['resids'] = resids
    result['rmse'] = float(np.sqrt(np.mean(2 * resids**2)))
    result['mae'] = float(np.mean(np.linalg.norm(resids, axis=1)))

    return result

Response: This function calculates the fit of a single object based on the geomap function.


Instruction:
Can you tell what is the following Python 3 function doing
def AstroDrizzle(input=None, mdriztab=False, editpars=False, configobj=None,
                 wcsmap=None, **input_dict):
    """ AstroDrizzle command-line interface """
    # Support input of filenames from command-line without a parameter name
    # then copy this into input_dict for merging with TEAL ConfigObj
    # parameters.

    # Load any user-specified configobj
    if isinstance(configobj, (str, bytes)):
        if configobj == 'defaults':
            # load "TEAL"-defaults (from ~/.teal/):
            configobj = teal.load(__taskname__)
        else:
            if not os.path.exists(configobj):
                raise RuntimeError('Cannot find .cfg file: '+configobj)
            configobj = teal.load(configobj, strict=False)
    elif configobj is None:
        # load 'astrodrizzle' parameter defaults as described in the docs:
        configobj = teal.load(__taskname__, defaults=True)

    if input and not util.is_blank(input):
        input_dict['input'] = input
    elif configobj is None:
        raise TypeError("AstroDrizzle() needs either 'input' or "
                        "'configobj' arguments")

    if 'updatewcs' in input_dict: # user trying to explicitly turn on updatewcs
        configobj['updatewcs'] = input_dict['updatewcs']
        del input_dict['updatewcs']

    # If called from interactive user-interface, configObj will not be
    # defined yet, so get defaults using EPAR/TEAL.
    #
    # Also insure that the input_dict (user-specified values) are folded in
    # with a fully populated configObj instance.
    try:
        configObj = util.getDefaultConfigObj(__taskname__, configobj,
                                             input_dict,
                                             loadOnly=(not editpars))
        log.debug('')
        log.debug("INPUT_DICT:")
        util.print_cfg(input_dict, log.debug)
        log.debug('')
        # If user specifies optional parameter for final_wcs specification in input_dict,
        #    insure that the final_wcs step gets turned on
        util.applyUserPars_steps(configObj, input_dict, step='3a')
        util.applyUserPars_steps(configObj, input_dict, step='7a')

    except ValueError:
        print("Problem with input parameters. Quitting...", file=sys.stderr)
        return

    if not configObj:
        return

    configObj['mdriztab'] = mdriztab
    # If 'editpars' was set to True, util.getDefaultConfigObj() will have
    # already called 'run()'.
    if not editpars:
        run(configObj, wcsmap=wcsmap)

Response: AstroDrizzle command - line interface.


Instruction:
Can you write a function in Python 3 where it
initials example by Nadia ran MD with configobj EPAR using: It can be run in one of two ways: from stsci.tools import teal 1. Passing a config object to teal teal.teal('drizzlepac/pars/astrodrizzle.cfg') 2. Passing a task name: teal.teal('astrodrizzle') The example config files are in drizzlepac/pars

Response:
def run(configobj, wcsmap=None):
    """
    Initial example by Nadia ran MD with configobj EPAR using:
    It can be run in one of two ways:

        from stsci.tools import teal

        1. Passing a config object to teal

        teal.teal('drizzlepac/pars/astrodrizzle.cfg')

        2. Passing a task  name:

        teal.teal('astrodrizzle')

        The example config files are in drizzlepac/pars

    """
    # turn on logging, redirecting stdout/stderr messages to a log file
    # while also printing them out to stdout as well
    # also, initialize timing of processing steps
    #
    # We need to define a default logfile name from the user's parameters
    input_list, output, ivmlist, odict = \
            processInput.processFilenames(configobj['input'])

    if output is not None:
        def_logname = output
    elif len(input_list) > 0:
        def_logname = input_list[0]
    else:
        print(textutil.textbox(
            "ERROR:\nNo valid input files found!   Please restart the task "
            "and check the value for the 'input' parameter."), file=sys.stderr)
        def_logname = None
        return

    clean = configobj['STATE OF INPUT FILES']['clean']
    procSteps = util.ProcSteps()

    print("AstroDrizzle Version {:s} ({:s}) started at: {:s}\n"
          .format(__version__, __version_date__, util._ptime()[0]))
    util.print_pkg_versions(log=log)

    log.debug('')
    log.debug(
        "==== AstroDrizzle was invoked with the following parameters: ===="
    )
    log.debug('')
    util.print_cfg(configobj, log.debug)

    try:
        # Define list of imageObject instances and output WCSObject instance
        # based on input paramters
        imgObjList = None
        procSteps.addStep('Initialization')
        imgObjList, outwcs = processInput.setCommonInput(configobj)
        procSteps.endStep('Initialization')

        if imgObjList is None or not imgObjList:
            errmsg = "No valid images found for processing!\n"
            errmsg += "Check log file for full details.\n"
            errmsg += "Exiting AstroDrizzle now..."
            print(textutil.textbox(errmsg, width=65))
            print(textutil.textbox(
                'ERROR:\nAstroDrizzle Version {:s} encountered a problem!  '
                'Processing terminated at {:s}.'
                .format(__version__, util._ptime()[0])), file=sys.stderr)
            return

        log.info("USER INPUT PARAMETERS common to all Processing Steps:")
        util.printParams(configobj, log=log)

        # Call rest of MD steps...
        #create static masks for each image
        staticMask.createStaticMask(imgObjList, configobj,
                                    procSteps=procSteps)

        #subtract the sky
        sky.subtractSky(imgObjList, configobj, procSteps=procSteps)

#       _dbg_dump_virtual_outputs(imgObjList)

        #drizzle to separate images
        adrizzle.drizSeparate(imgObjList, outwcs, configobj, wcsmap=wcsmap,
                              procSteps=procSteps)

#       _dbg_dump_virtual_outputs(imgObjList)

        #create the median images from the driz sep images
        createMedian.createMedian(imgObjList, configobj, procSteps=procSteps)

        #blot the images back to the original reference frame
        ablot.runBlot(imgObjList, outwcs, configobj, wcsmap=wcsmap,
                      procSteps=procSteps)

        #look for cosmic rays
        drizCR.rundrizCR(imgObjList, configobj, procSteps=procSteps)

        #Make your final drizzled image
        adrizzle.drizFinal(imgObjList, outwcs, configobj, wcsmap=wcsmap,
                           procSteps=procSteps)

        print()
        print("AstroDrizzle Version {:s} is finished processing at {:s}.\n"
              .format(__version__, util._ptime()[0]))

    except:
        clean = False
        print(textutil.textbox(
            "ERROR:\nAstroDrizzle Version {:s} encountered a problem!  "
            "Processing terminated at {:s}."
            .format(__version__, util._ptime()[0])), file=sys.stderr)
        raise

    finally:
        procSteps.reportTimes()
        if imgObjList:
            for image in imgObjList:
                if clean:
                    image.clean()
                image.close()
            del imgObjList
            del outwcs


Instruction:
Create a Python 3 function to
dump some helpful information about virtual outputs

Response:
def _dbg_dump_virtual_outputs(imgObjList):
    """ dump some helpful information.  strictly for debugging """
    global _fidx
    tag = 'virtual'
    log.info((tag+'  ')*7)
    for iii in imgObjList:
        log.info('-'*80)
        log.info(tag+'  orig nm: '+iii._original_file_name)
        log.info(tag+'  names.data: '+str(iii.outputNames["data"]))
        log.info(tag+'  names.orig: '+str(iii.outputNames["origFilename"]))
        log.info(tag+'  id: '+str(id(iii)))
        log.info(tag+'  in.mem: '+str(iii.inmemory))
        log.info(tag+'  vo items...')
        for vok in sorted(iii.virtualOutputs.keys()):
            FITSOBJ = iii.virtualOutputs[vok]
            log.info(tag+': '+str(vok)+' = '+str(FITSOBJ))
            if vok.endswith('.fits'):
                if not hasattr(FITSOBJ, 'data'):
                    FITSOBJ = FITSOBJ[0] # list of PrimaryHDU ?
                if not hasattr(FITSOBJ, 'data'):
                    FITSOBJ = FITSOBJ[0] # was list of HDUList ?
                dbgname = 'DEBUG_%02d_'%(_fidx,)
                dbgname+=os.path.basename(vok)
                _fidx+=1
                FITSOBJ.writeto(dbgname)
                log.info(tag+'  wrote: '+dbgname)
                log.info('\n'+vok)
                if hasattr(FITSOBJ, 'data'):
                    log.info(str(FITSOBJ._summary()))
                    log.info('min and max are: '+str( (FITSOBJ.data.min(),
                                                       FITSOBJ.data.max()) ))
                    log.info('avg and sum are: '+str( (FITSOBJ.data.mean(),
                                                       FITSOBJ.data.sum()) ))
#                    log.info(str(FITSOBJ.data)[:75])
                else:
                    log.info(vok+' has no .data attr')
                    log.info(str(type(FITSOBJ)))
                log.info(vok+'\n')
    log.info('-'*80)


Instruction:
Implement a function in Python 3 to
return the dark current for the WFC3 UVIS detector.

Response:
def getdarkcurrent(self,chip):
        """
        Return the dark current for the WFC3 UVIS detector.  This value
        will be contained within an instrument specific keyword.

        Returns
        -------
        darkcurrent: float
            The dark current value with **units of electrons**.
        """
        darkcurrent = 0.

        try:
            darkcurrent = self._image[self.scienceExt, chip].header['MEANDARK']

        except:
            msg =  "#############################################\n"
            msg += "#                                           #\n"
            msg += "# Error:                                    #\n"
            msg += "#   Cannot find the value for 'MEANDARK'    #\n"
            msg += "#   in the image header.  WFC3 input images #\n"
            msg += "#   are expected to have this header        #\n"
            msg += "#   keyword.                                #\n"
            msg += "#                                           #\n"
            msg += "# Error occured in WFC3UVISInputImage class #\n"
            msg += "#                                           #\n"
            msg += "#############################################\n"
            raise ValueError(msg)

        return darkcurrent


Instruction:
Here you have a function in Python 3, explain what it does
def getdarkimg(self,chip):
        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

Response: Returns an array representing the dark image for the detector.


Instruction:
Write a Python 3 function for
getting the sky image for the detector.

Response:
def getskyimg(self,chip):
        """
        Notes
        =====
        Return an array representing the sky image for the detector.  The value
        of the sky is what would actually be subtracted from the exposure by
        the skysub step.

        :units: electrons

        """
        sci_chip = self._image[self.scienceExt,chip]
        skyimg = np.ones(sci_chip.image_shape,dtype=sci_chip.image_dtype)*sci_chip.subtractedSky
        if sci_chip._conversionFactor != 1.0: # If units are not already ELECTRONS
            skyimg *= self.getexptimeimg(chip)
        return skyimg


Instruction:
Explain what the following Python 3 code does
def getdarkcurrent(self,extver):
        darkcurrent=0.
        try:
            darkcurrent = self._image[self.scienceExt,extver].header['MEANDARK']
        except:
            str =  "#############################################\n"
            str += "#                                           #\n"
            str += "# Error:                                    #\n"
            str += "#   Cannot find the value for 'MEANDARK'    #\n"
            str += "#   in the image header.  ACS input images  #\n"
            str += "#   are expected to have this header        #\n"
            str += "#   keyword.                                #\n"
            str += "#                                           #\n"
            str += "# Error occured in the ACSInputImage class  #\n"
            str += "#                                           #\n"
            str += "#############################################\n"
            raise ValueError(str)

        return darkcurrent

Response: Returns the dark current value for the ACS detector.


Instruction:
Write a Python 3 function that can
set the instrument parameters.

Response:
def setInstrumentParameters(self,instrpars):
        """ Sets the instrument parameters.
        """
        pri_header = self._image[0].header

        if self._isNotValid (instrpars['gain'], instrpars['gnkeyword']):
            instrpars['gnkeyword'] = None
        if self._isNotValid (instrpars['rdnoise'], instrpars['rnkeyword']):
            instrpars['rnkeyword'] = None
        if self._isNotValid (instrpars['exptime'], instrpars['expkeyword']):
            instrpars['expkeyword'] = 'EXPTIME'

        # We need to treat Read Noise and Gain as a special case since it is
        # not populated in the SBC primary header for the MAMA
        for chip in self.returnAllChips(extname=self.scienceExt):
            chip._gain      = 1.0 #self.getInstrParameter("", pri_header,
                                  #                  instrpars['gnkeyword'])
            chip._rdnoise   = 0.0 #self.getInstrParameter("", pri_header,
                                  #                   instrpars['rnkeyword'])
            chip._exptime   = self.getInstrParameter(instrpars['exptime'], pri_header,
                                                     instrpars['expkeyword'])
            if chip._exptime is None:
                print('ERROR: invalid instrument task parameter')
                raise ValueError

        # We need to determine if the user has used the default readnoise/gain value
        # since if not, they will need to supply a gain/readnoise value as well
        usingDefaultGain = instrpars['gnkeyword'] is None
        usingDefaultReadnoise = instrpars['rnkeyword'] is None

        # Set the default readnoise or gain values based upon the amount of user input given.

        # Case 1: User supplied no gain or readnoise information
        if usingDefaultReadnoise and usingDefaultGain:
            # Set the default gain and readnoise values
            self._setSBCchippars()
        # Case 2: The user has supplied a value for gain
        elif usingDefaultReadnoise and not usingDefaultGain:
            # Set the default readnoise value
            self._setDefaultSBCReadnoise()
        # Case 3: The user has supplied a value for readnoise
        elif not usingDefaultReadnoise and usingDefaultGain:
            # Set the default gain value
            self._setDefaultSBCGain()
        else:
            # In this case, the user has specified both a gain and readnoise values.  Just use them as is.
            pass


Instruction:
Implement a Python 3 function for
creating a median array that rejects the highest pixel and computes the lowest valid pixel after mask application.

Response:
def min_med(images, weight_images, readnoise_list, exptime_list,
            background_values, weight_masks=None, combine_grow=1,
            combine_nsigma1=4, combine_nsigma2=3, fillval=False):
    """ Create a median array, rejecting the highest pixel and
    computing the lowest valid pixel after mask application.

    .. note::
        In this version of the mimmed algorithm we assume that the units of
        all input data is electons.

    Parameters
    ----------
    images : list of numpy.ndarray
        List of input data to be combined.

    weight_images : list of numpy.ndarray
        List of input data weight images to be combined.

    readnoise_list : list
        List of readnoise values to use for the input images.

    exptime_list : list
        List of exposure times to use for the input images.

    background_values : list
        List of image background values to use for the input images.

    weight_masks : list of numpy.ndarray, None
        List of imput data weight masks to use for pixel rejection.
        (Default: `None`)

    combine_grow : int
        Radius (pixels) for neighbor rejection. (Default: 1)

    combine_nsigma1 : float
        Significance for accepting minimum instead of median. (Default: 4)

    combine_nsigma2 : float
        Significance for accepting minimum instead of median. (Default: 3)

    fillval : bool
        Turn on use of imedian/imean. (Default: `False`)

    Returns
    -------
    combined_array : numpy.ndarray
        Combined array.

    """
    # In this case we want to calculate two things:
    #   1) the median array, rejecting the highest pixel (thus running
    #      imcombine with nlow=0, nhigh=1, nkeep=1, using the masks)
    #   2) the lowest valid pixel after applying the masks (thus running
    #      imcombine with nlow=0, nhigh=3, nkeep=1, using the masks)
    #
    # We also calculate the sum of the weight files (to produce the total
    # effective exposure time for each pixel).
    #
    # The total effective background in the final image is calculated as
    # follows:
    #   - convert background for each input image to counts/s
    #     (divide by exptime)
    #   - multiply this value by the weight image, to obtain the effective
    #     background counts (in DN) for each pixel, for each image
    #   - Add these images together, to obtain the total effective background
    #     for the combined image.
    #
    # Once we've made these two files, then calculate the SNR based on the
    # median-pixel image, and compare with the minimum.

    nimages = len(images)
    combtype_median = 'imedian' if fillval else 'median'
    images = np.asarray(images)
    weight_images = np.asarray(weight_images)

    if weight_masks == [] or weight_masks is None:
        weight_masks = None
        mask_sum = np.zeros(images.shape[1:], dtype=np.int16)
        all_bad_idx = np.array([], dtype=np.int)
        all_bad_idy = np.array([], dtype=np.int)
    else:
        weight_masks = np.asarray(weight_masks, dtype=np.bool)
        mask_sum = np.sum(weight_masks, axis=0, dtype=np.int16)
        all_bad_idx, all_bad_idy = np.where(mask_sum == nimages)

    # Create a different median image based upon the number of images in the
    # input list.
    if nimages == 2:
        median_file = num_combine(
            images,
            masks=weight_masks,
            combination_type='imean' if fillval else 'mean',
            nlow=0, nhigh=0, lower=None, upper=None
        )

    else:
        # The value of NHIGH=1 will cause problems when there is only 1 valid
        # unmasked input image for that pixel due to a difference in behavior
        # between 'num_combine' and 'iraf.imcombine'.
        # This value may need to be adjusted on the fly based on the number of
        # inputs and the number of masked values/pixel.
        #
        median_file = num_combine(
            images,
            masks=weight_masks,
            combination_type=combtype_median,
            nlow=0, nhigh=1, lower=None, upper=None
        )

        # The following section of code will address the problem caused by
        # having a value of nhigh = 1.  This will behave in a way similar to
        # the way the IRAF task IMCOMBINE behaves.  In order to accomplish
        # this, the following procedure will be followed:
        # 1) The input masks will be summed.
        # 2) The science data will be summed.
        # 3) In the locations of the summed mask where the sum is 1 less than
        #    the total number of images, the value of that location in the
        #    summed science image will be used to replace the existing value
        #    in the existing median_file.
        #
        # This procedure is being used to prevent too much data from being
        # thrown out of the image. Take for example the case of 3 input images.
        # In two of the images the pixel locations have been masked out.
        # Now, if nhigh is applied there will be no value to use for that
        # position.  However, if this new procedure is used that value in
        # the resulting images will be the value that was rejected by the
        # nhigh rejection step.

        # We need to make certain that "bad" pixels in the sci data are set to
        # 0. That way, when the sci images are summed, the value of the sum
        # will only come from the "good" pixels.
        if weight_masks is None:
            sci_sum = np.sum(images, axis=0)
            if nimages == 1:
                median_file = sci_sum

        else:
            sci_sum = np.sum(images * np.logical_not(weight_masks), axis=0)
            # Use the summed sci image values in locations where the mask_sum
            # indicates that there is only 1 good pixel to use. The value will
            # be used in the median_file image
            idx = np.where(mask_sum == (nimages - 1))
            median_file[idx] = sci_sum[idx]

    # Create the minimum image from the stack of input images.
    if weight_masks is not None:
        # make a copy of images to avoid side-effect of modifying input
        # argument:
        images = images.copy()
        images[weight_masks] = np.nan
        images[:, all_bad_idx, all_bad_idy] = 0
        minimum_file = np.nanmin(images, axis=0)
    else:
        minimum_file = np.amin(images, axis=0)

    # Scale the weight images by the background values and add them to the bk
    # Create an image of the total effective background (in DN) per pixel:
    # (which is the sum of all the background-scaled weight files)
    s = np.asarray([bv / et for bv, et in
                    zip(background_values, exptime_list)])
    bkgd_file = np.sum(weight_images * s[:, None, None], axis=0)

    # Scale the weight mask images by the square of the readnoise values.
    # Create an image of the total readnoise**2 per pixel
    # (which is the sum of all the input readnoise values).
    if weight_masks is None:
        rdn2 = sum((r**2 for r in readnoise_list))
        readnoise_file = rdn2 * np.ones_like(images[0])

    else:
        readnoise_file = np.sum(
            np.logical_not(weight_masks) *
            (np.asarray(readnoise_list)**2)[:, None, None],
            axis=0
        )

    # Create an image of the total effective exposure time per pixel:
    # (which is simply the sum of all the drizzle output weight files)
    weight_file = np.sum(weight_images, axis=0)

    # Scale up both the median and minimum arrays by the total effective
    # exposure time per pixel.
    minimum_file_weighted = minimum_file * weight_file
    median_file_weighted = median_file * weight_file
    del weight_file

    # Calculate the 1-sigma r.m.s.:
    #   variance = median_electrons + bkgd_electrons + readnoise**2
    #   rms = sqrt(variance)
    #   This image has units of electrons.
    #
    # make this the abs value so that negative numbers dont throw an exception?
    rms_file2 = np.fmax(
        median_file_weighted + bkgd_file + readnoise_file,
        np.zeros_like(median_file_weighted)
    )
    rms_file = np.sqrt(rms_file2)
    del bkgd_file, readnoise_file

    # For the median array, calculate the n-sigma lower threshold to the array
    # and incorporate that into the pixel values.
    median_rms_file = median_file_weighted - rms_file * combine_nsigma1

    if combine_grow != 0:
        # Do a more sophisticated rejection: For all cases where the minimum
        # pixel will be accepted instead of the median, set a lower threshold
        # for that pixel and the ones around it (ie become less conservative
        # in rejecting the median). This is because in cases of
        # triple-incidence cosmic rays, quite often the low-lying outliers
        # of the CRs can influence the median for the initial relatively high
        # value of sigma, so a lower threshold must be used to mnake sure that
        # the minimum is selected.
        #
        # This is done as follows:
        # 1) make an image which is zero everywhere except where the minimum
        #    will be accepted
        # 2) box-car smooth this image, to make these regions grow.
        # 3) In the file "median_rms_file_electrons", replace these pixels
        #     by median - combine_nsigma2 * rms
        #
        # Then use this image in the final replacement, in the same way as for
        # the case where this option is not selected.
        minimum_flag_file = np.less(minimum_file_weighted,
                                    median_rms_file).astype(np.float64)

        # The box size value must be an integer. This is not a problem since
        # __combine_grow should always be an integer type. The combine_grow
        # column in the MDRIZTAB should also be an integer type.
        boxsize = int(2 * combine_grow + 1)
        boxshape = (boxsize, boxsize)
        minimum_grow_file = np.zeros_like(images[0])

        # If the boxcar convolution has failed it is potentially for
        # two reasons:
        #   1) The kernel size for the boxcar is bigger than the actual image.
        #   2) The grow parameter was specified with a value < 0.  This would
        #      result in an illegal boxshape kernel. The dimensions of the
        #      kernel box *MUST* be integer and greater than zero.
        #
        #   If the boxcar convolution has failed, try to give a meaningfull
        #   explanation as to why based upon the conditionals described above.
        if boxsize <= 0:
            errormsg1 = "############################################################\n"
            errormsg1 += "# The boxcar convolution in minmed has failed.  The 'grow' #\n"
            errormsg1 += "# parameter must be greater than or equal to zero. You     #\n"
            errormsg1 += "# specified an input value for the 'grow' parameter of:    #\n"
            errormsg1 += "        combine_grow: " + str(combine_grow)+'\n'
            errormsg1 += "############################################################\n"
            raise ValueError(errormsg1)

        if boxsize > images.shape[1]:
            errormsg2 = "############################################################\n"
            errormsg2 += "# The boxcar convolution in minmed has failed.  The 'grow' #\n"
            errormsg2 += "# parameter specified has resulted in a boxcar kernel that #\n"
            errormsg2 += "# has dimensions larger than the actual image.  You        #\n"
            errormsg2 += "# specified an input value for the 'grow' parameter of:    #\n"
            errormsg2 += "        combine_grow: " + str(combine_grow) + '\n'
            errormsg2 += "############################################################\n"
            print(images.shape[1:])
            raise ValueError(errormsg2)

        # Attempt the boxcar convolution using the boxshape based upon the user
        # input value of "grow"
        ker = np.ones((boxsize, boxsize)) / float(boxsize**2)
        minimum_grow_file = signal.convolve2d(minimum_flag_file, ker,
                                              boundary='fill', mode='same')

        median_rms_file = np.where(
            np.equal(minimum_grow_file, 0),
            median_file_weighted - rms_file * combine_nsigma1,
            median_file_weighted - rms_file * combine_nsigma2
        )
        del rms_file, minimum_grow_file

    # Finally decide whether to use the minimim or the median (in counts/s),
    # based on whether the median is more than 3 sigma above the minimum.
    combined_array = np.where(
        np.less(minimum_file_weighted, median_rms_file),
        minimum_file,
        median_file
    )
    # Set fill regions to a pixel value of 0.
    combined_array[all_bad_idx, all_bad_idy] = 0

    return combined_array


Instruction:
Can you implement a function in Python 3 that
sums a list of numarray objects.

Response:
def _sumImages(self,numarrayObjectList):
        """ Sum a list of numarray objects. """
        if numarrayObjectList in [None, []]:
            return None

        tsum = np.zeros(numarrayObjectList[0].shape, dtype=numarrayObjectList[0].dtype)

        for image in numarrayObjectList:
            tsum += image

        return tsum


Instruction:
Can you generate a brief explanation for the following Python 3 code
def moments(data,cntr):
    total = data.sum()
    #X, Y = np.indices(data.shape)
    #x = (X*data).sum()/total
    #y = (Y*data).sum()/total
    x,y = cntr
    xi = int(x)
    yi = int(y)
    if xi < 0 or xi >= data.shape[1] or yi < 0 or yi >= data.shape[0]:
        raise ValueError
    col = data[:, xi]
    width_x = np.sqrt(abs(((np.arange(col.size)-y)**2*col).sum()/col.sum()))
    row = data[yi, :]
    width_y = np.sqrt(abs(((np.arange(row.size)-x)**2*row).sum()/row.sum()))
    height = data.max()
    return height, x, y, width_x, width_y

Response:
Returns the height x y width_x width_y the gaussian parameters of a 2D distribution by calculating its
    moments.