Instruction:
How would you explain what the following Python 3 function does
def buildFileListOrig(input, output=None, ivmlist=None,
                wcskey=None, updatewcs=True, **workinplace):
    """
    Builds a file list which has undergone various instrument-specific
    checks for input to MultiDrizzle, including splitting STIS associations.
    Compared to buildFileList, this version returns the list of the
    original file names as specified by the user (e.g., before GEIS->MEF, or
    WAIVER FITS->MEF conversion).
    """
    # NOTE: original file name is required in order to correctly associate
    # user catalog files (e.g., user masks to be used with 'skymatch') with
    # corresponding imageObjects.

    filelist, output, ivmlist, oldasndict = processFilenames(input,output)

    # verify that all input images specified can be updated as needed
    filelist = util.verifyFilePermissions(filelist)
    if filelist is None or len(filelist) == 0:
        return None, None, None, None, None

    manageInputCopies(filelist,**workinplace)

    # to keep track of the original file names we do the following trick:
    # pack filelist with the ivmlist using zip and later unpack the zipped list.
    #
    # NOTE: this required a small modification of the checkStisFiles function
    # in stsci.tools.check_files to be able to handle ivmlists that are tuples.
    if ivmlist is None:
        ivmlist = len(filelist)*[None]
    else:
        assert(len(filelist) == len(ivmlist)) #TODO: remove after debugging
    ivmlist = list(zip(ivmlist,filelist))

    # Check format of FITS files - convert Waiver/GEIS to MEF if necessary
    filelist, ivmlist = check_files.checkFITSFormat(filelist, ivmlist)

    # check for non-polynomial distortion correction
    if not updatewcs:
        # with updatewcs turned on, any problems will get resolved
        # so we do not need to be concerned about the state of the DGEOFILEs
        filelist = checkDGEOFile(filelist)

    # run all WCS updating
    updated_input = _process_input_wcs(filelist, wcskey, updatewcs)

    newfilelist, ivmlist = check_files.checkFiles(updated_input, ivmlist)

    if updatewcs:
        uw.updatewcs(','.join(set(newfilelist) - set(filelist)))

    if len(ivmlist) > 0:
        ivmlist, filelist = list(zip(*ivmlist))
    else:
        filelist = [] # insure that both filelist and ivmlist are defined as empty lists

    return newfilelist, ivmlist, output, oldasndict, filelist

Response: Builds a list of original file names for a multi - drizzle input.


Instruction:
How would you explain what the following Python 3 function does
def buildASNList(rootnames, asnname, check_for_duplicates=True):

    # Recognize when multiple valid inputs with the same rootname are present
    # this would happen when both CTE-corrected (_flc) and non-CTE-corrected (_flt)
    # products are in the same directory as an ASN table
    filelist, duplicates = checkForDuplicateInputs(rootnames)

    if check_for_duplicates and duplicates:
        # Build new ASN tables for each set of input files
        origasn = changeSuffixinASN(asnname, 'flt')
        dupasn = changeSuffixinASN(asnname, 'flc')

        errstr = 'ERROR:\nMultiple valid input files found:\n'
        for fname, dname in zip(filelist, duplicates):
            errstr += '    %s    %s\n' % (fname, dname)
        errstr += ('\nNew association files have been generated for each '
                   'version of these files.\n    %s\n    %s\n\nPlease '
                   're-start astrodrizzle using of these new ASN files or '
                   'use widlcards for the input to only select one type of '
                   'input file.' % (dupasn, origasn))

        print(textutil.textbox(errstr), file=sys.stderr)

        # generate new ASN files for each case,
        # report this case of duplicate inputs to the user then quit
        raise ValueError

    return filelist

Response: Build a list of filenames for a given set of rootnames.


Instruction:
Can you tell what is the following Python 3 function doing
def changeSuffixinASN(asnfile, suffix):
    # Start by creating a new name for the ASN table
    _new_asn = asnfile.replace('_asn.fits','_'+suffix+'_asn.fits')
    if os.path.exists(_new_asn):
        os.remove(_new_asn)
    # copy original ASN table to new table
    shutil.copy(asnfile,_new_asn)

    # Open up the new copy and convert all MEMNAME's to include suffix
    fasn = fits.open(_new_asn, mode='update', memmap=False)
    fasn[0].header['DUPCHECK'] = "COMPLETE"
    newdata = fasn[1].data.tolist()
    for i in range(len(newdata)):
        val = newdata[i][0].decode(encoding='UTF-8').strip()
        if 'prod' not in newdata[i][1].decode(encoding='UTF-8').lower():
            val += '_'+suffix
        newdata[i] = (val,newdata[i][1].strip(),newdata[i][2])

    # Redefine dtype to support longer strings for MEMNAME
    new_dtype = []
    d = fasn[1].data.dtype
    msize = d.descr[0][1][1:]
    new_size = int(msize[1:])+8
    mtype = msize[0]
    new_dtype.append((d.descr[0][0],d.descr[0][1].replace(msize,'{}{}'.format(mtype,new_size))))
    new_dtype.append(d.descr[1])
    new_dtype.append(d.descr[2])

    # Assign newly created, reformatted array to extension
    newasn = np.array(newdata,dtype=new_dtype)
    fasn[1].data = newasn
    fasn.close()

    return _new_asn

Response: Change the suffix in the ASN file to include the suffix.


Instruction:
Implement a function in Python 3 to
check input files specified in ASN table for duplicate versions with multiple valid suffixes.

Response:
def checkForDuplicateInputs(rootnames):
    """
    Check input files specified in ASN table for duplicate versions with
    multiple valid suffixes (_flt and _flc, for example).
    """

    flist = []
    duplist = []

    for fname in rootnames:
        # Look for any recognized CTE-corrected products
        f1 = fileutil.buildRootname(fname,ext=['_flc.fits'])
        f2 = fileutil.buildRootname(fname)
        flist.append(f2)
        if os.path.exists(f1) and f1 != f2:
            # More than 1 valid input found for this rootname
            duplist.append(f1)

    return flist,duplist


Instruction:
Can you write a function in Python 3 where it
resets CR bits in each input image s DQ array

Response:
def resetDQBits(imageObjectList, cr_bits_value=4096):
    """Reset the CR bit in each input image's DQ array"""

    if cr_bits_value > 0:
        for img in imageObjectList:
            for chip in range(1,img._numchips+1,1):
                sci_chip = img._image[img.scienceExt,chip]
                resetbits.reset_dq_bits(sci_chip.dqfile, cr_bits_value,
                                        extver=chip, extname=sci_chip.dq_extn)


Instruction:
Write a Python 3 function that can
update names in a member dictionary.

Response:
def update_member_names(oldasndict, pydr_input):
    """
    Update names in a member dictionary.

    Given an association dictionary with rootnames and a list of full
    file names, it will update the names in the member dictionary to
    contain '_*' extension. For example a rootname of 'u9600201m' will
    be replaced by 'u9600201m_c0h' making sure that a MEf file is passed
    as an input and not the corresponding GEIS file.
    """

    omembers = oldasndict['members'].copy()
    nmembers = {}
    translated_names = [f.split('.fits')[0] for f in pydr_input]

    newkeys = [fileutil.buildNewRootname(file) for file in pydr_input]
    keys_map = list(zip(newkeys, pydr_input))

    for okey, oval in list(omembers.items()):
        if okey in newkeys:
            nkey = pydr_input[newkeys.index(okey)]
            nmembers[nkey.split('.fits')[0]] = oval

    oldasndict.pop('members')
    # replace should be always True to cover the case when flt files were removed
    # and the case when names were translated

    oldasndict.update(members=nmembers, replace=True)
    oldasndict['order'] = translated_names
    return oldasndict


Instruction:
Make a summary of the following Python 3 code
def manageInputCopies(filelist, **workinplace):

    # Find out what directory is being used for processing
    workingdir = os.getcwd()
    # Only create sub-directory for copies of inputs, if copies are requested
    # Create name of sub-directory for copies
    origdir = os.path.join(workingdir,'OrIg_files')
    if workinplace['overwrite'] or workinplace['preserve']:
        # if sub-directory does not exist yet, create it
        if not os.path.exists(origdir):
            os.mkdir(origdir)

    printMsg = True
    # check to see if copies already exist for each file
    for fname in filelist:
        copymade = False # If a copy is made, no need to restore
        copyname = os.path.join(origdir,fname)
        short_copyname = os.path.join('OrIg_files',fname)
        if workinplace['overwrite']:
            print('Forcibly archiving original of: ',fname, 'as ',short_copyname)
            # make a copy of the file in the sub-directory
            if os.path.exists(copyname): os.chmod(copyname, 438) # octal 666
            shutil.copy(fname,copyname)
            os.chmod(copyname,292) # octal 444 makes files read-only
            if printMsg:
                print('\nTurning OFF "preserve" and "restore" actions...\n')
                printMsg = False # We only need to print this one time...
            copymade = True

        if (workinplace['preserve'] and not os.path.exists(copyname)) \
                and not workinplace['overwrite']:
            # Preserving a copy of the input, but only if not already archived
            print('Preserving original of: ',fname, 'as ',short_copyname)
            # make a copy of the file in the sub-directory
            shutil.copy(fname,copyname)
            os.chmod(copyname,292) # octal 444 makes files read-only
            copymade = True

        if 'restore' in workinplace and not copymade:
            if (os.path.exists(copyname) and workinplace['restore']) and not workinplace['overwrite']:
                print('Restoring original input for ',fname,' from ',short_copyname)
                # replace current files with original version
                os.chmod(fname, 438) # octal 666
                shutil.copy(copyname, fname)
                os.chmod(fname, 438)

Response: Manage input copies of all input images in a sub - directory.


