Instruction:
Can you generate the documentation for the following Python 3 function
def xy2rd(input,x=None,y=None,coords=None, coordfile=None,colnames=None,separator=None,
            hms=True, precision=6,output=None,verbose=True):
    """ Primary interface to perform coordinate transformations from
        pixel to sky coordinates using STWCS and full distortion models
        read from the input image header.
    """
    single_coord = False
    # Only use value provided in `coords` if nothing has been specified for coordfile
    if coords is not None and coordfile is None:
        coordfile = coords
        warnings.simplefilter('always',DeprecationWarning)
        warnings.warn("Please update calling code to pass in `coordfile` instead of `coords`.",
            category=DeprecationWarning)
        warnings.simplefilter('default',DeprecationWarning)

    if coordfile is not None:
        if colnames in blank_list:
            colnames = ['c1','c2']
        # Determine columns which contain pixel positions
        cols = util.parse_colnames(colnames,coordfile)
        # read in columns from input coordinates file
        xyvals = np.loadtxt(coordfile,usecols=cols,delimiter=separator)
        if xyvals.ndim == 1:  # only 1 entry in coordfile
            xlist = [xyvals[0].copy()]
            ylist = [xyvals[1].copy()]
        else:
            xlist = xyvals[:,0].copy()
            ylist = xyvals[:,1].copy()
        del xyvals
    else:
        if isinstance(x, np.ndarray):
            xlist = x.tolist()
            ylist = y.tolist()
        elif not isinstance(x,list):
            xlist = [x]
            ylist = [y]
            single_coord = True
        else:
            xlist = x
            ylist = y

    # start by reading in WCS+distortion info for input image
    inwcs = wcsutil.HSTWCS(input)
    if inwcs.wcs.is_unity():
        print("####\nNo valid WCS found in {}.\n  Results may be invalid.\n####\n".format(input))

    # Now, convert pixel coordinates into sky coordinates
    dra,ddec = inwcs.all_pix2world(xlist,ylist,1)

    # convert to HH:MM:SS.S format, if specified
    if hms:
        ra,dec = wcs_functions.ddtohms(dra,ddec,precision=precision)
        rastr = ra
        decstr = dec
    else:
        # add formatting based on precision here...
        rastr = []
        decstr = []
        fmt = "%."+repr(precision)+"f"
        for r,d in zip(dra,ddec):
            rastr.append(fmt%r)
            decstr.append(fmt%d)

        ra = dra
        dec = ddec

    if verbose or (not verbose and util.is_blank(output)):
        print('# Coordinate transformations for ',input)
        print('# X      Y         RA             Dec\n')
        for x,y,r,d in zip(xlist,ylist,rastr,decstr):
            print("%.4f  %.4f    %s  %s"%(x,y,r,d))

    # Create output file, if specified
    if output:
        f = open(output,mode='w')
        f.write("# Coordinates converted from %s\n"%input)
        for r,d in zip(rastr,decstr):
            f.write('%s    %s\n'%(r,d))
        f.close()
        print('Wrote out results to: ',output)

    if single_coord:
        ra = ra[0]
        dec = dec[0]

    return ra,dec

Response: This function takes a input image file x y coordinates and returns a list of sky coordinates.


Instruction:
Can you generate the documentation for the following Python 3 function
def run(configObj, wcsmap=None):

    # Insure all output filenames specified have .fits extensions
    if configObj['outdata'][-5:] != '.fits': configObj['outdata'] += '.fits'
    if not util.is_blank(configObj['outweight']) and configObj['outweight'][-5:] != '.fits': configObj['outweight'] += '.fits'
    if not util.is_blank(configObj['outcontext']) and configObj['outcontext'][-5:] != '.fits': configObj['outcontext'] += '.fits'

    # Keep track of any files we need to open
    in_sci_handle = None
    in_wht_handle = None
    out_sci_handle = None
    out_wht_handle = None
    out_con_handle = None

    _wcskey = configObj['wcskey']
    if util.is_blank(_wcskey):
        _wcskey = ' '

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

    # Open the SCI (and WHT?) image
    # read file to get science array
    insci = get_data(configObj['input'])
    expin = fileutil.getKeyword(configObj['input'],scale_pars['expkey'])
    in_sci_phdr = fits.getheader(fileutil.parseFilename(configObj['input'])[0], memmap=False)

    # we need to read in the input WCS
    input_wcs = stwcs.wcsutil.HSTWCS(configObj['input'],wcskey=_wcskey)

    if not util.is_blank(configObj['inweight']):
        inwht = get_data(configObj['inweight']).astype(np.float32)
    else:
        # Generate a default weight map of all good pixels
        inwht = np.ones(insci.shape,dtype=insci.dtype)

    output_exists = False
    outname = fileutil.osfn(fileutil.parseFilename(configObj['outdata'])[0])
    if os.path.exists(outname):
        output_exists = True
    # Output was specified as a filename, so open it in 'update' mode
    outsci = get_data(configObj['outdata'])

    if output_exists:
        # we also need to read in the output WCS from pre-existing output
        output_wcs = stwcs.wcsutil.HSTWCS(configObj['outdata'])

        out_sci_hdr = fits.getheader(outname, memmap=False)
        outexptime = out_sci_hdr['DRIZEXPT']
        if 'ndrizim' in out_sci_hdr:
            uniqid = out_sci_hdr['ndrizim']+1
        else:
            uniqid = 1

    else:  # otherwise, define the output WCS either from user pars or refimage
        if util.is_blank(configObj['User WCS Parameters']['refimage']):
            # Define a WCS based on user provided WCS values
            # NOTE:
            #   All parameters must be specified, not just one or a few
            if not util.is_blank(user_wcs_pars['outscale']):
                output_wcs = wcs_functions.build_hstwcs(
                    user_wcs_pars['raref'], user_wcs_pars['decref'],
                    user_wcs_pars['xrefpix'], user_wcs_pars['yrefpix'],
                    user_wcs_pars['outnx'], user_wcs_pars['outny'],
                    user_wcs_pars['outscale'], user_wcs_pars['orient'] )
            else:
                # Define default WCS based on input image
                applydist = True
                if input_wcs.sip is None or input_wcs.instrument=='DEFAULT':
                    applydist = False
                output_wcs = stwcs.distortion.utils.output_wcs([input_wcs],undistort=applydist)
        else:
            refimage = configObj['User WCS Parameters']['refimage']
            refroot,extroot = fileutil.parseFilename(refimage)
            if extroot is None:
                fimg = fits.open(refroot, memmap=False)
                for i,extn in enumerate(fimg):
                    if 'CRVAL1' in extn.header: # Key on CRVAL1 for valid WCS
                        refwcs = wcsutil.HSTWCS('{}[{}]'.format(refroot,i))
                        if refwcs.wcs.has_cd():
                            extroot = i
                            break
                fimg.close()
                # try to find extension with valid WCS
                refimage = "{}[{}]".format(refroot,extroot)
            # Define the output WCS based on a user specified reference image WCS
            output_wcs = stwcs.wcsutil.HSTWCS(refimage)
        # Initialize values used for combining results
        outexptime = 0.0
        uniqid = 1

    # Set up the output data array and insure that the units for that array is 'cps'
    if outsci is None:
        # Define a default blank array based on definition of output_wcs
        outsci = np.empty(output_wcs.array_shape, dtype=np.float32)
        outsci.fill(np.nan)
    else:
        # Convert array to units of 'cps', if needed
        if outexptime != 0.0:
            np.divide(outsci, outexptime, outsci)
        outsci = outsci.astype(np.float32)

    # Now update output exposure time for additional input file
    outexptime += expin

    outwht = None
    if not util.is_blank(configObj['outweight']):
        outwht = get_data(configObj['outweight'])

    if outwht is None:
        outwht = np.zeros(output_wcs.array_shape, dtype=np.float32)
    else:
        outwht = outwht.astype(np.float32)

    outcon = None
    keep_con = False

    if not util.is_blank(configObj['outcontext']):
        outcon = get_data(configObj['outcontext'])
        keep_con = True
        if outcon is None:
            outcon = np.zeros((1,) + output_wcs.array_shape, dtype=np.int32)
        else:
            outcon = outcon.astype(np.int32)
            planeid = int((uniqid - 1)/ 32)

            # Add a new plane to the context image if planeid overflows
            while outcon.shape[0] <= planeid:
                plane = np.zeros_like(outcon[0])
                outcon = np.append(outcon, plane, axis=0)

    # Interpret wt_scl parameter
    if configObj['wt_scl'] == 'exptime':
        wt_scl = expin
    elif configObj['wt_scl'] == 'expsq':
        wt_scl = expin*expin
    else:
        wt_scl = float(configObj['wt_scl'])

    # Interpret coeffs parameter to determine whether to apply coeffs or not
    undistort = True
    if not configObj['coeffs'] or input_wcs.sip is None or input_wcs.instrument == 'DEFAULT':
        undistort = False
    # turn off use of coefficients if undistort is False (coeffs == False)
    if not undistort:
        input_wcs.sip = None
        input_wcs.cpdis1 = None
        input_wcs.cpdis2 = None
        input_wcs.det2im = None

    wcslin = distortion.utils.output_wcs([input_wcs],undistort=undistort)

    # Perform actual drizzling now...
    _vers = do_driz(insci, input_wcs, inwht,
            output_wcs, outsci, outwht, outcon,
            expin, scale_pars['in_units'],
            wt_scl, wcslin_pscale=wcslin.pscale ,uniqid=uniqid,
            pixfrac=configObj['pixfrac'], kernel=configObj['kernel'],
            fillval=scale_pars['fillval'], stepsize=configObj['stepsize'],
            wcsmap=None)

    out_sci_handle,outextn = create_output(configObj['outdata'])
    if not output_exists:
        # Also, define default header based on input image Primary header
        out_sci_handle[outextn].header = in_sci_phdr.copy()

    # Update header of output image with exptime used to scale the output data
    # if out_units is not counts, this will simply be a value of 1.0
    # the keyword 'exptime' will always contain the total exposure time
    # of all input image regardless of the output units
    out_sci_handle[outextn].header['EXPTIME'] = outexptime

    # create CTYPE strings
    ctype1 = input_wcs.wcs.ctype[0]
    ctype2 = input_wcs.wcs.ctype[1]
    if ctype1.find('-SIP'): ctype1 = ctype1.replace('-SIP','')
    if ctype2.find('-SIP'): ctype2 = ctype2.replace('-SIP','')

    # Update header with WCS keywords
    out_sci_handle[outextn].header['ORIENTAT'] = output_wcs.orientat
    out_sci_handle[outextn].header['CD1_1'] = output_wcs.wcs.cd[0][0]
    out_sci_handle[outextn].header['CD1_2'] = output_wcs.wcs.cd[0][1]
    out_sci_handle[outextn].header['CD2_1'] = output_wcs.wcs.cd[1][0]
    out_sci_handle[outextn].header['CD2_2'] = output_wcs.wcs.cd[1][1]
    out_sci_handle[outextn].header['CRVAL1'] = output_wcs.wcs.crval[0]
    out_sci_handle[outextn].header['CRVAL2'] = output_wcs.wcs.crval[1]
    out_sci_handle[outextn].header['CRPIX1'] = output_wcs.wcs.crpix[0]
    out_sci_handle[outextn].header['CRPIX2'] = output_wcs.wcs.crpix[1]
    out_sci_handle[outextn].header['CTYPE1'] = ctype1
    out_sci_handle[outextn].header['CTYPE2'] = ctype2
    out_sci_handle[outextn].header['VAFACTOR'] = 1.0

    if scale_pars['out_units'] == 'counts':
        np.multiply(outsci, outexptime, outsci)
        out_sci_handle[outextn].header['DRIZEXPT'] = outexptime

    else:
        out_sci_handle[outextn].header['DRIZEXPT'] = 1.0

    # Update header keyword NDRIZIM to keep track of how many images have
    # been combined in this product so far
    out_sci_handle[outextn].header['NDRIZIM'] = uniqid

    #define keywords to be written out to product header
    drizdict = outputimage.DRIZ_KEYWORDS.copy()

    # Update drizdict with current values
    drizdict['VER']['value'] = _vers[:44]
    drizdict['DATA']['value'] = configObj['input'][:64]
    drizdict['DEXP']['value'] = expin
    drizdict['OUDA']['value'] = configObj['outdata'][:64]
    drizdict['OUWE']['value'] = configObj['outweight'][:64]
    drizdict['OUCO']['value'] = configObj['outcontext'][:64]
    drizdict['MASK']['value'] = configObj['inweight'][:64]
    drizdict['WTSC']['value'] = wt_scl
    drizdict['KERN']['value'] = configObj['kernel']
    drizdict['PIXF']['value'] = configObj['pixfrac']
    drizdict['OUUN']['value'] = scale_pars['out_units']
    drizdict['FVAL']['value'] = scale_pars['fillval']
    drizdict['WKEY']['value'] = configObj['wcskey']
    outputimage.writeDrizKeywords(out_sci_handle[outextn].header,uniqid,drizdict)

    # add output array to output file
    out_sci_handle[outextn].data = outsci
    out_sci_handle.close()

    if not util.is_blank(configObj['outweight']):
        out_wht_handle,outwhtext = create_output(configObj['outweight'])
        out_wht_handle[outwhtext].header = out_sci_handle[outextn].header.copy()
        out_wht_handle[outwhtext].data = outwht
        out_wht_handle.close()

    if keep_con:
        out_con_handle,outconext = create_output(configObj['outcontext'])
        out_con_handle[outconext].data = outcon
        out_con_handle.close()