Instruction:
Here you have a function in Python 3, explain what it does
def buildEmptyDRZ(input, output):

    # Identify the first input image
    inputfile = parseinput.parseinput(input)[0]
    if not inputfile:
        print('\n******* ERROR *******', file=sys.stderr)
        print(
              'No input file found!  Check specification of parameter '
              '"input". ', file=sys.stderr)
        print('Quitting...',  file=sys.stderr)
        print('******* ***** *******\n',  file=sys.stderr)
        return # raise IOError, "No input file found!"

    # Set up output file here...
    if output is None:
        if len(input) == 1:
            oname = fileutil.buildNewRootname(input[0])
        else:
            oname = 'final'
        output = fileutil.buildNewRootname(oname, extn='_drz.fits')
    else:
        if 'drz' not in output:
            output = fileutil.buildNewRootname(output, extn='_drz.fits')

    log.info('Setting up output name: %s' % output)

    # Open the first image (of the excludedFileList?) to use as a template to build
    # the DRZ file.
    try :
        log.info('Building empty DRZ file from %s' % inputfile[0])
        img = fits.open(inputfile[0], memmap=False)
    except:
        raise IOError('Unable to open file %s \n' % inputfile)

    # Create the fitsobject
    fitsobj = fits.HDUList()
    # Copy the primary header
    hdu = img[0].copy()
    fitsobj.append(hdu)

    # Modify the 'NEXTEND' keyword of the primary header to 3 for the
    #'sci, wht, and ctx' extensions of the newly created file.
    fitsobj[0].header['NEXTEND'] = 3

    # Create the 'SCI' extension
    hdu = fits.ImageHDU(header=img['sci', 1].header.copy())
    hdu.header['EXTNAME'] = 'SCI'
    fitsobj.append(hdu)

    # Create the 'WHT' extension
    hdu = fits.ImageHDU(header=img['sci', 1].header.copy())
    hdu.header['EXTNAME'] = 'WHT'
    fitsobj.append(hdu)

    # Create the 'CTX' extension
    hdu = fits.ImageHDU(header=img['sci', 1].header.copy())
    hdu.header['EXTNAME'] = 'CTX'
    fitsobj.append(hdu)

    # Add HISTORY comments explaining the creation of this file.
    fitsobj[0].header.add_history("** AstroDrizzle has created this empty "
                                  "DRZ product because**")
    fitsobj[0].header.add_history("** all input images were excluded from "
                                  "processing.**")

    # Change the filename in the primary header to reflect the name of the output
    # filename.
    fitsobj[0].header['FILENAME'] = str(output)  # +"_drz.fits"

    # Change the ROOTNAME keyword to the ROOTNAME of the output PRODUCT
    fitsobj[0].header['ROOTNAME'] = str(output.split('_drz.fits')[0])
    # Modify the ASN_MTYP keyword to contain "PROD-DTH" so it can be properly
    # ingested into the archive catalog.

    # stis has this keyword in the [1] header, so I am directing the code
    #t o first look in the primary, then the 1
    try:
        fitsobj[0].header['ASN_MTYP'] = 'PROD-DTH'
    except:
        fitsobj[1].header['ASN_MTYP'] = 'PROD-DTH'

    # If the file is already on disk delete it and replace it with the
    # new file
    dirfiles = os.listdir(os.curdir)
    if dirfiles.count(output) > 0:
        os.remove(output)
        log.info("       Replacing %s..." % output)

    # Write out the empty DRZ file
    fitsobj.writeto(output)

    print(textutil.textbox(
        'ERROR:\nAstroDrizzle has created an empty DRZ product because all '
        'input images were excluded from processing or a user requested the '
        'program to stop.') + '\n', file=sys.stderr)

    return

Response: This module creates an empty DRZ file from a list of excluded files.


Instruction:
Write a Python 3 function that can
verify that input file has been updated with NPOLFILE This function checks for the presence of 'NPOLFILE' kw in the primary header when 'DGEOFILE' kw is present and valid (i.e. 'DGEOFILE' is not blank or 'N/A'). It handles the case of science files downloaded from the archive before the new software was installed there. If 'DGEOFILE' is present and 'NPOLFILE' is missing, print a message and let the user choose whether to (q)uit and update the headers or (c)ontinue and run astrodrizzle without the non-polynomial correction. 'NPOLFILE' will be populated in the pipeline before astrodrizzle is run. In the case of WFPC2 the old style dgeo files are used to create detector to image correction at runtime. Parameters ---------- filenames : list of str file names of all images to be checked

Response:
def checkDGEOFile(filenames):
    """
    Verify that input file has been updated with NPOLFILE

    This function checks for the presence of 'NPOLFILE' kw in the primary header
    when 'DGEOFILE' kw is present and valid (i.e. 'DGEOFILE' is not blank or 'N/A').
    It handles the case of science files downloaded from the archive before the new
    software was installed there.
    If 'DGEOFILE' is present and 'NPOLFILE' is missing, print a message and let the user
    choose whether to (q)uit and update the headers or (c)ontinue and run astrodrizzle
    without the non-polynomial correction.
    'NPOLFILE' will be populated in the pipeline before astrodrizzle is run.

    In the case of WFPC2 the old style dgeo files are used to create detector to image
    correction at runtime.

    Parameters
    ----------
    filenames : list of str
        file names of all images to be checked

    """

    msg = """
            A 'DGEOFILE' keyword is present in the primary header but 'NPOLFILE' keyword was not found.
            This version of the software uses a new format for the residual distortion DGEO files.
            Please consult the instrument web pages for which reference files to download.
            A small (new style) dgeofile is needed ('_npl.fits' extension) and possibly a
            detector to image correction file ('_d2i.fits' extension).
            The names of these files must be added to the primary header either using the task XXXX
            or manually, for example:

            hedit {0:s}[0] npolfile fname_npl.fits add+
            hedit {0:s}[0] d2imfile fname_d2i.fits add+

            where fname_npl.fits is the name of the new style dgeo file and fname_d2i.fits is
            the name of the detector to image correction. After adding these keywords to the
            primary header, updatewcs must be run to update the science files:

            from stwcs import updatewcs
            updatewcs.updatewcs("{0:s}")

            Alternatively you may choose to run astrodrizzle without DGEO and detector to image correction.

            To stop astrodrizzle and update the dgeo files, type 'q'.
            To continue running astrodrizzle without the non-polynomial distortion correction, type 'c':
            """

    short_msg = """
            To stop astrodrizzle and update the dgeo files, type 'q'.
            To continue running astrodrizzle without the non-polynomial distortion correction, type 'c':
    """

    for inputfile in filenames:
        try:
            dgeofile = fits.getval(inputfile, 'DGEOFILE', memmap=False)
        except KeyError:
            continue
        if dgeofile not in ["N/A", "n/a", ""]:
            message = msg.format(inputfile)
            try:
                npolfile = fits.getval(inputfile, 'NPOLFILE', memmap=False)
            except KeyError:
                ustop = userStop(message)
                while ustop is None:
                    ustop = userStop(short_msg)
                if ustop:
                    return None

    return filenames


Instruction:
Write a Python 3 function for
defining full set of default values for unit - testing this module.

Response:
def _setDefaults(input_dict={}):
    """ Define full set of default values for unit-testing this module.[OBSOLETE]"""
    paramDict = {
        'input':'*flt.fits',
        'output':None,
        'mdriztab':None,
        'refimage':None,
        'runfile':None,
        'workinplace':False,
        'updatewcs':True,
        'proc_unit':'native',
        'coeffs':True,
        'context':False,
        'clean':True,
        'group':None,
        'ra':None,
        'dec':None,
        'build':True,
        'gain':None,
        'gnkeyword':None,
        'readnoise':None,
        'rnkeyword':None,
        'exptime':None,
        'expkeyword':None,
        'crbitval':4096,
        'static':True,
        'static_sig':4.0,
        'skysub':True,
        'skymethod':"globalmin+match",
        'skystat':"median",
        'skywidth':0.1,
        'skylower':None,
        'skyupper':None,
        'skyclip':5,
        'skylsigma':4.0,
        'skyusigma':4.0,
        "skymask_cat":"",
        "use_static":True,
        "sky_bits":0,
        "skyuser":"",
        "skyfile":"",
        'driz_separate':True,
        'driz_sep_outnx':None,
        'driz_sep_outny':None,
        'driz_sep_crpix1':None,
        'driz_sep_crpix2':None,
        'driz_sep_kernel':'turbo',
        'driz_sep_scale':None,
        'driz_sep_pixfrac':1.0,
        'driz_sep_rot':None,
        'driz_sep_fillval':None,
        'driz_sep_bits':0,
        'median':True,
        'median_newmasks':True,
        'combine_type':"minmed",
        'combine_nsigma':"4 3",
        'combine_nlow':0,
        'combine_nhigh':1,
        'combine_lthresh':None,
        'combine_hthresh':None,
        'combine_grow':1,
        'blot':True,
        'blot_interp':'poly5',
        'blot_sinscl':1.0,
        'driz_cr':True,
        'driz_cr_corr':False,
        'driz_cr_snr':"3.5 3.0",
        'driz_cr_scale':"1.2 0.7",
        'driz_cr_cteg':0,
        'driz_cr_grow':1,
        'driz_combine':True,
        'final_wht_type':"EXP",
        'final_outnx':None,
        'final_outny':None,
        'final_crpix1':None,
        'final_crpix2':None,
        'final_kernel':'square',
        'final_scale':None,
        'final_pixfrac':1.0,
        'final_rot':None,
        'final_fillval':None,
        'final_bits':0}

    paramDict.update(input_dict)

    print('\nUser Input Parameters for Init Step:')
    util.printParams(paramDict)

    return paramDict


Instruction:
Write a Python 3 function that can
return an array representing the dark image for the detector.

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

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

        """

        # Read the temperature dependeant dark file.  The name for the file is taken from
        # the TEMPFILE keyword in the primary header.
        tddobj = readTDD.fromcalfile(self.name)

        if tddobj is None:
            return np.ones(self.full_shape, dtype=self.image_dtype) * self.getdarkcurrent()
        else:
            # Create Dark Object from AMPGLOW and Lineark Dark components
            darkobj = tddobj.getampglow() + tddobj.getlindark()

            # Return the darkimage taking into account an subarray information available
            return darkobj[self.ltv2:self.size2,self.ltv1:self.size1]


Instruction:
Can you generate a brief explanation for the following Python 3 code
def isCountRate(self):
        has_bunit = False
        if 'BUNIT' in self._image['sci',1].header :
            has_bunit = True

        countrate = False
        if (self._image[0].header['UNITCORR'].strip() == 'PERFORM') or \
            (has_bunit and self._image['sci',1].header['bunit'].find('/') != -1) :
            countrate = True

        return countrate

Response:
Method or IRInputObject used to indicate if the input
        science data is in units of counts or count rate.


Instruction:
How would you explain what the following Python 3 function does
def photeq(files='*_flt.fits', sciext='SCI', errext='ERR',
           ref_phot=None, ref_phot_ext=None,
           phot_kwd='PHOTFLAM', aux_phot_kwd='PHOTFNU',
           search_primary=True,
           readonly=True, clobber=False, logfile='photeq.log'):
    """
    Adjust data values of images by equalizing each chip's PHOTFLAM value
    to a single common value so that all chips can be treated equally
    by ``AstroDrizzle``.

    Parameters
    ----------

    files : str (Default = ``'*_flt.fits'``)

        A string containing one of the following:

            * a comma-separated list of valid science image file names,
              e.g.: ``'j1234567q_flt.fits, j1234568q_flt.fits'``;

            * an @-file name, e.g., ``'@files_to_match.txt'``. See notes
              section for details on the format of the @-files.

        .. note::

            **Valid science image file names** are:

            * file names of existing FITS, GEIS, or WAIVER FITS files;

            * partial file names containing wildcard characters, e.g.,
              ``'*_flt.fits'``;

            * Association (ASN) tables (must have ``_asn``, or ``_asc``
              suffix), e.g., ``'j12345670_asn.fits'``.

    sciext : str (Default = 'SCI')
        Extension *name* of extensions whose data and/or headers should
        be corrected.

    errext : str (Default = 'ERR')
        Extension *name* of the extensions containing corresponding error
        arrays. Error arrays are corrected in the same way as science data.

    ref_phot : float, None (Default = None)
        A number indicating the new value of PHOTFLAM or PHOTFNU
        (set by 'phot_kwd') to which the data should be adjusted.

    ref_phot_ext : int, str, tuple, None (Default = None)
        Extension from which the `photeq` should get the reference photometric
        value specified by the `phot_kwd` parameter. This parameter is ignored
        if `ref_phot` **is not** `None`. When `ref_phot_ext` is `None`, then
        the reference inverse sensitivity value will be picked from the
        first `sciext` of the first input image containing `phot_kwd`.

    phot_kwd : str (Default = 'PHOTFLAM')
        Specifies the primary keyword which contains inverse sensitivity
        (e.g., PHOTFLAM). It is used to compute conversion factors by
        which data should be rescaled.

    aux_phot_kwd : str, None, list of str (Default = 'PHOTFNU')
        Same as `phot_kwd` but describes *other* photometric keyword(s)
        that should be corrected by inverse of the scale factor used to correct
        data. These keywords are *not* used to compute conversion factors.
        Multiple keywords can be specified as a Python list of strings:
        ``['PHOTFNU', 'PHOTOHMY']``.

        .. note::

            If specifying multiple secondary photometric keywords in the TEAL
            interface, use a comma-separated list of keywords.

    search_primary : bool (Default = True)
        Specifies whether to first search the primary header for the
        presence of `phot_kwd` keyword and compute conversion factor based on
        that value. This is (partially) ignored when `ref_phot` is not `None` in
        the sense that the value specified by `ref_phot` will be used as the
        reference *but* in all images primary will be searched for `phot_kwd`
        and `aux_phot_kwd` and those values will be corrected
        (if ``search_primary=True``).

    readonly : bool (Default = True)
        If `True`, `photeq` will not modify input files (nevertheless, it will
        convert input GEIS or WAVERED FITS files to MEF and could overwrite
        existing MEF files if `clobber` is set to `True`).
        The (console or log file) output however will be identical to the case
        when ``readonly=False`` and it can be examined before applying these
        changes to input files.

    clobber : bool (Default = False)
        Overwrite existing MEF files when converting input WAVERED FITS or GEIS
        to MEF.

    logfile : str, None (Default = 'photeq.log')
        File name of the log file.

    Notes
    -----

    By default, `photeq` will search for the first inverse sensitivity
    value (given by the header keyword specified by the `phot_kwd` parameter,
    e.g., PHOTFLAM or PHOTFNU) found in the input images and it will equalize
    all other images to this reference value.

    It is possible to tell `photeq` to look for the reference inverse
    sensitivity value only in a specific extension of input images, e.g.: 3,
    ('sci',3), etc. This can be done by setting `ref_phot_ext` to a specific
    extension. This may be useful, for example, for WFPC2 images: WF3 chip was
    one of the better calibrated chips, and so, if one prefers to have
    inverse sensitivities equalized to the inverse sensitivity of the WF3 chip,
    one can set ``ref_phot_ext=3``.

    Alternatively, one can provide their own reference inverse sensitivity
    value to which all other images should be "equalized" through the
    parameter `ref_phot`.

    .. note::

       Default parameter values (except for `files`, `readonly`, and `clobber`)
       should be acceptable for most HST images.

    .. warning::

       If images are intended to be used with ``AstroDrizzle``, it is
       recommended that sky background measurement be performed on "equalized"
       images as the `photeq` is not aware of sky user keyword in the image
       headers and thus it cannot correct sky values already recorded in the
       headers.

    Examples
    --------

    #. In most cases the default parameters should suffice:

           >>> from drizzlepac import photeq
           >>> photeq.photeq(files='*_flt.fits', readonly=False)

    #. If the re-calibration needs to be done on PHOTFNU rather than
       PHOTFLAM, then:

           >>> photeq.photeq(files='*_flt.fits', ref_phot='PHOTFNU',
           ... aux_phot_kwd='PHOTFLAM')

    #. If for WFPC2 data one desires that PHOTFLAM from WF3 be used as the
       reference in WFPC2 images, then:

           >>> photeq.photeq(files='*_flt.fits', ref_phot_ext=3) # or ('sci',3)

    """

    # Time it
    runtime_begin = datetime.now()

    # check that input file name is a string:
    if not isinstance(files, str):
        raise TypeError("Argument 'files' must be a comma-separated list of "
                        " file names")

    # Set-up log files:
    if isinstance(logfile, str):
        # first, in case there are any "leftover" file handlers,
        # close and remove them:
        for h in _log.handlers:
            if h is not _sh_log and isinstance(h, logging.FileHandler):
                h.close()
                _log.removeHandler(h)
        # create file handler:
        log_formatter = logging.Formatter('[%(levelname)s:] %(message)s')
        log_file_handler = logging.FileHandler(logfile)
        log_file_handler.setFormatter(log_formatter)
        # add log_file_handler to logger
        _log.addHandler(log_file_handler)

    elif logfile is not None:
        raise TypeError("Unsupported 'logfile' type")

    #  BEGIN:
    _mlinfo("***** {0} started on {1}".format(__taskname__, runtime_begin))
    _mlinfo("      Version {0} ({1})".format(__version__, __version_date__))

    # check that extension names are strings (or None for error ext):
    if sciext is None:
        sci_ext4parse = '*'
        ext2get = None
    else:
        if not isinstance(sciext, str):
            raise TypeError("Argument 'sciext' must be a string or None")
        sciext = sciext.strip()
        if sciext.upper() == 'PRIMARY':
            sciext = sciext.upper()
            ext2get = (sciext, 1)
        else:
            ext2get = (sciext, '*')

        sci_ext4parse = ext2get

    if errext is not None and not isinstance(errext, str):
        raise TypeError("Argument 'errext' must be a string or None")

    # check that phot_kwd is supported:
    if not isinstance(phot_kwd, str):
        raise TypeError("Argument 'phot_kwd' must be a string")
    phot_kwd = phot_kwd.strip().upper()

    # check that ref_phot_ext has correct type:
    if ref_phot_ext is not None and not \
       (isinstance(ref_phot_ext, int) or isinstance(ref_phot_ext, str) \
        or (isinstance(ref_phot_ext, tuple) and len(ref_phot_ext) == 2 \
            and isinstance(ref_phot_ext[0], str) and \
            isinstance(ref_phot_ext[1], int))):
        raise TypeError("Unsupported 'ref_phot_ext' type")
    if isinstance(ref_phot_ext, str):
        ref_phot_ext = (ref_phot_ext, 1)

    if aux_phot_kwd is None:
        aux_phot_kwd = []

    elif isinstance(aux_phot_kwd, str):
        aux_phot_kwd = [aux_phot_kwd.strip().upper()]
        if phot_kwd == aux_phot_kwd:
            raise ValueError("Auxiliary photometric keyword must be different "
                             "from the main photometric keyword 'phot_kwd'.")

    elif hasattr(aux_phot_kwd, '__iter__'):
        if not all([isinstance(phot, str) for phot in aux_phot_kwd]):
            raise TypeError("Argument 'aux_phot_kwd' must be a string, list of "
                        "strings, or None")
        aux_phot_kwd = [phot.strip().upper() for phot in aux_phot_kwd]
        if ref_phot in aux_phot_kwd:
            raise ValueError("Auxiliary photometric keyword(s) must be "
                             "different from the main photometric keyword "
                             "'phot_kwd'.")

    else:
        raise TypeError("Argument 'aux_phot_kwd' must be a string, list of "
                        "strings, or None")

    # read input file list:
    fl = parseat.parse_cs_line(csline=files, default_ext=sci_ext4parse,
                               im_fmode='readonly' if readonly else 'update',
                               clobber=clobber, fnamesOnly=True,
                               doNotOpenDQ=True)

    # check if user supplied file extensions, set them to the sciext,
    # and warn that they will be ignored:
    for f in fl:
        if f.count > 1 or f.fext[0] != sci_ext4parse:
            _mlwarn("WARNING: Extension specifications for file {:s} "
                    "will be ignored. Using all {:s} extensions instead."
                    .format(f.image,  'image-like' if sciext is None else \
                            "{:s}".format(utils.ext2str(sciext,
                                                        default_extver=None))))

    # find the reference PHOTFLAM/PHOTNU:
    flc = fl[:]
    ref_hdu = None
    ref_ext = None
    ref_user = True

    if ref_phot is None:
        ref_user = False
        for f in flc:
            f.convert2ImageRef()

            # get primary hdu:
            pri_hdu = f.image.hdu[0]

            # find all valid extensions:
            if ref_phot_ext is None:
                if sciext == 'PRIMARY':
                    extnum = [0]
                else:
                    extnum = utils.get_ext_list(f.image, sciext)

                is_pri_hdu = [f.image.hdu[ext] is pri_hdu for ext in extnum]

                # if necessary, add primary header to the hdu list:
                if search_primary:
                    try:
                        pri_index = is_pri_hdu.index(True)
                        extnum.insert(0, extnum.pop(pri_index))
                    except ValueError:
                        extnum.insert(0, 0)

            else:
                extnum = [ref_phot_ext]

            for ext in extnum:
                hdu = f.image.hdu[ext]
                if phot_kwd in hdu.header:
                    ref_phot = hdu.header[phot_kwd]
                    ref_ext = ext
                    ref_hdu = hdu
                    break

            if ref_phot is None:
                _mlwarn("WARNING: Could not find specified inverse "
                        "         sensitivity keyword '{:s}'\n"
                        "         in any of the {} extensions of file '{}'.\n"
                        "         This input file will be ignored."
                        .format(phot_kwd, 'image-like' if sciext is None else \
                                "{:s}".format(utils.ext2str(sciext,
                                                            default_extver=None)),
                                os.path.basename(f.image.original_fname)))
                f.release_all_images()
                fl.remove(f)

            else:
                break

    if ref_phot is None:
        raise RuntimeError("Could not find the inverse sensitivity keyword "
                           "'{:s}' in the specified headers of "
                           "the input image(s).\nCannot continue."
                           .format(phot_kwd))

    aux_phot_kwd_list = ','.join(aux_phot_kwd)

    _mlinfo("\nPRIMARY PHOTOMETRIC KEYWORD: {:s}".format(phot_kwd))
    _mlinfo("SECONDARY PHOTOMETRIC KEYWORD(S): {:s}"
              .format(aux_phot_kwd_list if aux_phot_kwd_list else 'None'))
    if ref_user:
        _mlinfo("REFERENCE VALUE PROVIDED BY USER: '{:s}'={}\n"
                .format(phot_kwd, ref_phot))
    else:
        _mlinfo("REFERENCE VALUE FROM FILE: '{:s}[{:s}]'\n"
                .format(os.path.basename(f.image.original_fname),
                          utils.ext2str(ref_ext)))
        _mlinfo("REFERENCE '{:s}' VALUE IS: {}".format(phot_kwd, ref_phot))

    # equalize PHOTFLAM/PHOTNU
    for f in fl:
        # open the file if necessary:
        if f.fnamesOnly:
            _mlinfo("\nProcessing file '{:s}'".format(f.image))
            f.convert2ImageRef()
        else:
            _mlinfo("\nProcessing file '{:s}'".format(f.image.original_fname))

        # first, see if photflam is in the primary header and save this value:
        pri_conv = None
        if search_primary:
            whdu = f.image.hdu[0]
            if phot_kwd in whdu.header:
                _mlinfo("   * Primary header:")
                if whdu is ref_hdu:
                    pri_conv = 1.0
                    _mlinfo("     - '{}' = {} found in the primary header."
                            .format(phot_kwd, whdu.header[phot_kwd]))
                    _mlinfo("     - Data conversion factor based on primary "
                              "header: {}".format(pri_conv))
                else:
                    _mlinfo("     - '{}' found in the primary header."
                            .format(phot_kwd))
                    pri_conv = whdu.header[phot_kwd] / ref_phot
                    _mlinfo("     - Setting {:s} in the primary header to {} "
                              "(old value was {})"
                            .format(phot_kwd, ref_phot, whdu.header[phot_kwd]))
                    _mlinfo("     - Data conversion factor based on primary "
                            "header: {}".format(pri_conv))
                    whdu.header[phot_kwd] = ref_phot

            # correct the "other" photometric keyword, if present:
            if pri_conv is not None and whdu is not ref_hdu:
                for aux_kwd in aux_phot_kwd:
                    if aux_kwd in whdu.header:
                        old_aux_phot = whdu.header[aux_kwd]
                        new_aux_phot = old_aux_phot / pri_conv
                        whdu.header[aux_kwd] = new_aux_phot
                        _mlinfo("     - Setting {:s} in the primary header "
                                "to {} (old value was {})"
                                .format(aux_kwd, new_aux_phot, old_aux_phot))

            # process data and error arrays when 'sciext' was specifically set to
            # 'PRIMARY':
            if sciext == 'PRIMARY' and pri_conv is not None:
                has_data = (hasattr(whdu, 'data') and
                            whdu.data is not None)

                # correct data:
                if has_data:
                    if np.issubdtype(whdu.data.dtype, np.floating):
                        whdu.data *= pri_conv
                        _mlinfo("     - Data have been multiplied by {}"
                                .format(pri_conv))
                    else:
                        _mlwarn("WARNING: Data not converted because it is of "
                                "non-floating point type.")

                # correct error array:
                if errext is not None:
                    eext = (errext, 1)
                    try:
                        whdu = f.image.hdu[eext]
                    except KeyError:
                        _mlwarn("     - WARNING: Error extension {:s} not found."
                                .format(utils.ext2str(eext)))

                        f.release_all_images()
                        continue

                    if hasattr(whdu, 'data') and whdu.data is not None:
                        if np.issubdtype(whdu.data.dtype, np.floating):
                            whdu.data *= pri_conv
                            _mlinfo("     - Error array (ext={}) has been "
                                    "multiplied by {}".format(eext, pri_conv))
                        else:
                            _mlinfo("     - Error array in extension {:s} "
                                    "contains non-floating point data.\n"
                                    "       Skipping this extension"
                                    .format(utils.ext2str(ext)))

                f.release_all_images()
                continue

        # find all valid extensions:
        extnum = utils.get_ext_list(f.image, sciext)

        for ext in extnum:
            whdu = f.image.hdu[ext]
            conv = None

            if whdu is ref_hdu:
                _mlinfo("   * EXT: {} - This is the \"reference\" extension.\n"
                        "          Nothing to do. Skipping this extension..."
                        .format(ext))
                continue

            has_data = (hasattr(whdu, 'data') and
                        whdu.data is not None)

            if has_data and not np.issubdtype(whdu.data.dtype, np.floating):
                _mlinfo("   * EXT: {} contains non-floating point data. "
                        "Skipping this extension".format(ext))

            # find all auxiliary photometric keywords present in the header:
            paux = [aux_kwd for aux_kwd in aux_phot_kwd if aux_kwd \
                    in whdu.header]

            if phot_kwd in whdu.header:
                _mlinfo("   * EXT: {}".format(ext))
                old_phot = whdu.header[phot_kwd]
                conv = old_phot / ref_phot
                _mlinfo("     - Setting {:s} to {} (old value was {})"
                        .format(phot_kwd, ref_phot, old_phot))
                whdu.header[phot_kwd] = ref_phot
                _mlinfo("     - Computed conversion factor for data: {}"
                        .format(conv))

            elif pri_conv is None:
                _mlinfo("   * EXT: {}".format(ext))
                _mlinfo("     - '{:s} not found. Skipping this extension..."
                        .format(phot_kwd))
                continue

            else:
                _mlinfo("   * EXT: {}".format(ext))

                # if paux:
                    # print("ERROR: Primary photometric keyword ('{:s}') is "
                          # "missing but\n       the secondary keywords ('{:s}') "
                          # "are present. This extension cannot be processed."
                          # .format(phot_kwd, ','.join(paux)))
                    # continue

                _mlinfo("     - '{:s} not found. Using conversion factor "
                        "based\n       on the primary header: {}"
                        .format(phot_kwd, pri_conv))
                conv = pri_conv

            # correct the "other" photometric keyword, if present:
            if conv is not None:
                for aux_kwd in paux:
                    old_aux_phot = whdu.header[aux_kwd]
                    new_aux_phot = old_aux_phot / conv
                    whdu.header[aux_kwd] = new_aux_phot
                    _mlinfo("     - Setting {:s} to {} (old value was {})"
                            .format(aux_kwd, new_aux_phot, old_aux_phot))

            # correct data:
            if has_data:
                if conv is None:
                    _mlinfo("   * EXT: {}".format(ext))

                if np.issubdtype(whdu.data.dtype, np.floating):
                    whdu.data *= conv
                    _mlinfo("     - Data have been multiplied by {}"
                            .format(conv))
                else:
                    _mlinfo("WARNING: Non-floating point data. Data cannot "
                            "be re-scaled.")

            # correct error array:
            if errext is not None and isinstance(ext, tuple) and len(ext) == 2:
                eext = (errext, ext[1])
                try:
                    whdu = f.image.hdu[eext]
                except KeyError:
                    continue

                if hasattr(whdu, 'data') and whdu.data is not None:
                    if np.issubdtype(whdu.data.dtype, np.floating):
                        whdu.data *= conv
                        _mlinfo("     - Error array (ext={}) has been "
                                "multiplied by {}".format(eext, conv))
                    else:
                        _mlinfo("     - Error array in extension {:s} "
                                "contains non-floating point data.\n"
                                "       Skipping this extension"
                                .format(utils.ext2str(ext)))

        f.release_all_images()

    _mlinfo("\nDone.")

    if readonly:
        _mlinfo("\nNOTE: '{:s}' was run in READONLY mode\n"
                "       and input image(s)' content WAS NOT MODIFIED."
                .format(__taskname__))

    # close all log file handlers:
    for h in _log.handlers:
        if h is not _sh_log and isinstance(h, logging.FileHandler):
            h.close()
            _log.removeHandler(h)

Response: This function calculates the PHOTFLAM value of the chips in the current tree and stores it in the tree structure.


Instruction:
Implement a function in Python 3 to
manage the PSET - like configobj parameters for a particular task.

Response:
def _managePsets(configobj, section_name, task_name, iparsobj=None, input_dict=None):
    """ Read in parameter values from PSET-like configobj tasks defined for
        source-finding algorithms, and any other PSET-like tasks under this task,
        and merge those values into the input configobj dictionary.
    """
    # Merge all configobj instances into a single object
    configobj[section_name] = {}

    # Load the default full set of configuration parameters for the PSET:
    iparsobj_cfg = teal.load(task_name)

    # Identify optional parameters in input_dicts that are from this
    # PSET and add it to iparsobj:
    if input_dict is not None:
        for key in list(input_dict.keys()):
            if key in iparsobj_cfg:
                if iparsobj is not None and key in iparsobj:
                    raise DuplicateKeyError("Duplicate parameter '{:s}' "
                        "provided for task {:s}".format(key, task_name))
                iparsobj_cfg[key] = input_dict[key]
                del input_dict[key]

    if iparsobj is not None:
        iparsobj_cfg.update(iparsobj)

    del iparsobj_cfg['_task_name_']

    # merge these parameters into full set
    configobj[section_name].merge(iparsobj_cfg)


Instruction:
Can you write a function in Python 3 where it
allows the user to edit the imagefindpars configObj in a TEAL GUI

Response:
def edit_imagefindpars():
    """ Allows the user to edit the imagefindpars configObj in a TEAL GUI
        """
    teal.teal(imagefindpars.__taskname__, returnAs=None,
              autoClose=True, loadOnly=False, canExecute=False)


Instruction:
Create a Python 3 function to
allow the user to edit the refimagefindpars configObj in a TEAL GUI

Response:
def edit_refimagefindpars():
    """ Allows the user to edit the refimagefindpars configObj in a TEAL GUI
        """
    teal.teal(refimagefindpars.__taskname__, returnAs=None,
              autoClose=True, loadOnly=False, canExecute=False)


Instruction:
Create a Python 3 function to
print information about the specified local repository to STDOUT.

Response:
def print_rev_id(localRepoPath):
    """prints information about the specified local repository to STDOUT. Expected method of execution: command-line or
    shell script call

    Parameters
    ----------
    localRepoPath: string
        Local repository path.

    Returns
    =======
    Nothing as such. subroutine will exit with a state of 0 if everything ran OK, and a value of '111' if
    something went wrong.
    """
    start_path = os.getcwd()
    try:
        log.info("Local repository path: {}".format(localRepoPath))
        os.chdir(localRepoPath)
        log.info("\n== Remote URL")
        os.system('git remote -v')

        # log.info("\n== Remote Branches")
        # os.system("git branch -r")

        log.info("\n== Local Branches")
        os.system("git branch")

        log.info("\n== Most Recent Commit")
        os.system("git log |head -1")
        rv = 0
    except:
        rv = 111
        log.info("WARNING! get_git_rev_info.print_rev_id() encountered a problem and cannot continue.")
    finally:
        os.chdir(start_path)
        if rv != 0:
            sys.exit(rv)


Instruction:
Given the following Python 3 function, write the documentation
def get_rev_id(localRepoPath):
    start_path = os.getcwd()
    try:
        os.chdir(localRepoPath)

        instream = os.popen("git --no-pager log --max-count=1 | head -1")
        for streamline in instream.readlines():
            streamline = streamline.strip()
            if streamline.startswith("commit "):
                rv = streamline.replace("commit ","")
            else:
                raise
    except:
        rv = "FAILURE: git revision info not found"
    finally:
        os.chdir(start_path)

    return(rv)

Response: returns the current full git revision id of the specified local repository


Instruction:
Explain what the following Python 3 code does
def update(input,refdir="jref$",local=None,interactive=False,wcsupdate=True):
    print('UPDATENPOL Version',__version__+'('+__version_date__+')')
    # expand (as needed) the list of input files
    files,fcol = parseinput.parseinput(input)

    if not interactive:
        # expand reference directory name (if necessary) to
        # interpret IRAF or environment variable names
        rdir = fu.osfn(refdir)
        ngeofiles,ngcol = parseinput.parseinput(os.path.join(rdir,'*npl.fits'))
        # Find D2IMFILE in refdir for updating input file header as well
        d2ifiles,d2col = parseinput.parseinput(os.path.join(rdir,"*d2i.fits"))

    # Now, build a matched list of input files and DGEOFILE reference files
    # to use for selecting the appropriate new reference file from the
    # refdir directory.
    for f in files:
        print('Updating: ',f)
        fdir = os.path.split(f)[0]
        # Open each file...
        fimg = fits.open(f, mode='update', memmap=False)
        phdr = fimg['PRIMARY'].header
        fdet = phdr['detector']
        # get header of DGEOFILE
        dfile = phdr.get('DGEOFILE','')
        if dfile in ['N/A','',' ',None]:
            npolname = ''
        else:
            dhdr = fits.getheader(fu.osfn(dfile), memmap=False)
            if not interactive:
                # search all new NPOLFILEs for one that matches current DGEOFILE config
                npol = find_npolfile(ngeofiles,fdet,[phdr['filter1'],phdr['filter2']])
            else:
                if sys.version_info[0] >= 3:
                    npol = input("Enter name of NPOLFILE for %s:"%f)
                else:
                    npol = raw_input("Enter name of NPOLFILE for %s:"%f)
                if npol == "": npol = None

            if npol is None:
                errstr =  "No valid NPOLFILE found in "+rdir+" for detector="+fdet+"\n"
                errstr += " filters = "+phdr['filter1']+","+phdr['filter2']
                raise ValueError(errstr)

            npolname = os.path.split(npol)[1]
            if local:
                npolname = os.path.join(fdir,npolname)
                # clobber any previous copies of this reference file
                if os.path.exists(npolname): os.remove(npolname)
                shutil.copy(npol,npolname)
            else:
                if '$' in refdir:
                    npolname = refdir+npolname
                else:
                    npolname = os.path.join(refdir,npolname)
        phdr.set('NPOLFILE', value=npolname,
                 comment="Non-polynomial corrections in Paper IV LUT",
                 after='DGEOFILE')

        # Now find correct D2IFILE
        if not interactive:
            d2i = find_d2ifile(d2ifiles,fdet)
        else:
            if sys.version_info[0] >= 3:
                d2i = input("Enter name of D2IMFILE for %s:"%f)
            else:
                d2i = raw_input("Enter name of D2IMFILE for %s:"%f)
            if d2i == "": d2i = None

        if d2i is None:
            print('=============\nWARNING:')
            print("    No valid D2IMFILE found in "+rdir+" for detector ="+fdet)
            print("    D2IMFILE correction will not be applied.")
            print('=============\n')
            d2iname = ""
        else:
            d2iname = os.path.split(d2i)[1]
            if local:
                # Copy D2IMFILE to local data directory alongside input file as well
                d2iname = os.path.join(fdir,d2iname)
                # clobber any previous copies of this reference file
                if os.path.exists(d2iname): os.remove(d2iname)
                shutil.copy(d2i,d2iname)
            else:
                if '$' in refdir:
                    d2iname = refdir+d2iname
                else:
                    d2iname = os.path.join(refdir,d2iname)

        phdr.set('D2IMFILE', value=d2iname,
                 comment="Column correction table",
                 after='DGEOFILE')

        # Close this input file header and go on to the next
        fimg.close()

        if wcsupdate:
            updatewcs.updatewcs(f)

Response: Updates the headers of the input file with the new reference files.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def find_d2ifile(flist,detector):
    d2ifile = None
    for f in flist:
        fdet = fits.getval(f, 'detector', memmap=False)
        if fdet == detector:
            d2ifile = f
    return d2ifile

Response: Search a list of files for one that matches the detector specified.


Instruction:
Can you generate the documentation for the following Python 3 function
def find_npolfile(flist,detector,filters):
    npolfile = None
    for f in flist:
        fdet = fits.getval(f, 'detector', memmap=False)
        if fdet == detector:
            filt1 = fits.getval(f, 'filter1', memmap=False)
            filt2 = fits.getval(f, 'filter2', memmap=False)
            fdate = fits.getval(f, 'date', memmap=False)
            if filt1 == 'ANY' or \
             (filt1 == filters[0] and filt2 == filters[1]):
                npolfile = f
    return npolfile

Response:
Search a list of files for one that matches the configuration
        of detector and filters used.


Instruction:
Write a Python 3 script to
run Teal interface for running this code.

Response:
def run(configobj=None,editpars=False):
    """ Teal interface for running this code.
    """

    if configobj is None:
        configobj =teal.teal(__taskname__,loadOnly=(not editpars))

    update(configobj['input'],configobj['refdir'],
        local=configobj['local'],interactive=configobj['interactive'],
        wcsupdate=configobj['wcsupdate'])


Instruction:
Can you generate the documentation for the following Python 3 function
def reset_dq_bits(input,bits,extver=None,extname='dq'):
    # Interpret bits value
    bits = interpret_bit_flags(bits)

    flist, fcol = parseinput.parseinput(input)
    for filename in flist:
        # open input file in write mode to allow updating the DQ array in-place
        p = fits.open(filename, mode='update', memmap=False)

        # Identify the DQ array to be updated
        # If no extver is specified, build a list of all DQ arrays in the file
        if extver is None:
            extver = []
            for hdu in p:
                # find only those extensions which match the input extname
                # using case-insensitive name comparisons for 'extname'
                if 'extver' in hdu.header and \
                   hdu.header['extname'].lower() == extname.lower():
                    extver.append(int(hdu.header['extver']))
        else:
            # Otherwise, insure that input extver values are a list
            if not isinstance(extver, list): extver = [extver]

        # for each DQ array identified in the file...
        for extn in extver:
            dqarr = p[extname,extn].data
            dqdtype = dqarr.dtype
            # reset the desired bits
            p[extname,extn].data = (dqarr & ~bits).astype(dqdtype) # preserve original dtype
            log.info('Reset bit values of %s to a value of 0 in %s[%s,%s]' %
                     (bits, filename, extname, extn))
        # close the file with the updated DQ array(s)
        p.close()

Response: This function resets the bits in the integer array of all the DQ arrays in a FITS file.


Instruction:
How would you code a function in Python 3 to
replace pixels in input that have a value of pixvalue with a value given by newvalue.

Response:
def replace(input, **pars):
    """ Replace pixels in `input` that have a value of `pixvalue`
        with a value given by `newvalue`.

    """
    pixvalue = pars.get('pixvalue', np.nan)
    if pixvalue is None: pixvalue = np.nan # insure that None == np.nan

    newvalue = pars.get('newvalue', 0.0)
    ext = pars.get('ext',None)
    if ext in ['',' ','None',None]:
        ext = None

    files = parseinput.parseinput(input)[0]

    for f in files:
        fimg = fits.open(f, mode='update', memmap=False)

        if ext is None:
            # replace pixels in ALL extensions
            extn = [i for i in fimg]
        else:
            if type(ext) == type([]):
                extn = [fimg[e] for e in ext]
            else:
                extn = [fimg[ext]]

        for e in extn:
            if e.data is not None and e.is_image: # ignore empty Primary HDUs
                print("Converting {}[{},{}] value of {} to {}".format(
                        f,e.name,e.ver,pixvalue,newvalue))
                if np.isnan(pixvalue):
                    e.data[np.isnan(e.data)] = newvalue
                else:
                    e.data[np.where(e.data == pixvalue)] = newvalue

        fimg.close()


Instruction:
Can you tell what is the following Python 3 function doing
def tweakback(drzfile, input=None,  origwcs = None,
                newname = None, wcsname = None,
                extname='SCI', force=False, verbose=False):
    """
    Apply WCS solution recorded in drizzled file to distorted input images
    (``_flt.fits`` files) used to create the drizzled file.  This task relies on
    the original WCS and updated WCS to be recorded in the drizzled image's
    header as the last 2 alternate WCSs.

    Parameters
    ----------
    drzfile : str (Default = '')
        filename of undistorted image which contains the new WCS
        and WCS prior to being updated

    newname : str (Default = None)
        Value of ``WCSNAME`` to be used to label the updated solution in the
        output (eq., ``_flt.fits``) files.  If left blank or None, it will
        default to using the current ``WCSNAME`` value from the input drzfile.

    input : str (Default = '')
        filenames of distorted images to be updated using new WCS
        from 'drzfile'.  These can be provided either as an ``@-file``,
        a comma-separated list of filenames or using wildcards.

        .. note:: A blank value will indicate that the task should derive the
           filenames from the 'drzfile' itself, if possible. The filenames will be
           derived from the ``D*DATA`` keywords written out by
           ``AstroDrizzle``. If they can not be found, the task will quit.

    origwcs : str (Default = None)
        Value of ``WCSNAME`` keyword prior to the drzfile image being updated
        by ``TweakReg``.  If left blank or None, it will default to using the
        second to last ``WCSNAME*`` keyword value found in the header.

    wcsname : str (Default = None)
        Value of WCSNAME for updated solution written out by ``TweakReg`` as
        specified by the `wcsname` parameter from ``TweakReg``.  If this is
        left blank or `None`, it will default to the current ``WCSNAME``
        value from the input drzfile.

    extname : str (Default = 'SCI')
        Name of extension in `input` files to be updated with new WCS

    force : bool  (Default = False)
        This parameters specified whether or not to force an update of the WCS
        even though WCS already exists with this solution or `wcsname`?

    verbose : bool (Default = False)
        This parameter specifies whether or not to print out additional
        messages during processing.

    Notes
    -----
    The algorithm used by this function is based on linearization of
    the exact compound operator that converts input image coordinates
    to the coordinates (in the input image) that would result in
    alignment with the new drizzled image WCS.

    If no input distorted files are specified as input, this task will attempt
    to generate the list of filenames from the drizzled input file's own
    header.

    EXAMPLES
    --------
    An image named ``acswfc_mos2_drz.fits`` was created from 4 images using
    astrodrizzle. This drizzled image was then aligned to another image using
    tweakreg and the header was updated using the ``WCSNAME`` = ``TWEAK_DRZ``.
    The new WCS can then be used to update each of the 4 images that were
    combined to make up this drizzled image using:

    >>> from drizzlepac import tweakback
    >>> tweakback.tweakback('acswfc_mos2_drz.fits')

    If the same WCS should be applied to a specific set of images, those images
    can be updated using:

    >>> tweakback.tweakback('acswfc_mos2_drz.fits',
    ...                     input='img_mos2a_flt.fits,img_mos2e_flt.fits')

    See Also
    --------
    stwcs.wcsutil.altwcs: Alternate WCS implementation

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

    # Interpret input list/string into list of filename(s)
    fltfiles = parseinput.parseinput(input)[0]

    if fltfiles is None or len(fltfiles) == 0:
        # try to extract the filenames from the drizzled file's header
        fltfiles = extract_input_filenames(drzfile)
        if fltfiles is None:
            print('*'*60)
            print('*')
            print('* ERROR:')
            print('*    No input filenames found! ')
            print('*    Please specify "fltfiles" or insure that input drizzled')
            print('*    image contains D*DATA keywords. ')
            print('*')
            print('*'*60)
            raise ValueError

    if not isinstance(fltfiles,list):
        fltfiles = [fltfiles]

    sciext = determine_extnum(drzfile, extname='SCI')
    scihdr = fits.getheader(drzfile, ext=sciext, memmap=False)

    ### Step 1: Read in updated and original WCS solutions
    # determine keys for all alternate WCS solutions in drizzled image header
    wkeys = wcsutil.altwcs.wcskeys(drzfile, ext=sciext)
    wnames = wcsutil.altwcs.wcsnames(drzfile, ext=sciext)
    if not util.is_blank(newname):
        final_name = newname
    else:
        final_name = wnames[wkeys[-1]]

    # Read in HSTWCS objects for final,updated WCS and previous WCS from
    # from drizzled image header
    # The final solution also serves as reference WCS when using updatehdr
    if not util.is_blank(wcsname):
        for k in wnames:
            if wnames[k] == wcsname:
                wcskey = k
                break
    else:
        wcskey = wkeys[-1]
    final_wcs = wcsutil.HSTWCS(drzfile, ext=sciext, wcskey=wkeys[-1])

    if not util.is_blank(origwcs):
        for k in wnames:
            if wnames[k] == origwcs:
                orig_wcskey = k
                orig_wcsname = origwcs
                break
    else:
        orig_wcsname,orig_wcskey = determine_orig_wcsname(scihdr,wnames,wkeys)

    orig_wcs = wcsutil.HSTWCS(drzfile,ext=sciext,wcskey=orig_wcskey)

    # read in RMS values reported for new solution
    crderr1kw = 'CRDER1'+wkeys[-1]
    crderr2kw = 'CRDER2'+wkeys[-1]

    if crderr1kw in scihdr:
        crderr1 = fits.getval(drzfile, crderr1kw, ext=sciext, memmap=False)
    else:
        crderr1 = 0.0

    if crderr2kw in scihdr:
        crderr2 = fits.getval(drzfile, crderr2kw, ext=sciext, memmap=False)
    else:
        crderr2 = 0.0
    del scihdr

    ### Step 2: Apply solution to input file headers
    for fname in fltfiles:
        logstr = "....Updating header for {:s}...".format(fname)
        if verbose:
            print("\n{:s}\n".format(logstr))
        else:
            log.info(logstr)

        # reset header WCS keywords to original (OPUS generated) values
        imhdulist = fits.open(fname, mode='update', memmap=False)
        extlist = get_ext_list(imhdulist, extname='SCI')
        if not extlist:
            extlist = [0]

        # insure that input PRIMARY WCS has been archived before overwriting
        # with new solution
        wcsutil.altwcs.archiveWCS(imhdulist, extlist, reusekey=True)

        # Process MEF images...
        for ext in extlist:
            logstr = "Processing {:s}[{:s}]".format(imhdulist.filename(),
                                                    ext2str(ext))
            if verbose:
                print("\n{:s}\n".format(logstr))
            else:
                log.info(logstr)
            chip_wcs = wcsutil.HSTWCS(imhdulist, ext=ext)

            update_chip_wcs(chip_wcs, orig_wcs, final_wcs,
                            xrms=crderr1, yrms = crderr2)

            # Update FITS file with newly updated WCS for this chip
            extnum = imhdulist.index(imhdulist[ext])
            updatehdr.update_wcs(imhdulist, extnum, chip_wcs,
                                 wcsname=final_name, reusename=False,
                                 verbose=verbose)

        imhdulist.close()