Response: This function runs the wdrizzle from TEAL or Python command - line.


Instruction:
Write a Python 3 script to
merge static or CR mask with DQ array on - the - fly here.

Response:
def mergeDQarray(maskname,dqarr):
    """ Merge static or CR mask with mask created from DQ array on-the-fly here.
    """
    maskarr = None
    if maskname is not None:
        if isinstance(maskname, str):
            # working with file on disk (default case)
            if os.path.exists(maskname):
                mask = fileutil.openImage(maskname, memmap=False)
                maskarr = mask[0].data.astype(np.bool)
                mask.close()
        else:
            if isinstance(maskname, fits.HDUList):
                # working with a virtual input file
                maskarr = maskname[0].data.astype(np.bool)
            else:
                maskarr = maskname.data.astype(np.bool)

        if maskarr is not None:
            # merge array with dqarr now
            np.bitwise_and(dqarr,maskarr,dqarr)


Instruction:
Make a summary of the following Python 3 code
def _setDefaults(configObj={}):

    paramDict={"build":True,
              "single":True,
              "stepsize":10,
              "in_units":"cps",
              "wt_scl":1.,
              "pixfrac":1.,
              "kernel":"square",
              "fillval":999.,
              "maskval": None,
              "rot":0.,
              "scale":1.,
              "xsh":0.,
              "ysh":0.,
              "blotnx":2048,
              "blotny":2048,
              "outnx":4096,
              "outny":4096,
              "data":None,
              "driz_separate":True,
              "driz_combine":False}

    if(len(configObj) !=0):
        for key in configObj.keys():
            paramDict[key]=configObj[key]

    return paramDict

Response: set up the default parameters to run drizzle on the next iteration


Instruction:
Can you tell what is the following Python 3 function doing
def interpret_maskval(paramDict):
    # interpret user specified final_maskval value to use for initializing
    # output SCI array...
    if 'maskval' not in paramDict:
        return 0
    maskval = paramDict['maskval']
    if maskval is None:
        maskval = np.nan
    else:
        maskval = float(maskval) # just to be clear and absolutely sure...
    return maskval

Response: Interpret the final_maskval value in the paramDict.


Instruction:
Can you create a Python 3 function that
performs drizzle operation on input to create output. The input parameters originally was a list of dictionaries, one for each input, that matches the primary parameters for an ``IRAF`` `drizzle` task. This method would then loop over all the entries in the list and run `drizzle` for each entry. Parameters required for input in paramDict: build,single,units,wt_scl,pixfrac,kernel,fillval, rot,scale,xsh,ysh,blotnx,blotny,outnx,outny,data

Response:
def run_driz(imageObjectList,output_wcs,paramDict,single,build,wcsmap=None):
    """ Perform drizzle operation on input to create output.
    The input parameters originally was a list
    of dictionaries, one for each input, that matches the
    primary parameters for an ``IRAF`` `drizzle` task.

    This method would then loop over all the entries in the
    list and run `drizzle` for each entry.

    Parameters required for input in paramDict:
        build,single,units,wt_scl,pixfrac,kernel,fillval,
        rot,scale,xsh,ysh,blotnx,blotny,outnx,outny,data
    """
    # Insure that input imageObject is a list
    if not isinstance(imageObjectList, list):
        imageObjectList = [imageObjectList]

    #
    # Setup the versions info dictionary for output to PRIMARY header
    # The keys will be used as the name reported in the header, as-is
    #
    _versions = {'AstroDrizzle':__version__,
                 'PyFITS':util.__fits_version__,
                 'Numpy':util.__numpy_version__}

    # Set sub-sampling rate for drizzling
    #stepsize = 2.0
    log.info('  **Using sub-sampling value of %s for kernel %s' %
             (paramDict['stepsize'], paramDict['kernel']))

    maskval = interpret_maskval(paramDict)

    outwcs = copy.deepcopy(output_wcs)

    # Check for existance of output file.
    if (not single and build and
        fileutil.findFile(imageObjectList[0].outputNames['outFinal'])):
        log.info('Removing previous output product...')
        os.remove(imageObjectList[0].outputNames['outFinal'])

    # print out parameters being used for drizzling
    log.info("Running Drizzle to create output frame with WCS of: ")
    output_wcs.printwcs()

    # Will we be running in parallel?
    pool_size = util.get_pool_size(paramDict.get('num_cores'), len(imageObjectList))
    will_parallel = single and pool_size > 1
    if will_parallel:
        log.info('Executing %d parallel workers' % pool_size)
    else:
        if single: # not yet an option for final drizzle, msg would confuse
            log.info('Executing serially')

    # Set parameters for each input and run drizzle on it here.
    #
    # Perform drizzling...

    numctx = 0
    for img in imageObjectList:
        numctx += img._nmembers
    _numctx = {'all':numctx}

    #            if single:
    # Determine how many chips make up each single image
    for img in imageObjectList:
        for chip in img.returnAllChips(extname=img.scienceExt):
            plsingle = chip.outputNames['outSingle']
            if plsingle in _numctx: _numctx[plsingle] += 1
            else: _numctx[plsingle] = 1

    # Compute how many planes will be needed for the context image.
    _nplanes = int((_numctx['all']-1) / 32) + 1
    # For single drizzling or when context is turned off,
    # minimize to 1 plane only...
    if single or imageObjectList[0][1].outputNames['outContext'] in [None,'',' ']:
        _nplanes = 1

    #
    # An image buffer needs to be setup for converting the input
    # arrays (sci and wht) from FITS format to native format
    # with respect to byteorder and byteswapping.
    # This buffer should be reused for each input if possible.
    #
    _outsci = _outwht = _outctx = _hdrlist = None
    if (not single) or \
       (single and (not will_parallel) and (not imageObjectList[0].inmemory)):
        # Note there are four cases/combinations for single drizzle alone here:
        # (not-inmem, serial), (not-inmem, parallel), (inmem, serial), (inmem, parallel)
        _outsci=np.empty(output_wcs.array_shape, dtype=np.float32)
        _outsci.fill(maskval)
        _outwht=np.zeros(output_wcs.array_shape, dtype=np.float32)
        # initialize context to 3-D array but only pass appropriate plane to drizzle as needed
        _outctx=np.zeros((_nplanes,) + output_wcs.array_shape, dtype=np.int32)
        _hdrlist = []

    # Keep track of how many chips have been processed
    # For single case, this will determine when to close
    # one product and open the next.
    _chipIdx = 0

    # Remember the name of the 1st image that goes into this particular product
    # Insure that the header reports the proper values for the start of the
    # exposure time used to make this; in particular, TIME-OBS and DATE-OBS.
    template = None

    #
    # Work on each image
    #
    subprocs = []
    for img in imageObjectList:

        chiplist = img.returnAllChips(extname=img.scienceExt)

        # How many inputs should go into this product?
        num_in_prod = _numctx['all']
        if single:
            num_in_prod = _numctx[chiplist[0].outputNames['outSingle']]

        # The name of the 1st image
        fnames = []
        for chip in chiplist:
            fnames.append(chip.outputNames['data'])

        if _chipIdx == 0:
            template = fnames
        else:
            template.extend(fnames)

        # Work each image, possibly in parallel
        if will_parallel:
            # use multiprocessing.Manager only if in parallel and in memory
            if img.inmemory:
                manager = multiprocessing.Manager()
                dproxy = manager.dict(img.virtualOutputs) # copy & wrap it in proxy
                img.virtualOutputs = dproxy

            # parallelize run_driz_img (currently for separate drizzle only)
            p = multiprocessing.Process(target=run_driz_img,
                name='adrizzle.run_driz_img()', # for err msgs
                args=(img,chiplist,output_wcs,outwcs,template,paramDict,
                      single,num_in_prod,build,_versions,_numctx,_nplanes,
                      _chipIdx,None,None,None,None,wcsmap))
            subprocs.append(p)
        else:
            # serial run_driz_img run (either separate drizzle or final drizzle)
            run_driz_img(img,chiplist,output_wcs,outwcs,template,paramDict,
                         single,num_in_prod,build,_versions,_numctx,_nplanes,
                         _chipIdx,_outsci,_outwht,_outctx,_hdrlist,wcsmap)

        # Increment/reset master chip counter
        _chipIdx += len(chiplist)
        if _chipIdx == num_in_prod:
            _chipIdx = 0

    # do the join if we spawned tasks
    if will_parallel:
        mputil.launch_and_wait(subprocs, pool_size) # blocks till all done

    del _outsci,_outwht,_outctx,_hdrlist


Instruction:
Can you generate a brief explanation for the following Python 3 code
def run_driz_img(img,chiplist,output_wcs,outwcs,template,paramDict,single,
                 num_in_prod,build,_versions,_numctx,_nplanes,chipIdxCopy,
                 _outsci,_outwht,_outctx,_hdrlist,wcsmap):
    """ Perform the drizzle operation on a single image.
    This is separated out from :py:func:`run_driz` so as to keep together
    the entirety of the code which is inside the loop over
    images.  See the :py:func:`run_driz` code for more documentation.
    """
    maskval = interpret_maskval(paramDict)

    # Check for unintialized inputs
    here = _outsci is None and _outwht is None and _outctx is None
    if _outsci is None:
        _outsci=np.empty(output_wcs.array_shape, dtype=np.float32)
        if single:
            _outsci.fill(0)
        else:
            _outsci.fill(maskval)
    if _outwht is None:
        _outwht=np.zeros(output_wcs.array_shape, dtype=np.float32)
    if _outctx is None:
        _outctx = np.zeros((_nplanes,) + output_wcs.array_shape, dtype=np.int32)
    if _hdrlist is None:
        _hdrlist = []

    # Work on each chip - note that they share access to the arrays above
    for chip in chiplist:
        # See if we will be writing out data
        doWrite = chipIdxCopy == num_in_prod-1