Response: This function takes input drizzled file and returns a list of all the relevant attributes for the new WCS and original WCSs.


Instruction:
Implement a function in Python 3 to
generate a list of filenames from a drizzled image s header

Response:
def extract_input_filenames(drzfile):
    """
    Generate a list of filenames from a drizzled image's header
    """
    data_kws = fits.getval(drzfile, 'd*data', ext=0, memmap=False)
    if len(data_kws) == 0:
        return None
    fnames = []
    for kw in data_kws.cards:
        f = kw.value.split('[')[0]
        if f not in fnames:
            fnames.append(f)

    return fnames


Instruction:
Can you implement a function in Python 3 that
determines the name of the original unmodified WCS solution

Response:
def determine_orig_wcsname(header, wnames, wkeys):
    """
    Determine the name of the original, unmodified WCS solution
    """
    orig_wcsname = None
    orig_key = None
    if orig_wcsname is None:
        for k,w in wnames.items():
            if w[:4] == 'IDC_':
                orig_wcsname = w
                orig_key = k
                break
    if orig_wcsname is None:
        # No IDC_ wcsname found... revert to second to last if available
        if len(wnames) > 1:
            orig_key = wkeys[-2]
            orig_wcsname = wnames[orig_key]
    return orig_wcsname,orig_key