#       debuglog('#chips='+str(chipIdxCopy)+', num_in_prod='+\
#                 str(num_in_prod)+', single='+str(single)+', write='+\
#                 str(doWrite)+', here='+str(here))

        # run_driz_chip
        run_driz_chip(img,chip,output_wcs,outwcs,template,paramDict,
                      single,doWrite,build,_versions,_numctx,_nplanes,
                      chipIdxCopy,_outsci,_outwht,_outctx,_hdrlist,wcsmap)

        # Increment chip counter (also done outside of this function)
        chipIdxCopy += 1

    #
    # Reset for next output image...
    #
    if here:
        del _outsci,_outwht,_outctx,_hdrlist
    elif single:
        np.multiply(_outsci,0.,_outsci)
        np.multiply(_outwht,0.,_outwht)
        np.multiply(_outctx,0,_outctx)
        # this was "_hdrlist=[]", but we need to preserve the var ptr itself
        while len(_hdrlist)>0: _hdrlist.pop()

Response: This function is used to run drizzle on a single image.


Instruction:
Given the following Python 3 function, write the documentation
def run_driz_chip(img,chip,output_wcs,outwcs,template,paramDict,single,
                  doWrite,build,_versions,_numctx,_nplanes,_numchips,
                  _outsci,_outwht,_outctx,_hdrlist,wcsmap):
    """ Perform the drizzle operation on a single chip.
    This is separated out from `run_driz_img` so as to keep together
    the entirety of the code which is inside the loop over
    chips.  See the `run_driz` code for more documentation.
    """
    global time_pre_all, time_driz_all, time_post_all, time_write_all

    epoch = time.time()

    # Look for sky-subtracted product
    if os.path.exists(chip.outputNames['outSky']):
        chipextn = '['+chip.header['extname']+','+str(chip.header['extver'])+']'
        _expname = chip.outputNames['outSky']+chipextn
    else:
        # If sky-subtracted product does not exist, use regular input
        _expname = chip.outputNames['data']
    log.info('-Drizzle input: %s' % _expname)

    # Open the SCI image
    _handle = fileutil.openImage(_expname, mode='readonly', memmap=False)
    _sciext = _handle[chip.header['extname'],chip.header['extver']]

    # Apply sky subtraction and unit conversion to input array
    if chip.computedSky is None:
        _insci = _sciext.data
    else:
        log.info("Applying sky value of %0.6f to %s"%(chip.computedSky,_expname))
        _insci = _sciext.data - chip.computedSky
    # If input SCI image is still integer format (RAW files)
    # transform it to float32 for all subsequent operations
    # needed for numpy >=1.12.x
    if np.issubdtype(_insci[0,0],np.int16):
        _insci = _insci.astype(np.float32)

    _insci *= chip._effGain

    # Set additional parameters needed by 'drizzle'
    _in_units = chip.in_units.lower()
    if _in_units == 'cps':
        _expin = 1.0
    else:
        _expin = chip._exptime

    ####
    #
    # Put the units keyword handling in the imageObject class
    #
    ####
    # Determine output value of BUNITS
    # and make sure it is not specified as 'ergs/cm...'
    _bunit = chip._bunit

    _bindx = _bunit.find('/')

    if paramDict['units'] == 'cps':
        # If BUNIT value does not specify count rate already...
        if _bindx < 1:
            # ... append '/SEC' to value
            _bunit += '/S'
        else:
            # reset _bunit here to None so it does not
            #    overwrite what is already in header
            _bunit = None
    else:
        if _bindx > 0:
            # remove '/S'
            _bunit = _bunit[:_bindx]
        else:
            # reset _bunit here to None so it does not
            #    overwrite what is already in header
            _bunit = None

    _uniqid = _numchips + 1
    if _nplanes == 1:
        # We need to reset what gets passed to TDRIZ
        # when only 1 context image plane gets generated
        # to prevent overflow problems with trying to access
        # planes that weren't created for large numbers of inputs.
        _uniqid = ((_uniqid-1) % 32) + 1

    # Select which mask needs to be read in for drizzling
    ####
    #
    # Actually need to generate mask file here 'on-demand'
    # and combine it with the static_mask for single_drizzle case...
    #
    ####
    # Build basic DQMask from DQ array and bits value
    dqarr = img.buildMask(chip._chip,bits=paramDict['bits'])

    # get correct mask filenames/objects
    staticMaskName = chip.outputNames['staticMask']
    crMaskName = chip.outputNames['crmaskImage']

    if img.inmemory:
        if staticMaskName in img.virtualOutputs:
            staticMaskName = img.virtualOutputs[staticMaskName]
        if crMaskName in img.virtualOutputs:
            crMaskName = img.virtualOutputs[crMaskName]

    # Merge appropriate additional mask(s) with DQ mask
    if single:
        mergeDQarray(staticMaskName,dqarr)
        if dqarr.sum() == 0:
            log.warning('All pixels masked out when applying static mask!')
    else:
        mergeDQarray(staticMaskName,dqarr)

        if dqarr.sum() == 0:
            log.warning('All pixels masked out when applying static mask!')
        else:
            # Only apply cosmic-ray mask when some good pixels remain after
            # applying the static mask
            mergeDQarray(crMaskName,dqarr)

            if dqarr.sum() == 0:
                log.warning('WARNING: All pixels masked out when applying '
                            'cosmic ray mask to %s' % _expname)
        updateInputDQArray(chip.dqfile,chip.dq_extn,chip._chip,
                           crMaskName, paramDict['crbit'])

    img.set_wtscl(chip._chip,paramDict['wt_scl'])

    pix_ratio = outwcs.pscale / chip.wcslin_pscale

    # Convert mask to a datatype expected by 'tdriz'
    # Also, base weight mask on ERR or IVM file as requested by user
    wht_type = paramDict['wht_type']

    if wht_type == 'ERR':
        _inwht = img.buildERRmask(chip._chip,dqarr,pix_ratio)
    elif wht_type == 'IVM':
        _inwht = img.buildIVMmask(chip._chip,dqarr,pix_ratio)
    elif wht_type == 'EXP':
        _inwht = img.buildEXPmask(chip._chip,dqarr)
    else:  # wht_type == None, used for single drizzle images
        _inwht = chip._exptime * dqarr.astype(np.float32)

    if not(paramDict['clean']):
        # Write out mask file if 'clean' has been turned off
        if single:
            step_mask = 'singleDrizMask'
        else:
            step_mask = 'finalMask'

        _outmaskname = chip.outputNames[step_mask]
        if os.path.exists(_outmaskname): os.remove(_outmaskname)
        pimg = fits.PrimaryHDU(data=_inwht)
        img.saveVirtualOutputs({step_mask:pimg})
        # Only write out mask files if in_memory=False
        if not img.inmemory:
            pimg.writeto(_outmaskname)
            del pimg
            log.info('Writing out mask file: %s' % _outmaskname)

    time_pre = time.time() - epoch; epoch = time.time()
    # New interface to performing the drizzle operation on a single chip/image
    _vers = do_driz(_insci, chip.wcs, _inwht, outwcs, _outsci, _outwht, _outctx,
                _expin, _in_units, chip._wtscl,
                wcslin_pscale=chip.wcslin_pscale, uniqid=_uniqid,
                pixfrac=paramDict['pixfrac'], kernel=paramDict['kernel'],
                fillval=paramDict['fillval'], stepsize=paramDict['stepsize'],
                wcsmap=wcsmap)
    time_driz = time.time() - epoch; epoch = time.time()

    # Set up information for generating output FITS image
    #### Check to see what names need to be included here for use in _hdrlist
    chip.outputNames['driz_version'] = _vers
    chip.outputNames['driz_wcskey'] = paramDict['wcskey']
    outputvals = chip.outputNames.copy()

    # Update entries for names/values based on final output
    outputvals.update(img.outputValues)
    for kw in img.outputNames:
        if kw[:3] == 'out':
            outputvals[kw] = img.outputNames[kw]
    outputvals['exptime'] = chip._exptime
    outputvals['expstart'] = chip._expstart
    outputvals['expend'] = chip._expend

    outputvals['wt_scl_val'] = chip._wtscl

    _hdrlist.append(outputvals)
    time_post = time.time() - epoch; epoch = time.time()

    if doWrite:
        ###########################
        #
        #   IMPLEMENTATION REQUIREMENT:
        #
        # Need to implement scaling of the output image
        # from 'cps' to 'counts' in the case where 'units'
        # was set to 'counts'... 21-Mar-2005
        #
        ###########################

        # Convert output data from electrons/sec to counts/sec as specified
        native_units = img.native_units
        if paramDict['proc_unit'].lower() == 'native' and native_units.lower()[:6] == 'counts':
            np.divide(_outsci, chip._gain, _outsci)
            _bunit = native_units.lower()
            if paramDict['units'] == 'counts':
                indx = _bunit.find('/')
                if indx > 0: _bunit = _bunit[:indx]

        # record IDCSCALE for output to product header
        paramDict['idcscale'] = chip.wcs.idcscale
        #If output units were set to 'counts', rescale the array in-place
        if paramDict['units'] == 'counts':
            #determine what exposure time needs to be used
            # to rescale the product.
            if single:
                _expscale = chip._exptime
            else:
                _expscale = img.outputValues['texptime']
            np.multiply(_outsci, _expscale, _outsci)
        #
        # Write output arrays to FITS file(s)
        #
        if not single:
            img.inmemory = False

        _outimg = outputimage.OutputImage(_hdrlist, paramDict, build=build,
                                          wcs=output_wcs, single=single)
        _outimg.set_bunit(_bunit)
        _outimg.set_units(paramDict['units'])
        outimgs = _outimg.writeFITS(template,_outsci,_outwht,ctxarr=_outctx,
                                        versions=_versions,virtual=img.inmemory)
        del _outimg

        # update imageObject with product in memory
        if single:
            img.saveVirtualOutputs(outimgs)

    # this is after the doWrite
    time_write = time.time() - epoch; epoch = time.time()
    if False and not single: # turn off all this perf reporting for now
        time_pre_all.append(time_pre)
        time_driz_all.append(time_driz)
        time_post_all.append(time_post)
        time_write_all.append(time_write)

        log.info('chip time pre-drizzling:  %6.3f' % time_pre)
        log.info('chip time drizzling:      %6.3f' % time_driz)
        log.info('chip time post-drizzling: %6.3f' % time_post)
        log.info('chip time writing output: %6.3f' % time_write)

        if doWrite:
            tot_pre = sum(time_pre_all)
            tot_driz = sum(time_driz_all)
            tot_post = sum(time_post_all)
            tot_write = sum(time_write_all)
            tot = tot_pre+tot_driz+tot_post+tot_write
            log.info('chip total pre-drizzling:  %6.3f (%4.1f%%)' % (tot_pre,   (100.*tot_pre/tot)))
            log.info('chip total drizzling:      %6.3f (%4.1f%%)' % (tot_driz,  (100.*tot_driz/tot)))
            log.info('chip total post-drizzling: %6.3f (%4.1f%%)' % (tot_post,  (100.*tot_post/tot)))
            log.info('chip total writing output: %6.3f (%4.1f%%)' % (tot_write, (100.*tot_write/tot)))

Response: Perform the drizzle operation on a single chip.