Instruction:
Can you generate a brief explanation for the following Python 3 code
def parse_atfile_cat(input):
    with open(input[1:]) as f:
        catlist = []
        catdict = {}
        for line in f.readlines():
            if line[0] == '#' or not line.strip():
                continue

            lspl = line.split()
            if len(lspl) > 1:
                catdict[lspl[0]] = lspl[1:]
                catlist.append(lspl[1:])
            else:
                catdict[lspl[0]] = None
                catlist.append(None)

    return catlist, catdict

Response: Parse the list of catalog filenames specified as part of the input at - file


Instruction:
Write a Python 3 function for
functioning to parse RA and Dec input values and turn them into decimal degrees

Response:
def parse_skypos(ra, dec):
    """
    Function to parse RA and Dec input values and turn them into decimal
    degrees

    Input formats could be:
        ["nn","nn","nn.nn"]
        "nn nn nn.nnn"
        "nn:nn:nn.nn"
        "nnH nnM nn.nnS" or "nnD nnM nn.nnS"
        nn.nnnnnnnn
        "nn.nnnnnnn"

    """
    rval = make_val_float(ra)
    dval = make_val_float(dec)
    if rval is None:
        rval, dval = radec_hmstodd(ra, dec)
    return rval, dval


Instruction:
Can you generate a brief explanation for the following Python 3 code
def radec_hmstodd(ra, dec):
    hmstrans = string.maketrans(string.ascii_letters,
                                ' ' * len(string.ascii_letters))

    if isinstance(ra, list):
        rastr = ':'.join(ra)
    elif isinstance(ra, float):
        rastr = None
        pos_ra = ra
    elif ra.find(':') < 0:
        # convert any non-numeric characters to spaces
        # (we already know the units)
        rastr = ra.translate(hmstrans).strip()
        rastr = rastr.replace('  ', ' ')
        # convert 'nn nn nn.nn' to final 'nn:nn:nn.nn' string
        rastr = rastr.replace(' ', ':')
    else:
        rastr = ra

    if isinstance(dec, list):
        decstr = ':'.join(dec)
    elif isinstance(dec, float):
        decstr = None
        pos_dec = dec
    elif dec.find(':') < 0:
        decstr = dec.translate(hmstrans).strip()
        decstr = decstr.replace('  ', ' ')
        decstr = decstr.replace(' ', ':')
    else:
        decstr = dec

    if rastr is None:
        pos = (pos_ra, pos_dec)
    else:
        pos_coord = coords.SkyCoord(rastr + ' ' + decstr,
                                    unit=(u.hourangle, u.deg))
        pos = (pos_coord.ra.deg, pos_coord.dec.deg)
    return pos