Instruction:
Explain what the following Python 3 code does
def do_driz(insci, input_wcs, inwht,
            output_wcs, outsci, outwht, outcon,
            expin, in_units, wt_scl,
            wcslin_pscale=1.0,uniqid=1, pixfrac=1.0, kernel='square',
            fillval="INDEF", stepsize=10,wcsmap=None):
    """
    Core routine for performing 'drizzle' operation on a single input image
    All input values will be Python objects such as ndarrays, instead
    of filenames.
    File handling (input and output) will be performed by calling routine.

    """
    # Insure that the fillval parameter gets properly interpreted for use with tdriz
    if util.is_blank(fillval):
        fillval = 'INDEF'
    else:
        fillval = str(fillval)

    if in_units == 'cps':
        expscale = 1.0
    else:
        expscale = expin

    # Compute what plane of the context image this input would
    # correspond to:
    planeid = int((uniqid-1) / 32)

    # Check if the context image has this many planes
    if outcon.ndim == 3:
        nplanes = outcon.shape[0]
    elif outcon.ndim == 2:
        nplanes = 1
    else:
        nplanes = 0

    if nplanes <= planeid:
        raise IndexError("Not enough planes in drizzle context image")

    # Alias context image to the requested plane if 3d
    if outcon.ndim == 2:
        outctx = outcon
    else:
        outctx = outcon[planeid]

    pix_ratio = output_wcs.pscale/wcslin_pscale

    if wcsmap is None and cdriz is not None:
        log.info('Using WCSLIB-based coordinate transformation...')
        log.info('stepsize = %s' % stepsize)
        mapping = cdriz.DefaultWCSMapping(
            input_wcs, output_wcs,
            input_wcs.pixel_shape[0], input_wcs.pixel_shape[1],
            stepsize
        )
    else:
        #
        ##Using the Python class for the WCS-based transformation
        #
        # Use user provided mapping function
        log.info('Using coordinate transformation defined by user...')
        if wcsmap is None:
            wcsmap = wcs_functions.WCSMap
        wmap = wcsmap(input_wcs,output_wcs)
        mapping = wmap.forward

    _shift_fr = 'output'
    _shift_un = 'output'
    ystart = 0
    nmiss = 0
    nskip = 0
    #
    # This call to 'cdriz.tdriz' uses the new C syntax
    #
    _dny = insci.shape[0]
    # Call 'drizzle' to perform image combination
    if insci.dtype > np.float32:
        #WARNING: Input array recast as a float32 array
        insci = insci.astype(np.float32)

    _vers,nmiss,nskip = cdriz.tdriz(insci, inwht, outsci, outwht,
        outctx, uniqid, ystart, 1, 1, _dny,
        pix_ratio, 1.0, 1.0, 'center', pixfrac,
        kernel, in_units, expscale, wt_scl,
        fillval, nmiss, nskip, 1, mapping)

    if nmiss > 0:
        log.warning('! %s points were outside the output image.' % nmiss)
    if nskip > 0:
        log.debug('! Note, %s input lines were skipped completely.' % nskip)

    return _vers

Response: This routine performs the drizzle operation on a single input image and outputs the result image.


Instruction:
Can you generate the documentation for the following Python 3 function
def _regwrite(shapelist,outfile):
    # This function corrects bugs and provides improvements over the pyregion's
    # ShapeList.write method in the following:
    #
    # 1. ShapeList.write crashes if regions have no comments;
    # 2. ShapeList.write converts 'exclude' ("-") regions to normal regions ("+");
    # 3. ShapeList.write does not support mixed coordinate systems in a
    #    region list.
    #
    # NOTE: This function is provided as a temoprary workaround for the above
    #    listed problems of the ShapeList.write. We hope that a future version
    #    of pyregion will address all these issues.
    #
    #TODO: Push these changes to pyregion.

    if len(shapelist) < 1:
        _print_warning("The region list is empty. The region file \"%s\" "\
                       "will be empty." % outfile)
        try:
            outf = open(outfile,'w')
            outf.close()
            return
        except IOError as e:
            cmsg = "Unable to create region file \'%s\'." % outfile
            if e.args:
                e.args = (e.args[0] + "\n" + cmsg,) + e.args[1:]
            else:
                e.args=(cmsg,)
            raise e
        except:
            raise

    prev_cs = shapelist[0].coord_format

    outf = None
    try:
        outf = open(outfile,'w')

        attr0 = shapelist[0].attr[1]
        defaultline = " ".join(["%s=%s" % (a,attr0[a]) for a in attr0 \
                                if a!='text'])

        # first line is globals
        print("global", defaultline, file=outf)
        # second line must be a coordinate format
        print(prev_cs, file=outf)

        for shape in shapelist:
            shape_attr = '' if prev_cs == shape.coord_format \
                            else shape.coord_format+"; "
            shape_excl = '-' if shape.exclude else ''
            text_coordlist = ["%f" % f for f in shape.coord_list]
            shape_coords = "(" + ",".join(text_coordlist) + ")"
            shape_comment = " # " + shape.comment if shape.comment else ''

            shape_str = shape_attr + shape_excl + shape.name + shape_coords + \
                        shape_comment

            print(shape_str, file=outf)

    except IOError as e:
        cmsg = "Unable to create region file \'%s\'." % outfile
        if e.args:
            e.args = (e.args[0] + "\n" + cmsg,) + e.args[1:]
        else:
            e.args=(cmsg,)
        if outf: outf.close()
        raise e
    except:
        if outf: outf.close()
        raise

    outf.close()

Response: Writes the current shape list out as a region file.


Instruction:
Create a Python 3 function for
checking if the region list contains shapes in image - like coordinates

Response:
def _needs_ref_WCS(reglist):
    """ Check if the region list contains shapes in image-like coordinates
    """
    from pyregion.wcs_helper import image_like_coordformats

    for r in reglist:
        if r.coord_format in image_like_coordformats:
            return True
    return False


Instruction:
Can you tell what is the following Python 3 function doing
def extension_from_filename(filename):
    # Parse out any extension specified in filename
    _indx1 = filename.find('[')
    _indx2 = filename.find(']')
    if _indx1 > 0:
        # check for closing square bracket:
        if _indx2 < _indx1:
            raise RuntimeError("Incorrect extension specification in file " \
                                "name \'%s\'." % filename)
        # Read extension name provided
        _fname = filename[:_indx1]
        _extn = filename[_indx1+1:_indx2].strip()
    else:
        _fname = filename
        _extn = None

    return _fname, _extn

Response: Parse out filename from any specified extensions.


Instruction:
How would you code a function in Python 3 to
return the number of extensions in the image.

Response:
def count_extensions(img, extname='SCI'):
    """ Return the number of 'extname' extensions. 'img' can be either a file
    name, an HDU List object (from fits), or None (to get the number of all
    HDU headers.
    """
    if isinstance(img, str):
        img = fits.open(img, memmap=False)
        img.close()
    elif not isinstance(img, fits.HDUList):
        raise TypeError("Argument 'img' must be either a file name (string) " \
                        "or a `astropy.io.fits.HDUList` object.")

    if extname is None:
        return len(img)

    if not isinstance(extname, str):
        raise TypeError("Argument 'extname' must be either a string " \
        "indicating the value of the 'EXTNAME' keyword of the extensions " \
        "to be counted or None to return the count of all HDUs in the " \
        "'img' FITS file.")

    extname = extname.upper()

    n = 0
    for e in img:
        #if isinstance(e, fits.ImageHDU): continue
        if 'EXTNAME' in list(map(str.upper, list(e.header.keys()))) \
            and e.header['extname'].upper() == extname:
            n += 1

    return n


Instruction:
Implement a Python 3 function for
returning a list of all extension versions of extname extensions.

Response:
def get_extver_list(img, extname='SCI'):
    """ Return a list of all extension versions of 'extname' extensions.
    'img' can be either a file name or a HDU List object (from fits).
    """
    if isinstance(img, str):
        img = fits.open(img, memmap=False)
        img.close()
    elif not isinstance(img, fits.HDUList):
        raise TypeError("Argument 'img' must be either a file name (string) "  \
                        "or a fits.HDUList object.")

    # when extver is None - return the range of all FITS extensions
    if extname is None:
        extver = list(range(len(img)))
        return extver

    if not isinstance(extname, str):
        raise TypeError("Argument 'extname' must be either a string "          \
            "indicating the value of the 'EXTNAME' keyword of the extensions " \
            "whose versions are to be returned or None to return "             \
            "extension numbers of all HDUs in the 'img' FITS file.")

    extname = extname.upper()

    extver = []
    for e in img:
        #if not isinstance(e, fits.ImageHDU): continue
        hkeys = list(map(str.upper, list(e.header.keys())))
        if 'EXTNAME' in hkeys and e.header['EXTNAME'].upper() == extname:
            extver.append(e.header['EXTVER'] if 'EXTVER' in hkeys else 1)

    return extver


Instruction:
Can you generate the documentation for the following Python 3 function
def _check_FITS_extvers(img, extname, extvers):
    default_extn = 1 if isinstance(extname, str) else 0

    if isinstance(extvers, list):
        extv = [default_extn if ext is None else ext for ext in extvers]
    else:
        extv = [default_extn if extvers is None else extvers]

    extv_in_fits = get_extver_list(img, extname)

    return set(extv).issubset(set(extv_in_fits))

Response: Checks if all extensions in the FITS file are present in the image. Returns True if all extensions in the FITS file are present in the image. Returns False if any of the specified extensions are not present in the image FITS file.


Instruction:
Implement a function in Python 3 to
generate image and sourcelist filenames for single - exposure products.

Response:
def single_exposure_product_filename_generator(obs_info,nn):
    """
    Generate image and sourcelist filenames for single-exposure products

    Parameters
    ----------
    obs_info : list
        list of items that will be used to generate the filenames: proposal_id,
        visit_id, instrument, detector, filter, and ipppssoot
    nn : string
        the single-exposure image number (NOTE: only used in
        single_exposure_product_filename_generator())

    Returns
    --------
    product_filename_dict : dictionary
        A dictionary containing the generated filenames.
    """
    proposal_id = obs_info[0]
    visit_id = obs_info[1]
    instrument = obs_info[2]
    detector = obs_info[3]
    filter = obs_info[4]
    ipppssoot = obs_info[5]

    product_filename_dict = {}
    product_filename_dict["image"] = "hst_{}_{}_{}_{}_{}_{}_{}.fits".format(proposal_id,visit_id,instrument,detector,filter,ipppssoot,nn)
    product_filename_dict["source catalog"]= product_filename_dict["image"].replace(".fits",".cat")

    return(product_filename_dict)


Instruction:
Make a summary of the following Python 3 code
def filter_product_filename_generator(obs_info,nn):
    proposal_id = obs_info[0]
    visit_id = obs_info[1]
    instrument = obs_info[2]
    detector = obs_info[3]
    filter = obs_info[4]

    product_filename_dict = {}
    product_filename_dict["image"] = "hst_{}_{}_{}_{}_{}.fits".format(proposal_id,visit_id,instrument,detector,filter)
    product_filename_dict["source catalog"] = product_filename_dict["image"].replace(".fits",".cat")

    return(product_filename_dict)

Response: Generate image and sourcelist filenames for filter products


Instruction:
Write a Python 3 script to
generate image and sourcelist filenames for total detection products.

Response:
def total_detection_product_filename_generator(obs_info,nn):
    """
    Generate image and sourcelist filenames for total detection products

    Parameters
    ----------
    obs_info : list
        list of items that will be used to generate the filenames: proposal_id,
        visit_id, instrument, and detector
    nn : string
        the single-exposure image number (NOTE: only used in
        single_exposure_product_filename_generator())

    Returns
    --------
    product_filename_dict : dictionary
        A dictionary containing the generated filenames.
    """
    proposal_id = obs_info[0]
    visit_id = obs_info[1]
    instrument = obs_info[2]
    detector = obs_info[3]

    product_filename_dict = {}
    product_filename_dict["image"] = "hst_{}_{}_{}_{}.fits".format(proposal_id, visit_id, instrument, detector)
    product_filename_dict["source catalog"] = product_filename_dict["image"].replace(".fits",".cat")

    return (product_filename_dict)


Instruction:
Can you create a Python 3 function that
generates image and sourcelist filenames for multi - visit mosaic products.

Response:
def multivisit_mosaic_product_filename_generator(obs_info,nn):
    """
    Generate image and sourcelist filenames for multi-visit mosaic products

    Parameters
    ----------
    obs_info : list
        list of items that will be used to generate the filenames: group_id,
        instrument, detector, and filter
    nn : string
        the single-exposure image number (NOTE: only used in
        single_exposure_product_filename_generator())

    Returns
    --------
    product_filename_dict : dictionary
        A dictionary containing the generated filenames.
    """
    group_num = obs_info[0]
    instrument = obs_info[1]
    detector = obs_info[2]
    filter = obs_info[3]

    product_filename_dict = {}
    product_filename_dict["image"] = "hst_mos_{}_{}_{}_{}.fits".format(group_num,instrument,detector,filter)
    product_filename_dict["source catalog"] = product_filename_dict["image"].replace(".fits",".cat")

    return (product_filename_dict)


Instruction:
Can you tell what is the following Python 3 function doing
def build_referenceWCS(catalog_list):
    wcslist = []
    for catalog in catalog_list:
        for scichip in catalog.catalogs:
            wcslist.append(catalog.catalogs[scichip]['wcs'])
    return utils.output_wcs(wcslist)

Response: Build a default reference WCS from a list of Catalog objects.


Instruction:
Make a summary of the following Python 3 code
def convex_hull(points):

    # Sort the points lexicographically (tuples are compared lexicographically).
    # Remove duplicates to detect the case we have just one unique point.
    points = sorted(set(points))

    # Boring case: no points or a single point, possibly repeated multiple times.
    if len(points) <= 1:
        return points

    # 2D cross product of OA and OB vectors, i.e. z-component of their 3D cross product.
    # Returns a positive value, if OAB makes a counter-clockwise turn,
    # negative for clockwise turn, and zero if the points are collinear.
    def cross(o, a, b):
        return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0])

    # Build lower hull
    lower = []
    for p in points:
        while len(lower) >= 2 and cross(lower[-2], lower[-1], p) <= 0:
            lower.pop()
        lower.append(p)

    # Build upper hull
    upper = []
    for p in reversed(points):
        while len(upper) >= 2 and cross(upper[-2], upper[-1], p) <= 0:
            upper.pop()
        upper.append(p)

    # Concatenation of the lower and upper hulls gives the convex hull.
    # Last point of each list is omitted because it is repeated at the beginning of the other list.
    return lower[:-1] + upper

Response: Computes the convex hull of a set of 2D points.


Instruction:
Implement a function in Python 3 to
compute the initial guess for the 2D histogram for each entry in the image and the UV positions.

Response:
def _estimate_2dhist_shift(imgxy, refxy, searchrad=3.0):
    """ Create a 2D matrix-histogram which contains the delta between each
        XY position and each UV position. Then estimate initial offset
        between catalogs.
    """
    print("Computing initial guess for X and Y shifts...")

    # create ZP matrix
    zpmat = _xy_2dhist(imgxy, refxy, r=searchrad)

    nonzeros = np.count_nonzero(zpmat)
    if nonzeros == 0:
        # no matches within search radius. Return (0, 0):
        print("WARNING: No matches found within a search radius of {:g} "
              "pixels.".format(searchrad))
        return 0.0, 0.0, 0, 0, zpmat, False

    elif nonzeros == 1:
        # only one non-zero bin:
        yp, xp = np.unravel_index(np.argmax(zpmat), zpmat.shape)
        maxval = int(np.ceil(zpmat[yp, xp]))
        xp -= searchrad
        yp -= searchrad
        print("Found initial X and Y shifts of {:.4g}, {:.4g} "
              "based on a single non-zero bin and {} matches"
              .format(xp, yp, maxval))
        return xp, yp, maxval, maxval, zpmat, True

    (xp, yp), fit_status, fit_sl = _find_peak(zpmat, peak_fit_box=5,
                                              mask=zpmat > 0)

    if fit_status.startswith('ERROR'):
        print("WARNING: No valid shift found within a search radius of {:g} "
              "pixels.".format(searchrad))
        maxval = int(np.ceil(zpmat.max()))
        return 0.0, 0.0, maxval, maxval, zpmat, False

    xp -= searchrad
    yp -= searchrad

    if fit_status == 'WARNING:EDGE':
        print(
            "WARNING: Found peak in the 2D histogram lies at the edge of "
            "the histogram. Try increasing 'searchrad' for improved results."
        )

    # Attempt to estimate "significance of detection":
    maxval = zpmat.max()
    zpmat_mask = (zpmat > 0) & (zpmat < maxval)

    if np.any(zpmat_mask):
        bkg = zpmat[zpmat_mask].mean()
        sig = maxval / np.sqrt(bkg)

    flux = int(zpmat[fit_sl].sum())
    print("Found initial X and Y shifts of {:.4g}, {:.4g} "
          "with significance of {:.4g} and {:d} matches"
          .format(xp, yp, sig, flux))

    return xp, yp, int(np.ceil(maxval)), flux, zpmat, True


Instruction:
Can you create a Python 3 function that
finds the location of the peak in an array.