Response: Function to convert HMS values into decimal degrees.


Instruction:
Write a Python 3 script to
read in exclusion definitions from file named by exclusions and return a list of positions and distances.

Response:
def parse_exclusions(exclusions):
    """ Read in exclusion definitions from file named by 'exclusions'
        and return a list of positions and distances
    """
    fname = fileutil.osfn(exclusions)
    if os.path.exists(fname):
        with open(fname) as f:
            flines = f.readlines()
    else:
        print('No valid exclusions file "', fname, '" could be found!')
        print('Skipping application of exclusions files to source catalogs.')
        return None

    # Parse out lines which can be interpreted as positions and distances
    exclusion_list = []
    units = None
    for line in flines:
        if line[0] == '#' or 'global' in line[:6]:
            continue
        # Only interpret the part of the line prior to the comment
        # if a comment has been attached to the line
        if '#' in line:
            line = line.split('#')[0].rstrip()

        if units is None:
            units = 'pixels'
            if line[:3] in ['fk4', 'fk5', 'sky']:
                units = 'sky'
            if line[:5] in ['image', 'physi', 'pixel']:
                units = 'pixels'
            continue

        if 'circle(' in line:
            nline = line.replace('circle(', '')
            nline = nline.replace(')', '')
            nline = nline.replace('"', '')
            vals = nline.split(',')
            if ':' in vals[0]:
                posval = vals[0] + ' ' + vals[1]
            else:
                posval = (float(vals[0]), float(vals[1]))
        else:
            # Try to interpret unformatted line
            if ',' in line:
                split_tok = ','
            else:
                split_tok = ' '
            vals = line.split(split_tok)
            if len(vals) == 3:
                if ':' in vals[0]:
                    posval = vals[0] + ' ' + vals[1]
                else:
                    posval = (float(vals[0]), float(vals[1]))
            else:
                continue
        exclusion_list.append(
            {'pos': posval, 'distance': float(vals[2]), 'units': units}
        )
    return exclusion_list


Instruction:
Create a Python 3 function for
functioning which reads specified columns from either FITS or ASCII files and returns numpy array or arrays of columns

Response:
def readcols(infile, cols=None):
    """ Function which reads specified columns from either FITS tables or
        ASCII files

        This function reads in the columns specified by the user into numpy
        arrays regardless of the format of the input table (ASCII or FITS
        table).

        Parameters
        ----------
        infile : string
            Filename of the input file
        cols   : string or list of strings
            Columns to be read into arrays

        Returns
        -------
        outarr : array
            Numpy array or arrays of columns from the table

    """
    if _is_str_none(infile) is None:
        return None

    if infile.endswith('.fits'):
        outarr = read_FITS_cols(infile, cols=cols)
    else:
        outarr = read_ASCII_cols(infile, cols=cols)
    return outarr


Instruction:
Can you write a function in Python 3 where it
reads columns from FITS table

Response:
def read_FITS_cols(infile, cols=None):  # noqa: N802
    """ Read columns from FITS table """
    with fits.open(infile, memmap=False) as ftab:
        extnum = 0
        extfound = False
        for extn in ftab:
            if 'tfields' in extn.header:
                extfound = True
                break
            extnum += 1

        if not extfound:
            print('ERROR: No catalog table found in ', infile)
            raise ValueError

        # Now, read columns from the table in this extension if no column names
        # were provided by user, simply read in all columns from table
        if _is_str_none(cols[0]) is None:
            cols = ftab[extnum].data.names

        # Define the output
        outarr = [ftab[extnum].data.field(c) for c in cols]

    return outarr


Instruction:
Write a Python 3 script to
interpret input ASCII file to return arrays for specified columns.

Response:
def read_ASCII_cols(infile, cols=[1, 2, 3]):  # noqa: N802
    """ Interpret input ASCII file to return arrays for specified columns.

        Notes
        -----
        The specification of the columns should be expected to have lists for
        each 'column', with all columns in each list combined into a single
        entry.

        For example::

            cols = ['1,2,3','4,5,6',7]

        where '1,2,3' represent the X/RA values, '4,5,6' represent the Y/Dec
        values and 7 represents the flux value for a total of 3 requested
        columns of data to be returned.

        Returns
        -------
        outarr : list of arrays
            The return value will be a list of numpy arrays, one for each
            'column'.
    """
    # build dictionary representing format of each row
    # Format of dictionary: {'colname':col_number,...}
    # This provides the mapping between column name and column number
    coldict = {}
    with open(infile, 'r') as f:
        flines = f.readlines()

    for l in flines:  # interpret each line from catalog file
        if l[0].lstrip() == '#' or l.lstrip() == '':
            continue
        else:
            # convert first row of data into column definitions using indices
            coldict = {str(i + 1): i for i, _ in enumerate(l.split())}
            break

    numcols = len(cols)
    outarr = [[] for _ in range(numcols)]
    convert_radec = False

    # Now, map specified columns to columns in file and populate output arrays
    for l in flines:  # interpret each line from catalog file
        l = l.strip()
        lspl = l.split()
        # skip blank lines, comment lines, or lines with
        # fewer columns than requested by user
        if not l or len(lspl) < numcols or l[0] == '#' or "INDEF" in l:
            continue

        # For each 'column' requested by user, pull data from row
        for c, i in zip(cols, list(range(numcols))):
            cnames = parse_colname(c)
            if len(cnames) > 1:
                # interpret multi-column specification as one value
                outval = ''
                for cn in cnames:
                    cnum = coldict[cn]
                    cval = lspl[cnum]
                    outval += cval + ' '
                outarr[i].append(outval)
                convert_radec = True
            else:
                # pull single value from row for this column
                cnum = coldict[cnames[0]]
                if isfloat(lspl[cnum]):
                    cval = float(lspl[cnum])
                else:
                    cval = lspl[cnum]
                    # Check for multi-column values given as "nn:nn:nn.s"
                    if ':' in cval:
                        cval = cval.replace(':', ' ')
                        convert_radec = True
                outarr[i].append(cval)

    # convert multi-column RA/Dec specifications
    if convert_radec:
        outra = []
        outdec = []
        for ra, dec in zip(outarr[0], outarr[1]):
            radd, decdd = radec_hmstodd(ra, dec)
            outra.append(radd)
            outdec.append(decdd)
        outarr[0] = outra
        outarr[1] = outdec

    # convert all lists to numpy arrays
    for c in range(len(outarr)):
        outarr[c] = np.array(outarr[c])

    return outarr