Response:
def _find_peak(data, peak_fit_box=5, mask=None):
    """
    Find location of the peak in an array. This is done by fitting a second
    degree 2D polynomial to the data within a `peak_fit_box` and computing the
    location of its maximum. An initial
    estimate of the position of the maximum will be performed by searching
    for the location of the pixel/array element with the maximum value.

    Parameters
    ----------
    data : numpy.ndarray
        2D data.

    peak_fit_box : int, optional
        Size (in pixels) of the box around the initial estimate of the maximum
        to be used for quadratic fitting from which peak location is computed.
        It is assumed that fitting box is a square with sides of length
        given by ``peak_fit_box``.

    mask : numpy.ndarray, optional
        A boolean type `~numpy.ndarray` indicating "good" pixels in image data
        (`True`) and "bad" pixels (`False`). If not provided all pixels
        in `image_data` will be used for fitting.

    Returns
    -------
    coord : tuple of float
        A pair of coordinates of the peak.

    fit_status : str
        Status of the peak search. Currently the following values can be
        returned:

        - ``'SUCCESS'``: Fit was successful and peak is not on the edge of
          the input array;
        - ``'ERROR:NODATA'``: Not enough valid data to perform the fit; The
          returned coordinate is the center of input array;
        - ``'WARNING:EDGE'``: Peak lies on the edge of the input array.
          Returned coordinates are the result of a discreet search;
        - ``'WARNING:BADFIT'``: Performed fid did not find a maximum. Returned
          coordinates are the result of a discreet search;
        - ``'WARNING:CENTER-OF-MASS'``: Returned coordinates are the result
          of a center-of-mass estimate instead of a polynomial fit. This is
          either due to too few points to perform a fit or due to a
          failure of the polynomial fit.

    fit_box : a tuple of two tuples
        A tuple of two tuples of the form ``((x1, x2), (y1, y2))`` that
        indicates pixel ranges used for fitting (these indices can be used
        directly for slicing input data)

    """
    # check arguments:
    data = np.asarray(data, dtype=np.float64)
    ny, nx = data.shape

    # find index of the pixel having maximum value:
    if mask is None:
        jmax, imax = np.unravel_index(np.argmax(data), data.shape)
        coord = (float(imax), float(jmax))

    else:
        j, i = np.indices(data.shape)
        i = i[mask]
        j = j[mask]

        if i.size == 0:
            # no valid data:
            coord = ((nx - 1.0) / 2.0, (ny - 1.0) / 2.0)
            return coord, 'ERROR:NODATA', np.s_[0:ny-1, 0:nx-1]

        ind = np.argmax(data[mask])
        imax = i[ind]
        jmax = j[ind]
        coord = (float(imax), float(jmax))

    if data[jmax, imax] < 1:
        # no valid data: we need some counts in the histogram bins
        coord = ((nx - 1.0) / 2.0, (ny - 1.0) / 2.0)
        return coord, 'ERROR:NODATA', np.s_[0:ny-1, 0:nx-1]

    # choose a box around maxval pixel:
    x1 = max(0, imax - peak_fit_box // 2)
    x2 = min(nx, x1 + peak_fit_box)
    y1 = max(0, jmax - peak_fit_box // 2)
    y2 = min(ny, y1 + peak_fit_box)

    # if peak is at the edge of the box, return integer indices of the max:
    if imax == x1 or imax == x2 or jmax == y1 or jmax == y2:
        return (float(imax), float(jmax)), 'WARNING:EDGE', np.s_[y1:y2, x1:x2]

    # expand the box if needed:
    if (x2 - x1) < peak_fit_box:
        if x1 == 0:
            x2 = min(nx, x1 + peak_fit_box)
        if x2 == nx:
            x1 = max(0, x2 - peak_fit_box)

    if (y2 - y1) < peak_fit_box:
        if y1 == 0:
            y2 = min(ny, y1 + peak_fit_box)
        if y2 == ny:
            y1 = max(0, y2 - peak_fit_box)

    if x2 - x1 == 0 or y2 - y1 == 0:
        # not enough data:
        coord = ((nx - 1.0) / 2.0, (ny - 1.0) / 2.0)
        return coord, 'ERROR:NODATA', np.s_[y1:y2, x1:x2]

    # fit a 2D 2nd degree polynomial to data:
    xi = np.arange(x1, x2)
    yi = np.arange(y1, y2)
    x, y = np.meshgrid(xi, yi)
    x = x.ravel()
    y = y.ravel()
    v = np.vstack((np.ones_like(x), x, y, x*y, x*x, y*y)).T
    d = data[y1:y2, x1:x2].ravel()
    if mask is not None:
        m = mask[y1:y2, x1:x2].ravel()
        v = v[m]
        d = d[m]

    if d.size == 0 or np.max(d) <= 0:
        coord = ((nx - 1.0) / 2.0, (ny - 1.0) / 2.0)
        return coord, 'ERROR:NODATA', np.s_[y1:y2, x1:x2]

    if d.size < 6:
        # we need at least 6 points to fit a 2D quadratic polynomial
        # attempt center-of-mass instead:
        dt = d.sum()
        xc = np.dot(v[:, 1], d) / dt
        yc = np.dot(v[:, 2], d) / dt
        return (xc, yc), 'WARNING:CENTER-OF-MASS', np.s_[y1:y2, x1:x2]

    try:
        c = np.linalg.lstsq(v, d, rcond=None)[0]
    except np.linalg.LinAlgError:
        print("WARNING: Least squares failed!\n{}".format(c))

        # attempt center-of-mass instead:
        dt = d.sum()
        xc = np.dot(v[:, 1], d) / dt
        yc = np.dot(v[:, 2], d) / dt
        return (xc, yc), 'WARNING:CENTER-OF-MASS', np.s_[y1:y2, x1:x2]

    # find maximum of the polynomial:
    _, c10, c01, c11, c20, c02 = c
    det = 4 * c02 * c20 - c11**2
    if det <= 0 or ((c20 > 0.0 and c02 >= 0.0) or (c20 >= 0.0 and c02 > 0.0)):
        # polynomial does not have max. return maximum value in the data:
        return coord, 'WARNING:BADFIT', np.s_[y1:y2, x1:x2]

    xm = (c01 * c11 - 2.0 * c02 * c10) / det
    ym = (c10 * c11 - 2.0 * c01 * c20) / det

    if 0.0 <= xm <= (nx - 1.0) and 0.0 <= ym <= (ny - 1.0):
        coord = (xm, ym)
        fit_status = 'SUCCESS'

    else:
        xm = 0.0 if xm < 0.0 else min(xm, nx - 1.0)
        ym = 0.0 if ym < 0.0 else min(ym, ny - 1.0)
        fit_status = 'WARNING:EDGE'

    return coord, fit_status, np.s_[y1:y2, x1:x2]


Instruction:
Here you have a function in Python 3, explain what it does
def openFile(self, openDQ=False):

        if self._im.closed:
            if not self._dq.closed:
                self._dq.release()
            assert(self._dq.closed)
            fi = FileExtMaskInfo(clobber=False,
                                 doNotOpenDQ=not openDQ,
                                 im_fmode=self.open_mode)
            fi.image = self.name
            self._im = fi.image
            fi.append_ext(spu.get_ext_list(self._im, extname='SCI'))
            fi.finalize()
            self._im = fi.image
            self._dq = fi.DQimage
            self._imext = fi.fext
            self._dqext = fi.dqext

Response: Open file and set up filehandle for image file


Instruction:
Create a Python 3 function to
return a list of all the input WCS objects associated with this image.

Response:
def get_wcs(self):
        """ Helper method to return a list of all the input WCS objects associated
            with this image.
        """
        wcslist = []
        for chip in self.chip_catalogs:
            wcslist.append(self.chip_catalogs[chip]['wcs'])
        return wcslist


Instruction:
Can you generate the documentation for the following Python 3 function
def buildSkyCatalog(self):
        self.all_radec = None
        self.all_radec_orig = None
        ralist = []
        declist = []
        fluxlist = []
        idlist = []
        for scichip in self.chip_catalogs:
            skycat = self.chip_catalogs[scichip]['catalog'].radec
            xycat = self.chip_catalogs[scichip]['catalog'].xypos
            if skycat is not None:
                ralist.append(skycat[0])
                declist.append(skycat[1])
                if xycat is not None and len(xycat) > 2:
                    fluxlist.append(xycat[2])
                    idlist.append(xycat[3])
                elif len(skycat) > 2:
                    fluxlist.append(skycat[2])
                    idlist.append(skycat[3])
                else:
                    fluxlist.append([999.0]*len(skycat[0]))
                    idlist.append(np.arange(len(skycat[0])))

                self.all_radec = [np.concatenate(ralist),np.concatenate(declist),
                        np.concatenate(fluxlist),np.concatenate(idlist)]
                self.all_radec_orig = copy.deepcopy(self.all_radec)

Response: Builds a single sky catalog for all chips.


Instruction:
Given the following Python 3 function, write the documentation
def buildDefaultRefWCS(self):
        self.default_refWCS = None
        if self.use_wcs:
            wcslist = []
            for scichip in self.chip_catalogs:
                wcslist.append(self.chip_catalogs[scichip]['wcs'])
            self.default_refWCS = utils.output_wcs(wcslist)

Response: Generates a default reference WCS for this image.


Instruction:
Explain what the following Python 3 code does
def transformToRef(self,ref_wcs,force=False):
        if not isinstance(ref_wcs, pywcs.WCS):
            print(textutil.textbox('Reference WCS not a valid HSTWCS object'),
                  file=sys.stderr)
            raise ValueError
        # Need to concatenate catalogs from each input
        if self.outxy is None or force:
            outxy = ref_wcs.wcs_world2pix(self.all_radec[0],self.all_radec[1],self.origin)
            # convert outxy list to a Nx2 array
            self.outxy = np.column_stack([outxy[0][:,np.newaxis],outxy[1][:,np.newaxis]])
            if self.pars['writecat']:
                catname = self.rootname+"_refxy_catalog.coo"
                self.write_outxy(catname)
                self.catalog_names['ref_xy'] = catname

Response: Transform sky coords from ALL chips into X Y coords in reference WCS.


Instruction:
Can you implement a function in Python 3 that
sorts and clip the source catalog based on the flux range specified by the user.

Response:
def sortSkyCatalog(self):
        """ Sort and clip the source catalog based on the flux range specified
        by the user. It keeps a copy of the original full list in order to
        support iteration.

        """
        if len(self.all_radec_orig[2].nonzero()[0]) == 0:
            warn_str = "Source catalog NOT trimmed by flux/mag. No fluxes read in for sources!"
            print('\nWARNING: ',warn_str,'\n')
            log.warning(warn_str)
            return
        clip_catalog = False
        clip_prefix = ''
        for k in sortKeys:
            for p in self.pars.keys():
                pindx = p.find(k)
                if pindx >= 0 and self.pars[p] is not None:
                    log.info('found a match for %s to %s'%(
                                str(p),str(self.pars[p])))
                    # find prefix (if any)
                    clip_prefix = p[:pindx].strip()
                    #Only clip the catalog if one of the keys is specified
                    # in the catalog parameters, not the source finding pars
                    if clip_prefix and 'units' not in p:
                        clip_catalog = True
                        break
            if clip_catalog:
                break
        all_radec = None

        if clip_catalog:

            # Start by clipping by any specified flux range
            if self.pars[clip_prefix+'maxflux'] is not None or \
                    self.pars[clip_prefix+'minflux'] is not None:
                clip_catalog = True
                if self.pars[clip_prefix+'minflux'] is not None:
                    fluxmin = self.pars[clip_prefix+'minflux']
                else:
                    fluxmin = self.all_radec[2].min()

                if self.pars[clip_prefix+'maxflux'] is not None:
                    fluxmax = self.pars[clip_prefix+'maxflux']
                else:
                    fluxmax = self.all_radec[2].max()

                # apply flux limit clipping
                minindx = self.all_radec_orig[2] >= fluxmin
                maxindx = self.all_radec_orig[2] <= fluxmax
                flux_indx = np.bitwise_and(minindx,maxindx)
                all_radec = []
                all_radec.append(self.all_radec_orig[0][flux_indx])
                all_radec.append(self.all_radec_orig[1][flux_indx])
                all_radec.append(self.all_radec_orig[2][flux_indx])
                all_radec.append(np.arange(len(self.all_radec_orig[0][flux_indx])))

            if clip_prefix+'nbright' in self.pars and \
                    self.pars[clip_prefix+'nbright'] is not None:
                clip_catalog = True

                nbright = self.pars[clip_prefix+'nbright']

                # pick out only the brightest 'nbright' sources
                if self.pars[clip_prefix+'fluxunits'] == 'mag':
                    nbslice = slice(None,nbright)
                else:
                    nbslice = slice(nbright,None)

                if all_radec is None:
                    # work on copy of all original data
                    all_radec = copy.deepcopy(self.all_radec_orig)
                # find indices of brightest
                nbright_indx = np.argsort(all_radec[2])[nbslice]
                self.all_radec[0] = all_radec[0][nbright_indx]
                self.all_radec[1] = all_radec[1][nbright_indx]
                self.all_radec[2] = all_radec[2][nbright_indx]
                self.all_radec[3] = np.arange(len(all_radec[0][nbright_indx]))

            else:
                if all_radec is not None:
                    self.all_radec = copy.deepcopy(all_radec)


Instruction:
Explain what the following Python 3 code does
def match(self,refimage, quiet_identity, **kwargs):
        ref_outxy = refimage.outxy
        refWCS = refimage.wcs
        refname = refimage.name
        ref_inxy = refimage.xy_catalog

        cat_src_type = kwargs['cat_src_type']
        del kwargs['cat_src_type']

        if not quiet_identity:
            print("Matching sources from \'{}\' with sources from "
                  "reference {} \'{}\'"
                  .format(self.name, cat_src_type, refname))
        #self.sortSkyCatalog() # apply any catalog sorting specified by the user
        self.transformToRef(refWCS)
        self.refWCS = refWCS
        # extract xyxymatch parameters from input parameters
        matchpars = kwargs.copy()
        self.match_pars = matchpars
        minobj = matchpars['minobj'] # needed for later
        del matchpars['minobj'] # not needed in xyxymatch

        self.goodmatch = True

        # Check to see whether or not it is being matched to itself
        if refname.strip() == self.name.strip():
            self.identityfit = True
            if not quiet_identity:
                log.info('NO fit performed for reference image: %s\n'%self.name)
        else:
            # convert tolerance from units of arcseconds to pixels, as needed
            radius = matchpars['searchrad']
            if matchpars['searchunits'] == 'arcseconds':
                radius /= refWCS.pscale

            # Determine xyoff (X,Y offset) and tolerance to be used with xyxymatch
            if matchpars['use2dhist']:
                xsh, ysh, maxval, flux, zpmat, qual = _estimate_2dhist_shift(
                    self.outxy,
                    ref_outxy,
                    searchrad=radius
                )
                xyoff = (xsh, ysh)

                if matchpars['see2dplot']:
                    zpstd = max(10, flux // 5) if qual else 10
                    title_str = ("Histogram of offsets: Peak has {:d} matches "
                                 "at ({:0.4g}, {:0.4g})"
                                 .format(maxval, xsh, ysh))
                    hist_name = None
                    if not self.interactive:
                        hist_name = 'hist2d_{0}.png'.format(self.rootname)

                    plot_pars = {
                        'data': zpmat,
                        'figure_id': self.figure_id,
                        'vmax': zpstd,
                        'xp': xsh,
                        'yp': ysh,
                        'searchrad': radius,
                        'title_str': title_str,
                        'plotname': hist_name,
                        'interactive': self.interactive
                    }

                    tweakutils.plot_zeropoint(plot_pars)

                if matchpars['see2dplot'] and ('residplot' in matchpars and
                                               'No' in matchpars['residplot']):
                    if self.interactive:
                        prompt = ("Press ENTER for next image, \n" +
                                  "     'n' to continue without updating header or \n" +
                                  "     'q' to quit immediately...\n")

                        if sys.version_info[0] >= 3:
                            a = input(prompt)
                        else:
                            a = raw_input(prompt)

                    else:
                        a = ' '

                    if 'n' in a.lower():
                        self.perform_update = False

                    if 'q' in a.lower():
                        self.quit_immediately = True

                if matchpars['see2dplot']:
                    self.figure_id += 1

            else:
                xoff = 0.
                yoff = 0.
                if not util.is_blank(matchpars['xoffset']):
                    xoff = matchpars['xoffset']
                if not util.is_blank(matchpars['yoffset']):
                    yoff = matchpars['yoffset']
                xyoff = (xoff, yoff)

            matches = xyxymatch(self.outxy, ref_outxy, origin=xyoff,
                                tolerance=matchpars['tolerance'],
                                separation=matchpars['separation'])

            if len(matches) > minobj:
                self.matches['image'] = np.column_stack([matches['input_x'][:,
                                np.newaxis],matches['input_y'][:,np.newaxis]])
                self.matches['ref'] = np.column_stack([matches['ref_x'][:,
                                np.newaxis],matches['ref_y'][:,np.newaxis]])
                self.matches['ref_idx'] = matches['ref_idx']
                self.matches['img_idx'] = self.all_radec[3][matches['input_idx']]
                self.matches['input_idx'] = matches['input_idx']
                self.matches['img_RA'] = self.all_radec[0][matches['input_idx']]
                self.matches['img_DEC'] = self.all_radec[1][matches['input_idx']]

                self.matches['ref_orig_xy'] = np.column_stack([
                                    np.array(ref_inxy[0])[matches['ref_idx']][:,np.newaxis],
                                    np.array(ref_inxy[1])[matches['ref_idx']][:,np.newaxis]])

                self.matches['img_orig_xy'] = np.column_stack([
                    np.array(self.xy_catalog[0])[matches['input_idx']][:,np.newaxis],
                    np.array(self.xy_catalog[1])[matches['input_idx']][:,np.newaxis]])
                self.matches['src_origin'] = ref_inxy[-1][matches['ref_idx']]
                print('Found %d matches for %s...'%(len(matches),self.name))

                if self.pars['writecat']:
                    matchfile = open(self.catalog_names['match'],mode='w+')
                    matchfile.write('#Reference: %s\n'%refname)
                    matchfile.write('#Input: %s\n'%self.name)
                    title = '#Ref_X        Ref_Y        '
                    title += 'Input_X    Input_Y        '
                    title += 'Ref_X0    Ref_Y0        '
                    title += 'Input_X0    Input_Y0        '
                    title += 'Ref_ID    Input_ID        '
                    title += 'Ref_Source\n'
                    fmtstr = '%0.6f    %0.6f        '*4
                    fmtstr += '%d    %d    %s\n'
                    matchfile.write(title)
                    for i in range(len(matches['input_x'])):
                        linestr = fmtstr%\
                            (matches['ref_x'][i],matches['ref_y'][i],\
                             matches['input_x'][i],matches['input_y'][i],
                            self.matches['ref_orig_xy'][:,0][i],
                            self.matches['ref_orig_xy'][:,1][i],
                            self.matches['img_orig_xy'][:,0][i],
                            self.matches['img_orig_xy'][:,1][i],
                            matches['ref_idx'][i],matches['input_idx'][i],
                            self.matches['src_origin'][i])
                        matchfile.write(linestr)
                    matchfile.close()
            else:
                warnstr = textutil.textbox('WARNING: \n'+
                    'Not enough matches (< %d) found for input image: %s'%(minobj,self.name))
                for line in warnstr.split('\n'):
                    log.warning(line)
                print(warnstr)
                self.goodmatch = False

Response: Matches this image with a reference image.


Instruction:
Implement a function in Python 3 to
perform a fit between the matched sources.

Response:
def performFit(self,**kwargs):
        """ Perform a fit between the matched sources.

            Parameters
            ----------
            kwargs : dict
                Parameter necessary to perform the fit; namely, *fitgeometry*.

            Notes
            -----
            This task still needs to implement (eventually) interactive iteration of
                   the fit to remove outliers.
        """
        assert(self.refWCS is not None)
        pars = kwargs.copy()
        self.fit_pars = pars

        self.fit = {'offset':[0.0,0.0],'rot':0.0,'scale':[1.0],'rms':[0.0,0.0],
                    'rms_keys':{'RMS_RA':0.0,'RMS_DEC':0.0,'NMATCH':0},
                    'fit_matrix':[[1.0,0.0],[0.0,1.0]], 'src_origin':[None]}

        if not self.identityfit:
            if self.matches is not None and self.goodmatch:
                self.fit = linearfit.iter_fit_all(
                    self.matches['image'],self.matches['ref'],
                    self.matches['img_idx'],self.matches['ref_idx'],
                    xyorig=self.matches['img_orig_xy'],
                    uvorig=self.matches['ref_orig_xy'],
                    mode=pars['fitgeometry'],nclip=pars['nclip'],
                    sigma=pars['sigma'],minobj=pars['minobj'],
                    center=self.refWCS.wcs.crpix,
                    verbose=self.verbose)

                self.fit['rms_keys'] = self.compute_fit_rms()
                radec_fit = self.refWCS.all_pix2world(self.fit['fit_xy'],1)
                self.fit['fit_RA'] = radec_fit[:,0]
                self.fit['fit_DEC'] = radec_fit[:,1]
                self.fit['src_origin'] = self.matches['src_origin']

                print('Computed ',pars['fitgeometry'],' fit for ',self.name,': ')
                if pars['fitgeometry'] == 'shift':
                    print("XSH: {:.4f}  YSH: {:.4f}"
                          .format(self.fit['offset'][0],
                                  self.fit['offset'][1]))
                elif pars['fitgeometry'] == 'rscale' and self.fit['proper']:
                    print("XSH: {:.4f}  YSH: {:.4f}    ROT: {:.10g}    "
                          "SCALE: {:.6f}".format(
                              self.fit['offset'][0],
                              self.fit['offset'][1],
                              self.fit['rot'],
                              self.fit['scale'][0]))
                elif pars['fitgeometry'] == 'general' or \
                     (pars['fitgeometry'] == 'rscale' and not self.fit['proper']):
                    print("XSH: {:.4f}  YSH: {:.4f}    PROPER ROT: {:.10g}    "
                          "".format(
                              self.fit['offset'][0],
                              self.fit['offset'][1],
                              self.fit['rot']))
                    print("<ROT>: {:.10g}  SKEW: {:.10g}    ROT_X: {:.10g}  "
                          "ROT_Y: {:.10g}".format(
                              self.fit['rotxy'][2],
                              self.fit['skew'],
                              self.fit['rotxy'][0],
                              self.fit['rotxy'][1]))
                    print("<SCALE>: {:.10g}  SCALE_X: {:.10g}  "
                          "SCALE_Y: {:.10g}".format(
                              self.fit['scale'][0],
                              self.fit['scale'][1],
                              self.fit['scale'][2]))
                else:
                    assert(False)

                print('FIT XRMS: {:<7.2g}    FIT YRMS: {:<7.2g}'
                      .format(*self.fit['rms']))
                print('FIT RMSE: {:<7.2g}    FIT MAE: {:<7.2g}\n'
                      .format(self.fit['rmse'], self.fit['mae']))
                print('RMS_RA: %.2g (deg)   RMS_DEC: %.2g (deg)\n'%(
                        self.fit['rms_keys']['RMS_RA'],
                        self.fit['rms_keys']['RMS_DEC']))
                print('Final solution based on ',self.fit['rms_keys']['NMATCH'],' objects.')

                self.write_fit_catalog()

                # Plot residuals, if requested by the user
                if 'residplot' in pars and "No" not in pars['residplot']:
                    xy = self.fit['img_coords']
                    resids = self.fit['resids']
                    xy_fit = xy + resids
                    title_str = 'Residuals\ for\ {0}\ using\ {1:6d}\ sources'.format(
                        self.name.replace('_','\_'),self.fit['rms_keys']['NMATCH'])
                    if not self.interactive:
                        resid_name = 'residuals_{0}.png'.format(self.rootname)
                        vector_name = resid_name.replace('residuals','vector')
                    else:
                        resid_name = None
                        vector_name = None
                    if pars['residplot'] == 'both':
                        tweakutils.make_vector_plot(None,
                            data=[xy[:,0],xy[:,1],xy_fit[:,0],xy_fit[:,1]],
                            figure_id=self.figure_id, vector=True,
                            labelsize=pars['labelsize'],
                            plotname=vector_name, title=title_str)
                        ptype=False # Setup
                        self.figure_id += 1
                    elif pars['residplot'] == 'vector':
                        ptype = True
                    else:
                        ptype = False

                    # Generate new plot
                    tweakutils.make_vector_plot(None,
                        data=[xy[:,0],xy[:,1],xy_fit[:,0],xy_fit[:,1]],
                        figure_id=self.figure_id, vector=ptype,
                        ylimit=pars['ylimit'], labelsize=pars['labelsize'],
                        plotname=resid_name, title=title_str)
                    if self.interactive:
                        prompt = ("Press ENTER for next image, \n" +
                                  "      'n' to continue without updating header or \n" +
                                  "      'q' to quit immediately...\n")
                        if sys.version_info[0] >= 3:
                            a = input(prompt)
                        else:
                            a = raw_input(prompt)
                    else:
                        a = ' '
                    if 'n' in a.lower():
                        self.perform_update = False
                    if 'q' in a.lower():
                        self.quit_immediately = True
            else:
                self.fit['offset'] = [np.nan,np.nan]
                self.fit['rot'] = np.nan
                self.fit['scale'] = [np.nan]


Instruction:
Can you generate the documentation for the following Python 3 function
def updateHeader(self, wcsname=None, reusename=False):
        # Insure filehandle is open and available...
        self.openFile()

        verbose_level = 1
        if not self.perform_update:
            verbose_level = 0
        # Create WCSCORR table to keep track of WCS revisions anyway
        if self.perform_update:
            wcscorr.init_wcscorr(self._im.hdu)

        extlist = []
        wcscorr_extname = self.ext_name
        if self.ext_name == "PRIMARY":
            extlist = [0]
        else:
            for ext in range(1,self.nvers+1):
                extlist.append((self.ext_name,ext))
                # add WCSNAME to SCI headers, if not provided (such as for
                # drizzled images directly obtained from the archive pre-AD)
                if ('wcsname' not in self._im.hdu[self.ext_name,ext].header and
                    self._im.hdu.fileinfo(0)['filemode'] == 'update'):
                    self._im.hdu[self.ext_name,ext].header['wcsname'] = 'Default'

        if not self.identityfit and self.goodmatch and \
                self.fit['offset'][0] != np.nan:
            updatehdr.updatewcs_with_shift(self._im.hdu, self.refWCS,
                wcsname=wcsname, reusename=reusename,
                fitgeom=self.fit_pars['fitgeometry'],
                xsh=self.fit['offset'][0],ysh=self.fit['offset'][1],
                rot=self.fit['rot'],scale=self.fit['scale'][0],
                fit=self.fit['fit_matrix'], verbose=verbose_level,
                xrms=self.fit['rms_keys']['RMS_RA'],
                yrms=self.fit['rms_keys']['RMS_DEC'])

            wnames = altwcs.wcsnames(self._im.hdu,ext=extlist[0])

            altkeys = []
            for k in wnames:
                if wnames[k] == wcsname:
                    altkeys.append(k)
            if len(altkeys) > 1 and ' ' in altkeys:
                altkeys.remove(' ')
            if len(altkeys) == 0:
                next_key = ' '
            else:
                next_key = altkeys[-1]
            if self.perform_update:
                log.info('    Writing out new WCS to alternate WCS: "%s"'%next_key)

            self.next_key = next_key
        else: #if self.identityfit or not self.goodmatch:
            if reusename:
                # Look for key of WCS with this name
                next_key = altwcs.getKeyFromName(self._im.hdu[extlist[0]].header,wcsname)
                # This wcsname is new, so start fresh
                if next_key is None:
                    next_key = altwcs.next_wcskey(self._im.hdu[extlist[0]].header)
            else:
                # Find key for next WCS and save again to replicate an updated solution
                next_key = altwcs.next_wcskey(self._im.hdu[extlist[0]].header)

            if self.perform_update:
                # archive current WCS as alternate WCS with specified WCSNAME
                # Start by archiving original PRIMARY WCS
                wnames = altwcs.wcsnames(self._im.hdu,ext=extlist[0])

                # Define a default WCSNAME in the case that the file to be
                # updated did not have the WCSNAME keyword defined already
                # (as will happen when updating images that have not been
                #  updated using updatewcs).
                if len(wnames) == 0:
                    pri_wcsname = None
                else:
                    # Safeguard against headers not having WCSNAME defined
                    # This would occur if they were written out by something
                    # other than stwcs.updatewcs v
                    if ' ' not in wnames:
                        self._im.hdu[extlist[0]].header['wscname'] = ''
                        wnames[' '] = ''
                    pri_wcsname = wnames[' ']

                next_pkey = altwcs.getKeyFromName(fits.getheader(self.name, extlist[0], memmap=False),pri_wcsname)
                log.info('    Saving Primary WCS to alternate WCS: "%s"'%next_pkey)

                altwcs.archiveWCS(self._im.hdu, extlist,
                                    wcskey=next_pkey, wcsname=pri_wcsname,
                                    reusekey=True)
                if reusename:
                    # Look for key of WCS with this name
                    next_key = altwcs.getKeyFromName(self._im.hdu[extlist[0]].header,wcsname)
                    # This wcsname is new, so start fresh
                    if next_key is None:
                        next_key = altwcs.next_wcskey(self._im.hdu[extlist[0]].header)
                else:
                    # Find key for next WCS and save again to replicate an updated solution
                    next_key = altwcs.next_wcskey(self._im.hdu[extlist[0]].header)
                    # update WCSNAME to be the new name
                    for ext in extlist:
                        self._im.hdu[ext].header['WCSNAME'] = wcsname

                # save again using new WCSNAME
                altwcs.archiveWCS(self._im.hdu, extlist,
                    wcskey=next_key,wcsname=wcsname, reusekey=reusename)
            self.next_key = ' '

        # add FIT values to image's PRIMARY header
        fimg = self._im.hdu

        if wcsname in ['',' ',None,"INDEF"]:
            wcsname = 'TWEAK'
        # Record values for the fit with both the PRIMARY WCS being updated
        # and the alternate WCS which will be created.
        assert(not self._im.closed)

        for ext in extlist:
            self._im.hdu[ext].header['FITNAME'+next_key] = wcsname
            for kw in self.fit['rms_keys']:
                self._im.hdu[ext].header.set(kw+next_key,
                                     self.fit['rms_keys'][kw],
                                     after='FITNAME'+next_key)

        if self.perform_update:
            log.info('Updating WCSCORR table with new WCS solution "%s"'%wcsname)
            wcscorr.update_wcscorr(self._im.hdu, wcs_id=wcsname,
                                   extname=self.ext_name)

Response: Update the header of the image with shifts computed by perform_fit.


Instruction:
Explain what the following Python 3 code does
def writeHeaderlet(self,**kwargs):
        # Insure filehandle is open and available...
        self.openFile()

        pars = kwargs.copy()
        rms_pars = self.fit['rms_keys']

        str_kw = ['descrip','history','author','hdrfile']
        for kw in str_kw:
            if pars[kw] == '': pars[kw] = None

        # Call function with properly interpreted input parameters
        # Syntax: write_headerlet(filename, hdrname, output, sciext='SCI',
        #                    wcsname=None, wcskey=None, destim=None,
        #                    sipname=None, npolfile=None, d2imfile=None,
        #                    author=None, descrip=None, history=None,
        #                    rms_ra=None, rms_dec=None, nmatch=None, catalog=None,
        #                    attach=True, clobber=False):
        headerlet.write_headerlet(self._im.hdu, pars['hdrname'],
                output=pars['hdrfile'],
                wcsname=None, wcskey=self.next_key, destim=None,
                sipname=None, npolfile=None, d2imfile=None,
                author=pars['author'], descrip=pars['descrip'],
                history=pars['history'],
                nmatch=rms_pars['NMATCH'],catalog=pars['catalog'],
                attach=pars['attach'], clobber=pars['clobber']
            )

Response: Write a headerlet based on update to PRIMARY WCS


Instruction:
Given the following Python 3 function, write the documentation
def write_skycatalog(self,filename):
        if self.all_radec is None:
            return
        ralist = self.all_radec[0]#.tolist()
        declist = self.all_radec[1]#.tolist()
        f = open(filename,'w')
        f.write("#Sky positions for: "+self.name+'\n')
        f.write("#RA        Dec\n")
        f.write("#(deg)     (deg)\n")
        for i in range(len(ralist)):
            f.write('%0.12f  %0.12f\n'%(ralist[i],declist[i]))
        f.close()

Response: Write out the all_radec catalog for this image to a file.


Instruction:
How would you implement a function in Python 3 that
returns a string with the names of input_xy catalog names

Response:
def get_xy_catnames(self):
        """ Return a string with the names of input_xy catalog names
        """
        catstr = self.name+'  '
        if 'input_xy' in self.catalog_names:
            for xycat in self.catalog_names['input_xy']:
                catstr += '  '+xycat
        return catstr + '\n'


Instruction:
Write a Python 3 function that can
write out the catalog of all sources and resids used in the final fit.

Response:
def write_fit_catalog(self):
        """ Write out the catalog of all sources and resids used in the final fit.
        """
        if self.pars['writecat']:
            log.info('Creating catalog for the fit: {:s}'.format(self.catalog_names['fitmatch']))
            f = open(self.catalog_names['fitmatch'],'w')
            f.write('# Input image: {:s}\n'.format(self.filename))
            f.write('# Coordinate mapping parameters: \n')
            f.write('#    X and Y rms: {:.2g}  {:.2g}\n'
                    .format(self.fit['rms'][0], self.fit['rms'][1]))
            f.write('#    X and Y shift: {:.4f}  {:.4f}\n'
                    .format(self.fit['offset'][0], self.fit['offset'][1]))
            f.write('#    X and Y scale: {:.10g}  {:.10g}\n'
                    .format(self.fit['scale'][1], self.fit['scale'][2]))
            f.write('#    X and Y rotation: {:.10g}  {:.10g}\n'
                    .format(self.fit['rotxy'][0], self.fit['rotxy'][1]))
            f.write('#    <rotation> and skew: {:.10g}  {:.10g}\n'
                    .format(self.fit['rotxy'][2], self.fit['skew']))

            f.write('# \n# Input Coordinate Listing\n')
            f.write('#     Column 1: X (reference)\n')
            f.write('#     Column 2: Y (reference)\n')
            f.write('#     Column 3: X (input)\n')
            f.write('#     Column 4: Y (input)\n')
            f.write('#     Column 5: X (fit)\n')
            f.write('#     Column 6: Y (fit)\n')
            f.write('#     Column 7: X (residual)\n')
            f.write('#     Column 8: Y (residual)\n')
            f.write('#     Column 9: Original X (reference)\n')
            f.write('#     Column 10: Original Y (reference)\n')
            f.write('#     Column 11: Original X (input)\n')
            f.write('#     Column 12: Original Y (input)\n')
            f.write('#     Column 13: Ref ID\n')
            f.write('#     Column 14: Input ID\n')
            f.write('#     Column 15: Input EXTVER ID \n')
            f.write('#     Column 16: RA (fit)\n')
            f.write('#     Column 17: Dec (fit)\n')
            f.write('#     Column 18: Ref source provenience\n')
            #
            # Need to add chip ID for each matched source to the fitmatch file
            # The chip information can be extracted from the following source:
            #
            #     self.chip_catalogs[sci_extn] = {'catalog':catalog,'wcs':wcs}
            #     xypos = catalog.xypos
            img_chip_id = self.fit['img_indx'].copy()
            for sci_extn in range(1,self.nvers+1):
                catalog = self.chip_catalogs[sci_extn]['catalog']
                if catalog.xypos is not None:
                    img_indx_orig = self.chip_catalogs[sci_extn]['catalog'].xypos[3]
                    chip_min = img_indx_orig.min()
                    chip_max = img_indx_orig.max()
                    cid = np.logical_and((img_chip_id >= chip_min),(img_chip_id <= chip_max))
                    img_chip_id[cid] = sci_extn
            #
            f.write('#\n')
            f.close()

            xydata = [[self.fit['ref_coords'][:,0],self.fit['ref_coords'][:,1],
                      self.fit['img_coords'][:,0],self.fit['img_coords'][:,1],
                      self.fit['fit_xy'][:,0],self.fit['fit_xy'][:,1],
                      self.fit['resids'][:,0],self.fit['resids'][:,1],
                      self.fit['ref_orig_xy'][:,0],
                      self.fit['ref_orig_xy'][:,1],
                      self.fit['img_orig_xy'][:,0],
                      self.fit['img_orig_xy'][:,1]],
                      [self.fit['ref_indx'],self.fit['img_indx'],img_chip_id],
                      [self.fit['fit_RA'],self.fit['fit_DEC']],
                      [self.fit['src_origin']]
                    ]

            tweakutils.write_xy_file(self.catalog_names['fitmatch'],xydata,
                append=True,format=["%15.6f","%8d","%20.12f","   %s"])


Instruction:
Can you generate the documentation for the following Python 3 function
def write_outxy(self,filename):
        f = open(filename,'w')
        f.write("#Pixel positions for: "+self.name+'\n')
        f.write("#X           Y\n")
        f.write("#(pix)       (pix)\n")
        for i in range(self.all_radec[0].shape[0]):
            f.write('%f  %f\n'%(self.outxy[i,0],self.outxy[i,1]))
        f.close()

Response: Write out the output XY catalog for this image to a file.


Instruction:
Write a Python 3 script to
return the information for a shiftfile for this image to provide the MultiDrizzle - based MultiDrizzle compatability with the IRAF - based MultiDrizzle.

Response:
def get_shiftfile_row(self):
        """ Return the information for a shiftfile for this image to provide
            compatability with the IRAF-based MultiDrizzle.
        """
        if self.fit is not None:
            rowstr = '%s    %0.6f  %0.6f    %0.6f     %0.6f   %0.6f  %0.6f\n'%(
                    self.name,self.fit['offset'][0],self.fit['offset'][1],
                    self.fit['rot'],self.fit['scale'][0],
                    self.fit['rms'][0],self.fit['rms'][1])
        else:
            rowstr = None
        return rowstr


Instruction:
Can you tell what is the following Python 3 function doing
def clean(self):
        #TODO: add cleaning of mask files, *if* created ...
        for f in self.catalog_names:
            if 'match' in f:
                if os.path.exists(self.catalog_names[f]):
                    log.info('Deleting intermediate match file: %s'%
                                self.catalog_names[f])
                    os.remove(self.catalog_names[f])
            else:
                for extn in f:
                    if os.path.exists(extn):
                        log.info('Deleting intermediate catalog: %d'%extn)
                        os.remove(extn)

Response: Remove intermediate files created.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def write_skycatalog(self, filename, show_flux=False, show_id=False):
        f = open(filename,'w')
        f.write("#Sky positions for cumulative reference catalog. Initial catalog from: "+self.name+'\n')
        header1 = "#RA        Dec"
        header2 = "#(deg)     (deg)"
        if show_flux:
            header1 += "        Flux"
            header2 += "       (counts)"
        if show_id:
            header1 += "        ID        Origin"
            header2 += ""
        header1 += "\n"
        header2 += "\n"

        f.write(header1)
        f.write(header2)

        show_details = show_flux or show_id
        flux_end_char = ''
        if show_details and show_flux:
            if show_id:
                flux_end_char = '\t'

        for i in range(self.all_radec[0].shape[0]):
            src_line = "{:.7f}  {:.7f}" \
                .format(self.all_radec[0][i], self.all_radec[1][i])
            if show_details:
                #src_line += " #"
                if show_flux:
                    #src_line += " flux: {:.5g}{:s}" \
                        #.format(self.xy_catalog[2][i], flux_end_char)
                    src_line += "  {:.5g}".format(self.xy_catalog[2][i])
                if show_id:
                    #src_line += " ID: {:d}\torigin: '{:s}'" \
                        #.format(self.xy_catalog[3][i], self.xy_catalog[-1][i])
                    src_line += "  {:d}  {:s}".format(self.xy_catalog[3][i],
                                                      self.xy_catalog[-1][i])
            f.write(src_line + '\n')
        f.close()

Response: Write out the all_radec catalog for this image to a file.


Instruction:
Write a Python 3 script for
transforming the reference catalog sky positions to reference tangent plane.

Response:
def transformToRef(self):
        """ Transform reference catalog sky positions (self.all_radec)
        to reference tangent plane (self.wcs) to create output X,Y positions.
        """
        if 'refxyunits' in self.pars and self.pars['refxyunits'] == 'pixels':
            log.info('Creating RA/Dec positions for reference sources...')
            self.outxy = np.column_stack([self.all_radec[0][:,np.newaxis],self.all_radec[1][:,np.newaxis]])
            skypos = self.wcs.wcs_pix2world(self.all_radec[0],self.all_radec[1],self.origin)
            self.all_radec[0] = skypos[0]
            self.all_radec[1] = skypos[1]
        else:
            log.info('Converting RA/Dec positions of reference sources from "%s" to '%self.name+
                        'X,Y positions in reference WCS...')
            self.refWCS = self.wcs
            outxy = self.wcs.wcs_world2pix(self.all_radec[0],self.all_radec[1],self.origin)
            # convert outxy list to a Nx2 array
            self.outxy = np.column_stack([outxy[0][:,np.newaxis],outxy[1][:,np.newaxis]])


Instruction:
Given the following Python 3 function, write the documentation
def clean(self):
        if not util.is_blank(self.catalog.catname) and os.path.exists(self.catalog.catname):
            os.remove(self.catalog.catname)

Response: Remove intermediate files created by this instance of the class.