Instruction:
Implement a Python 3 function for
writing out a shiftfile for a given list of input Image class objects

Response:
def write_shiftfile(image_list, filename, outwcs='tweak_wcs.fits'):
    """ Write out a shiftfile for a given list of input Image class objects
    """
    rows = ''
    nrows = 0
    for img in image_list:
        row = img.get_shiftfile_row()
        if row is not None:
            rows += row
            nrows += 1
    if nrows == 0:  # If there are no fits to report, do not write out a file
        return

    # write out reference WCS now
    if os.path.exists(outwcs):
        os.remove(outwcs)
    p = fits.HDUList()
    p.append(fits.PrimaryHDU())
    p.append(createWcsHDU(image_list[0].refWCS))
    p.writeto(outwcs)

    # Write out shiftfile to go with reference WCS
    with open(filename, 'w') as f:
        f.write('# frame: output\n')
        f.write('# refimage: %s[wcs]\n' % outwcs)
        f.write('# form: delta\n')
        f.write('# units: pixels\n')
        f.write(rows)
    print('Writing out shiftfile :', filename)


Instruction:
Make a summary of the following Python 3 code
def createWcsHDU(wcs):  # noqa: N802
    header = wcs.to_header()

    header['EXTNAME'] = 'WCS'
    header['EXTVER'] = 1

    # Now, update original image size information
    header['NPIX1'] = (wcs.pixel_shape[0], "Length of array axis 1")
    header['NPIX2'] = (wcs.pixel_shape[1], "Length of array axis 2")
    header['PIXVALUE'] = (0.0, "values of pixels in array")

    if hasattr(wcs, 'orientat'):
        orientat = wcs.orientat
    else:
        # find orientat from CD or PC matrix
        if wcs.wcs.has_cd():
            cd12 = wcs.wcs.cd[0][1]
            cd22 = wcs.wcs.cd[1][1]
        elif wcs.wcs.has_pc():
            cd12 = wcs.wcs.cdelt[0] * wcs.wcs.pc[0][1]
            cd22 = wcs.wcs.cdelt[1] * wcs.wcs.pc[1][1]
        else:
            raise ValueError("Invalid WCS: WCS does not contain neither "
                             "a CD nor a PC matrix.")
        orientat = np.rad2deg(np.arctan2(cd12, cd22))
    header['ORIENTAT'] = (orientat, "position angle of "
                          "image y axis (deg. e of n)")

    return fits.ImageHDU(None, header)

Response: Create a WCS HDU that can be used to populate a reference WCS HDU.


Instruction:
How would you implement a function in Python 3 that
generates the 2D Gaussian function for the given size nx and ny.

Response:
def gauss_array(nx, ny=None, fwhm=1.0, sigma_x=None, sigma_y=None,
                zero_norm=False):
    """ Computes the 2D Gaussian with size nx*ny.

        Parameters
        ----------
        nx : int
        ny : int [Default: None]
            Size of output array for the generated Gaussian. If ny == None,
            output will be an array nx X nx pixels.

        fwhm : float [Default: 1.0]
            Full-width, half-maximum of the Gaussian to be generated

        sigma_x : float [Default:  None]
        sigma_y : float [Default:  None]
            Sigma_x and sigma_y are the stddev of the Gaussian functions.

        zero_norm : bool [Default:  False]
            The kernel will be normalized to a sum of 1 when True.

        Returns
        -------
        gauss_arr : array
            A numpy array with the generated gaussian function

    """

    if ny is None:
        ny = nx

    if sigma_x is None:
        if fwhm is None:
            print('A value for either "fwhm" or "sigma_x" needs to be '
                  'specified!')
            raise ValueError
        else:
            # Convert input FWHM into sigma
            sigma_x = fwhm / (2 * np.sqrt(2 * np.log(2)))

    if sigma_y is None:
        sigma_y = sigma_x

    xradius = nx // 2
    yradius = ny // 2

    # Create grids of distance from center in X and Y
    xarr = np.abs(np.arange(-xradius, xradius + 1))
    yarr = np.abs(np.arange(-yradius, yradius + 1))
    hnx = gauss(xarr, sigma_x)
    hny = gauss(yarr, sigma_y)
    hny = hny.reshape((ny, 1))
    h = hnx * hny

    # Normalize gaussian kernel to a sum of 1
    h = h / np.abs(h).sum()
    if zero_norm:
        h -= h.mean()

    return h


Instruction:
Explain what the following Python 3 code does
def gauss(x, sigma):
    return (np.exp(-np.power(x, 2) / (2 * np.power(sigma, 2))) /
            (sigma * np.sqrt(2 * np.pi)))

Response: Compute 1 - D value of gaussian at position x relative to center.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def make_vector_plot(coordfile, columns=[1, 2, 3, 4], data=None,
                     figure_id=None, title=None, axes=None, every=1,
                     labelsize=8, ylimit=None, limit=None, xlower=None,
                     ylower=None, output=None, headl=4, headw=3,
                     xsh=0.0, ysh=0.0, fit=None, scale=1.0, vector=True,
                     textscale=5, append=False, linfit=False, rms=True,
                     plotname=None):
    """ Convert a XYXYMATCH file into a vector plot or set of residuals plots.

        This function provides a single interface for generating either a
        vector plot of residuals or a set of 4 plots showing residuals.
        The data being plotted can also be adjusted for a linear fit
        on-the-fly.

        Parameters
        ----------
        coordfile : string
            Name of file with matched sets of coordinates. This input file can
            be a file compatible for use with IRAF's geomap.
        columns : list [Default: [0,1,2,3]]
            Column numbers for the X,Y positions from each image
        data : list of arrays
            If specified, this can be used to input matched data directly
        title : string
            Title to be used for the generated plot
        axes : list
            List of X and Y min/max values to customize the plot axes
        every : int [Default: 1]
            Slice value for the data to be plotted
        limit : float
            Radial offset limit for selecting which sources are included in
            the plot
        labelsize : int [Default: 8] or str
            Font size to use for tick labels, either in font points or as a
            string understood by tick_params().
        ylimit : float
            Limit to use for Y range of plots.
        xlower : float
        ylower : float
            Limit in X and/or Y offset for selecting which sources are included
            in the plot
        output : string
            Filename of output file for generated plot
        headl : int [Default: 4]
            Length of arrow head to be used in vector plot
        headw : int [Default: 3]
            Width of arrow head to be used in vector plot
        xsh : float
        ysh : float
            Shift in X and Y from linear fit to be applied to source positions
            from the first image
        scale : float
            Scale from linear fit to be applied to source positions from the
            first image
        fit : array
            Array of linear coefficients for rotation (and scale?) in X and Y
            from a linear fit to be applied to source positions from the
            first image
        vector : bool [Default: True]
            Specifies whether or not to generate a vector plot. If False, task
            will generate a set of 4 residuals plots instead
        textscale : int [Default: 5]
            Scale factor for text used for labelling the generated plot
        append : bool [Default: False]
            If True, will overplot new plot on any pre-existing plot
        linfit : bool [Default: False]
            If True, a linear fit to the residuals will be generated and
            added to the generated residuals plots
        rms : bool [Default: True]
            Specifies whether or not to report the RMS of the residuals as a
            label on the generated plot(s).
        plotname : str [Default: None]
            Write out plot to a file with this name if specified.

    """
    from matplotlib import pyplot as plt

    if data is None:
        data = readcols(coordfile, cols=columns)

    xy1x = data[0]
    xy1y = data[1]
    xy2x = data[2]
    xy2y = data[3]

    numpts = xy1x.shape[0]
    if fit is not None:
        xy1x, xy1y = apply_db_fit(data, fit, xsh=xsh, ysh=ysh)
        dx = xy2x - xy1x
        dy = xy2y - xy1y
    else:
        dx = xy2x - xy1x - xsh
        dy = xy2y - xy1y - ysh
    # apply scaling factor to deltas
    dx *= scale
    dy *= scale

    print('Total # points: {:d}'.format(len(dx)))
    if limit is not None:
        indx = np.sqrt(dx**2 + dy**2) <= limit
        dx = dx[indx].copy()
        dy = dy[indx].copy()
        xy1x = xy1x[indx].copy()
        xy1y = xy1y[indx].copy()

    if xlower is not None:
        xindx = np.abs(dx) >= xlower
        dx = dx[xindx].copy()
        dy = dy[xindx].copy()
        xy1x = xy1x[xindx].copy()
        xy1y = xy1y[xindx].copy()
    print('# of points after clipping: {:d}'.format(len(dx)))

    dr = np.sqrt(dx**2 + dy**2)
    max_vector = dr.max()

    if output is not None:
        write_xy_file(output, [xy1x, xy1y, dx, dy])

    fig = plt.figure(num=figure_id)
    if not append:
        plt.clf()

    if vector:
        dxs = imagestats.ImageStats(dx.astype(np.float32))
        dys = imagestats.ImageStats(dy.astype(np.float32))
        minx = xy1x.min()
        maxx = xy1x.max()
        miny = xy1y.min()
        maxy = xy1y.max()
        plt_xrange = maxx - minx
        plt_yrange = maxy - miny

        qplot = plt.quiver(xy1x[::every], xy1y[::every], dx[::every],
                           dy[::every], units='y', headwidth=headw,
                           headlength=headl)
        key_dx = 0.01 * plt_xrange
        key_dy = 0.005 * plt_yrange * textscale
        maxvec = max_vector / 2.
        key_len = round(maxvec + 0.005, 2)

        plt.xlabel('DX: %.4f to %.4f +/- %.4f' % (dxs.min, dxs.max,
                                                  dxs.stddev))
        plt.ylabel('DY: %.4f to %.4f +/- %.4f' % (dys.min, dys.max,
                                                  dys.stddev))
        plt.title(r"$Vector\ plot\ of\ %d/%d\ residuals:\ %s$" %
                  (xy1x.shape[0], numpts, title))
        plt.quiverkey(qplot, minx + key_dx, miny - key_dy, key_len,
                      "%0.2f pixels" % (key_len),
                      coordinates='data', labelpos='E', labelcolor='Maroon',
                      color='Maroon')
    else:
        plot_defs = [[xy1x, dx, "X (pixels)", "DX (pixels)"],
                     [xy1y, dx, "Y (pixels)", "DX (pixels)"],
                     [xy1x, dy, "X (pixels)", "DY (pixels)"],
                     [xy1y, dy, "Y (pixels)", "DY (pixels)"]]
        if axes is None:
            # Compute a global set of axis limits for all plots
            minx = min(xy1x.min(), xy1y.min())
            maxx = max(xy1x.max(), xy1y.max())
            miny = min(dx.min(), dy.min())
            maxy = max(dx.max(), dy.max())
        else:
            minx = axes[0][0]
            maxx = axes[0][1]
            miny = axes[1][0]
            maxy = axes[1][1]

        if ylimit is not None:
            miny = -ylimit
            maxy = ylimit

        rms_labelled = False
        if title is None:
            fig.suptitle("Residuals [%d/%d]" % (xy1x.shape[0], numpts),
                         ha='center', fontsize=labelsize + 6)
        else:
            # This definition of the title supports math symbols in the title
            fig.suptitle(r"$" + title + "$", ha='center',
                         fontsize=labelsize + 6)

        for pnum, p in enumerate(plot_defs):
            pn = pnum + 1
            ax = fig.add_subplot(2, 2, pn)
            plt.plot(
                p[0], p[1], 'b.',
                label='RMS(X) = %.4f, RMS(Y) = %.4f' % (dx.std(), dy.std())
            )
            lx = [int((p[0].min() - 500) / 500) * 500,
                  int((p[0].max() + 500) / 500) * 500]
            plt.plot(lx, [0.0, 0.0], 'k', linewidth=3)
            plt.axis([minx, maxx, miny, maxy])
            if rms and not rms_labelled:
                leg_handles, leg_labels = ax.get_legend_handles_labels()
                fig.legend(leg_handles, leg_labels, loc='center left',
                           fontsize='small', frameon=False,
                           bbox_to_anchor=(0.33, 0.51), borderaxespad=0)
                rms_labelled = True

            ax.tick_params(labelsize=labelsize)

            # Fine-tune figure; hide x ticks for top plots and y ticks for
            # right plots
            if pn <= 2:
                plt.setp(ax.get_xticklabels(), visible=False)
            else:
                ax.set_xlabel(plot_defs[pnum][2])

            if pn % 2 == 0:
                plt.setp(ax.get_yticklabels(), visible=False)
            else:
                ax.set_ylabel(plot_defs[pnum][3])

            if linfit:
                lxr = int((lx[-1] - lx[0]) / 100)
                lyr = int((p[1].max() - p[1].min()) / 100)
                a = np.vstack([p[0], np.ones(len(p[0]))]).T
                m, c = np.linalg.lstsq(a, p[1])[0]
                yr = [m * lx[0] + c, lx[-1] * m + c]
                plt.plot([lx[0], lx[-1]], yr, 'r')
                plt.text(
                    lx[0] + lxr, p[1].max() + lyr,
                    "%0.5g*x + %0.5g [%0.5g,%0.5g]" % (m, c, yr[0], yr[1]),
                    color='r'
                )

    plt.draw()

    if plotname:
        suffix = plotname[-4:]
        if '.' not in suffix:
            output += '.png'
            format = 'png'
        else:
            if suffix[1:] in ['png', 'pdf', 'ps', 'eps', 'svg']:
                format = suffix[1:]
        plt.savefig(plotname, format=format)

Response: This function converts a XYXYMATCH file into a vector plot or set of 4 plots.


Instruction:
Implement a Python 3 function for
finding the center of the peak of offsets

Response:
def find_xy_peak(img, center=None, sigma=3.0):
    """ Find the center of the peak of offsets """
    # find level of noise in histogram
    istats = imagestats.ImageStats(img.astype(np.float32), nclip=1,
                                   fields='stddev,mode,mean,max,min')
    if istats.stddev == 0.0:
        istats = imagestats.ImageStats(img.astype(np.float32),
                                       fields='stddev,mode,mean,max,min')
    imgsum = img.sum()

    # clip out all values below mean+3*sigma from histogram
    imgc = img[:, :].copy()
    imgc[imgc < istats.mode + istats.stddev * sigma] = 0.0
    # identify position of peak
    yp0, xp0 = np.where(imgc == imgc.max())

    # Perform bounds checking on slice from img
    ymin = max(0, int(yp0[0]) - 3)
    ymax = min(img.shape[0], int(yp0[0]) + 4)
    xmin = max(0, int(xp0[0]) - 3)
    xmax = min(img.shape[1], int(xp0[0]) + 4)
    # take sum of at most a 7x7 pixel box around peak
    xp_slice = (slice(ymin, ymax),
                slice(xmin, xmax))
    yp, xp = ndimage.measurements.center_of_mass(img[xp_slice])
    if np.isnan(xp) or np.isnan(yp):
        xp = 0.0
        yp = 0.0
        flux = 0.0
        zpqual = None
    else:
        xp += xp_slice[1].start
        yp += xp_slice[0].start

        # compute S/N criteria for this peak: flux/sqrt(mean of rest of array)
        flux = imgc[xp_slice].sum()
        delta_size = float(img.size - imgc[xp_slice].size)
        if delta_size == 0:
            delta_size = 1
        delta_flux = float(imgsum - flux)
        if flux > imgc[xp_slice].max():
            delta_flux = flux - imgc[xp_slice].max()
        else:
            delta_flux = flux
        zpqual = flux / np.sqrt(delta_flux / delta_size)
        if np.isnan(zpqual) or np.isinf(zpqual):
            zpqual = None

        if center is not None:
            xp -= center[0]
            yp -= center[1]
        flux = imgc[xp_slice].max()

    del imgc
    return xp, yp, flux, zpqual


Instruction:
Write a Python 3 script to
plot a 2d histogram.

Response:
def plot_zeropoint(pars):
    """ Plot 2d histogram.

    Pars will be a dictionary containing:
        data, figure_id, vmax, title_str, xp,yp, searchrad
    """
    from matplotlib import pyplot as plt

    xp = pars['xp']
    yp = pars['yp']
    searchrad = int(pars['searchrad'] + 0.5)

    plt.figure(num=pars['figure_id'])
    plt.clf()

    if pars['interactive']:
        plt.ion()
    else:
        plt.ioff()

    plt.imshow(pars['data'], vmin=0, vmax=pars['vmax'],
               interpolation='nearest')
    plt.viridis()
    plt.colorbar()
    plt.title(pars['title_str'])
    plt.plot(xp + searchrad, yp + searchrad, color='red', marker='+',
             markersize=24)
    plt.plot(searchrad, searchrad, color='yellow', marker='+', markersize=120)
    plt.text(searchrad, searchrad, "Offset=0,0", verticalalignment='bottom',
             color='yellow')
    plt.xlabel("Offset in X (pixels)")
    plt.ylabel("Offset in Y (pixels)")
    if pars['interactive']:
        plt.show()

    if pars['plotname']:
        suffix = pars['plotname'][-4:]
        output = pars['plotname']
        if '.' not in suffix:
            output += '.png'
            format = 'png'
        else:
            if suffix[1:] in ['png', 'pdf', 'ps', 'eps', 'svg']:
                format = suffix[1:]
        plt.savefig(output, format=format)


Instruction:
Write a Python 3 function that can
build ZP matrix for a single image and a single ref xy position.

Response:
def build_xy_zeropoint(imgxy, refxy, searchrad=3.0, histplot=False,
                       figure_id=1, plotname=None, interactive=True):
    """ Create a matrix which contains the delta between each XY position and
        each UV position.
    """
    print('Computing initial guess for X and Y shifts...')

    # run C function to create ZP matrix
    zpmat = cdriz.arrxyzero(imgxy.astype(np.float32), refxy.astype(np.float32),
                            searchrad)

    xp, yp, flux, zpqual = find_xy_peak(zpmat, center=(searchrad, searchrad))
    if zpqual is not None:
        print('Found initial X and Y shifts of ', xp, yp)
        print('    with significance of ', zpqual, 'and ', flux, ' matches')
    else:
        # try with a lower sigma to detect a peak in a sparse set of sources
        xp, yp, flux, zpqual = find_xy_peak(
            zpmat, center=(searchrad, searchrad), sigma=1.0
        )
        if zpqual:
            print('Found initial X and Y shifts of ', xp, yp)
            print('    with significance of ', zpqual, 'and ',
                  flux, ' matches')
        else:
            print('!' * 80)
            print('!')
            print('! WARNING: No valid shift found within a search radius of ',
                  searchrad, ' pixels.')
            print('!')
            print('!' * 80)

    if histplot:
        zpstd = flux // 5
        if zpstd < 10:
            zpstd = 10
        if zpqual is None:
            zpstd = 10

        title_str = ("Histogram of offsets: Peak has %d matches at "
                     "(%0.4g, %0.4g)" % (flux, xp, yp))

        plot_pars = {'data': zpmat, 'figure_id': figure_id, 'vmax': zpstd,
                     'xp': xp, 'yp': yp, 'searchrad': searchrad,
                     'title_str': title_str, 'plotname': plotname,
                     'interactive': interactive}

        plot_zeropoint(plot_pars)

    return xp, yp, flux, zpqual


Instruction:
How would you implement a function in Python 3 that
builds a grid of positions starting at X Y given by start and ending at X Y given by end.

Response:
def build_pos_grid(start, end, nstep, mesh=False):
    """
    Return a grid of positions starting at X,Y given by 'start', and ending
    at X,Y given by 'end'. The grid will be completely filled in X and Y by
    every 'step' interval.
    """
    # Build X and Y arrays
    dx = end[0] - start[0]
    if dx < 0:
        nstart = end
        end = start
        start = nstart
    dx = -dx
    stepx = dx / nstep
    # Perform linear fit to find exact line that connects start and end
    xarr = np.arange(start[0], end[0] + stepx / 2.0, stepx)
    yarr = np.interp(xarr, [start[0], end[0]], [start[1], end[1]])

    # create grid of positions
    if mesh:
        xa, ya = np.meshgrid(xarr, yarr)
        xarr = xa.ravel()
        yarr = ya.ravel()

    return xarr, yarr


Instruction:
Can you generate the documentation for the following Python 3 function
def find_DQ_extension(self):
        dqfile = None
        # Look for additional file with DQ array, primarily for WFPC2 data

        indx = self._filename.find('.fits')

        if indx > 3:
            suffix = self._filename[indx-4:indx]
            dqfile = self._filename.replace(suffix[:3],'_c1')

        elif indx < 0 and len(self._filename) > 3 and \
             self._filename[-4] == os.extsep and \
             self._filename[-1].lower() == 'h':

            # assume we've got a GEIS file
            dqfile  = self._filename[:-2]+'1'+self._filename[-1]
            hdulist = readgeis.readgeis(dqfile)
            prih    = hdulist[0].header
            if 'FILETYPE' in prih:
                dq_suffix = prih['FILETYPE'].strip().upper()
            else:
                # assume extension name is 'SDQ' for WFPC2 GEIS files
                dq_suffix = 'SDQ'
            hdulist.close()
            return dqfile,dq_suffix

        else:
            raise ValueError("Input file {} does not appear to be neither " \
                        "a FITS file nor a GEIS file.".format(self._filename))

        if os.path.exists(dqfile):
            dq_suffix = fits.getval(dqfile, "EXTNAME", ext=1, memmap=False)
        else:
            dq_suffix = "SCI"

        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.