Esempio n. 1
0
def xyideal_to_v2v3(xi, yi, **kwargs):
    if ('siaf1A' in kwargs):
        siaf1A = kwargs['siaf1A']
    else:
        # Import locally to this function so that pysiaf isn't required for everything in mrs_tools
        import miricoord.mrs.makesiaf.makesiaf_mrs as makesiaf
        siaf1A = makesiaf.create_siaf_oneband('1A')

    v2ref, v3ref = siaf1A['inscr_v2ref'], siaf1A['inscr_v3ref']

    v2 = -(xi - v2ref)
    v3 = yi + v3ref

    return v2, v3
Esempio n. 2
0
def v2v3_to_xyideal(v2, v3, **kwargs):
    if ('siaf1A' in kwargs):
        siaf1A = kwargs['siaf1A']
    else:
        # Import locally to this function so that pysiaf isn't required for everything in mrs_tools
        import miricoord.mrs.makesiaf.makesiaf_mrs as makesiaf
        siaf1A = makesiaf.create_siaf_oneband('1A')

    v2ref, v3ref = siaf1A['inscr_v2ref'], siaf1A['inscr_v3ref']

    xidl = -(v2 - v2ref)
    yidl = v3 - v3ref

    return xidl, yidl
Esempio n. 3
0
def main(detband, dithers, psftot, extval, scan=False, writearea=False):
    # Set the distortion solution to use
    mt.set_toolversion('cdp8b')

    # Define the bands to use
    left, right = 'N/A', 'N/A'

    if ((detband == '1A') or (detband == '12A')):
        left = '1A'
    if ((detband == '2A') or (detband == '12A')):
        right = '2A'
    if ((detband == '1B') or (detband == '12B')):
        left = '1B'
    if ((detband == '2B') or (detband == '12B')):
        right = '2B'
    if ((detband == '1C') or (detband == '12C')):
        left = '1C'
    if ((detband == '2C') or (detband == '12C')):
        right = '2C'

    if ((detband == '3A') or (detband == '34A')):
        right = '3A'
    if ((detband == '4A') or (detband == '34A')):
        left = '4A'
    if ((detband == '3B') or (detband == '34B')):
        right = '3B'
    if ((detband == '4B') or (detband == '34B')):
        left = '4B'
    if ((detband == '3C') or (detband == '34C')):
        right = '3C'
    if ((detband == '4C') or (detband == '34C')):
        left = '4C'

    #########################################################

    print('Setting up the dithers')

    # Normal CDP-8b distortion solution dithers from PRDOPSSOC-M-026
    if (scan == False):
        dxidl = -np.array([
            0., 1.094458, -1.012049, 0.988069, -1.117844, 0.102213, -0.127945,
            0.008080, -0.034015
        ])
        dyidl = -np.array([
            0., -0.385616, 0.296642, -0.311605, 0.371771, -0.485776, 0.467512,
            -0.499923, 0.481275
        ])

        # Select desired combination of dither positions
        # Warning, this will fail if we have bad input!
        dxidl = dxidl[dithers]
        dyidl = dyidl[dithers]
        nexp = len(dxidl)

    # If the 'scan' option was True, then override the setup to create a scanning grid to sample
    # the field for a given channel.  Note that this also will only populate a single detector at a time!
    if (scan == True):
        if ((detband == '12A') or (detband == '12B') or (detband == '12C')
                or (detband == '34A') or (detband == '34B')
                or (detband == '34C')):
            print('Cannot use scan with selected band!')
        # What is the field for this channel?
        chinfo = mrssiaf.create_siaf_oneband(detband)
        minalpha, maxalpha = np.min(chinfo['inscr_alpha_corners']), np.max(
            chinfo['inscr_alpha_corners'])
        minbeta, maxbeta = np.min(chinfo['inscr_beta_corners']), np.max(
            chinfo['inscr_beta_corners'])
        # And the slice width
        sw = mt.slicewidth(detband)
        # Number of slices
        nslice = ((maxbeta - minbeta) / sw).astype(int)
        # PSF FWHM for spacing from detector edges for sim points
        fwhm = 2 * rough_fwhm(detband)
        # First seven points are the center, corners, and sides
        alpha1 = np.array([
            0, minalpha + fwhm, maxalpha - fwhm, minalpha + fwhm,
            maxalpha - fwhm, minalpha + fwhm, maxalpha - fwhm
        ])
        beta1 = np.array([
            0, maxbeta - fwhm, maxbeta - fwhm, 0, 0, minbeta + fwhm,
            minbeta + fwhm
        ])
        # Next set of points is a scan up alpha=0 for every slice
        alpha2 = np.zeros(nslice)
        beta2 = np.arange(nslice) * sw + minbeta + sw / 2.
        # Concatenate arrays
        alpha = np.concatenate((alpha1, alpha2))
        beta = np.concatenate((beta1, beta2))

        # Convert to v2,v3
        v2, v3 = mt.abtov2v3(alpha, beta, detband)
        # Now convert to Ideal coordinate offsets relative to Ch1a reference point
        dxidl, dyidl = mt.v2v3_to_xyideal(v2, v3)
        # Now flip them, because we're moving the source not the telescope
        dxidl, dyidl = -dxidl, -dyidl
        nexp = len(dxidl)

        # Print the points to a file for reference
        pointfile = 'simpoints' + detband + '.txt'
        print('# alpha beta', file=open(pointfile, "w"))
        for ii in range(0, nexp):
            print(alpha[ii], beta[ii], file=open(pointfile, "a"))

        # Plot where the points were for reference
        plotname = 'qaplot' + detband + '.png'
        plot_qascan(chinfo, detband, v2, v3, filename=plotname)

    #########################################################

    print('Ndither = ', nexp)

    # MRS reference location is DEFINED for 1A regardless of band in use
    v2ref, v3ref = mt.abtov2v3(0., 0., '1A')

    # Define source coordinates (decl=0 makes life easier)
    raobj = 45.0
    decobj = 0.0
    # Make life easier by assuming that telescope roll exactly places
    # slices along R.A. for Ch1A (will not be quite as good for other channels)
    # Compute what that roll is
    a1, b1 = 0., 0.
    a2, b2 = 2., 0.  # A location along alpha axis
    v2_1, v3_1 = mt.abtov2v3(a1, b1, '1A')
    v2_2, v3_2 = mt.abtov2v3(a2, b2, '1A')
    ra_1, dec_1, _ = tt.jwst_v2v3toradec([v2_1], [v3_1],
                                         v2ref=v2ref,
                                         v3ref=v3ref,
                                         raref=raobj,
                                         decref=decobj,
                                         rollref=0.)
    ra_2, dec_2, _ = tt.jwst_v2v3toradec([v2_2], [v3_2],
                                         v2ref=v2ref,
                                         v3ref=v3ref,
                                         raref=raobj,
                                         decref=decobj,
                                         rollref=0.)
    dra = (ra_2 - ra_1) * 3600.
    ddec = (dec_2 - dec_1) * 3600.
    roll = -(np.arctan2(dra, ddec) * 180. / np.pi - 90.0)

    # Compute the corresponding raref, decref, rollref of the dither positions.
    raref = np.zeros(nexp)
    decref = np.zeros(nexp)
    rollref = np.zeros(nexp)
    for ii in range(0, nexp):
        temp1, temp2, temp3 = tt.jwst_v2v3toradec([v2ref] - dxidl[ii],
                                                  [v3ref] + dyidl[ii],
                                                  v2ref=v2ref,
                                                  v3ref=v3ref,
                                                  raref=raobj,
                                                  decref=decobj,
                                                  rollref=roll)
        raref[ii] = temp1
        decref[ii] = temp2
        rollref[ii] = temp3

    # Values for each exposure
    allexp = np.zeros([nexp, 1024, 1032])
    allarea = np.zeros([nexp, 1024, 1032])

    # Do left half of detector
    print('Working on left half of detector')
    roi = rough_fwhm(left) * 3
    if (left != 'N/A'):
        allexp, allarea = setvalues(allexp, allarea, left, roi, raobj, decobj,
                                    raref, decref, rollref, dxidl, dyidl,
                                    psftot, extval)

    # Do right half of detector
    print('Working on right half of detector')
    roi = rough_fwhm(right) * 3
    if (right != 'N/A'):
        allexp, allarea = setvalues(allexp, allarea, right, roi, raobj, decobj,
                                    raref, decref, rollref, dxidl, dyidl,
                                    psftot, extval)

    # Write the exposures to disk
    print('Writing files')
    basefile = get_template(detband)
    for ii in range(0, nexp):
        thisexp = allexp[ii, :, :]
        thisarea = allarea[ii, :, :]
        # Ensure two-digit sim format code
        strii = str(ii)
        if (ii <= 9):
            strii = '0' + str(ii)
        newfile = 'mock' + detband + '-' + strii + '.fits'
        newareafile = 'mockarea' + detband + '-' + strii + '.fits'
        hdu = fits.open(basefile)
        # Hack header WCS
        primheader = hdu[0].header
        primheader['TARG_RA'] = raobj
        primheader['TARG_DEC'] = decobj
        header = hdu['SCI'].header
        header['V2_REF'] = v2ref
        header['V3_REF'] = v3ref
        header['RA_REF'] = raref[ii]
        header['DEC_REF'] = decref[ii]
        header['ROLL_REF'] = rollref[ii]
        hdu['SCI'].header = header
        hdu['SCI'].data = thisexp
        # Overwrite any old DQ problems
        hdu['DQ'].data[:] = 0
        hdu.writeto(newfile, overwrite=True)
        if (writearea == True):
            hdu['SCI'].data = thisarea
            hdu.writeto(newareafile, overwrite=True)

    print('Done!')
Esempio n. 4
0
def make_x1d_fromdict(now, cdp_dir, outplot):
    meta = {}
    meta['telescope'] = 'JWST'
    meta['pedigree'] = 'GROUND'
    meta['description'] = 'Default MIRI MRS Extract1d parameters'
    meta['date'] = now.value
    meta['reftype'] = 'EXTRACT1D'
    meta['exposure'] = {'type': 'MIR_MRS'}
    meta['useafter'] = '2000-01-01T00:00:00'
    meta['version'] = int(now.mjd)
    meta['author'] = 'D. Law'
    meta['origin'] = 'STSCI'
    meta['model_type'] = 'Extract1dIFUModel'
    meta['history'] = '1D Extraction defaults'
    meta['history'] += ' DOCUMENT: TBD'
    meta[
        'history'] += ' SOFTWARE: https://github.com/STScI-MIRI/miri3d/tree/master/miri3d/x1d/make_x1d.py'
    meta['history'] += ' DATA USED: CDP-7'
    meta['history'] += ' Updated 4/26/21 to decrease background annulus size'
    meta['instrument'] = {'name': 'MIRI'}
    meta['region_type'] = 'target'
    meta['subtract_background'] = True
    meta['method'] = 'subpixel'
    meta['subpixels'] = 10

    print('Figuring out wavelength ranges')
    wmin1A, _ = mc.waveminmax('1A')
    _, wmax4C = mc.waveminmax('4C')

    print('Building tables')

    # Set up placeholder vectors
    waves = np.arange(wmin1A, wmax4C, 0.01, dtype='float32')
    nwave = len(waves)
    radius = np.ones(nwave, dtype='float32')
    inbkg = np.zeros(nwave, dtype='float32')
    outbkg = np.zeros(nwave, dtype='float32')
    axratio = np.ones(nwave, dtype='float32')
    axangle = np.zeros(nwave, dtype='float32')

    # Populate real values
    # Read in the CDP files
    files = [
        'MIRI_FM_MIRIFUSHORT_1SHORT_APERCORR_07.00.00.fits',
        'MIRI_FM_MIRIFUSHORT_1MEDIUM_APERCORR_07.00.00.fits',
        'MIRI_FM_MIRIFUSHORT_1LONG_APERCORR_07.00.00.fits',
        'MIRI_FM_MIRIFUSHORT_2SHORT_APERCORR_07.00.00.fits',
        'MIRI_FM_MIRIFUSHORT_2MEDIUM_APERCORR_07.00.00.fits',
        'MIRI_FM_MIRIFUSHORT_2LONG_APERCORR_07.00.00.fits',
        'MIRI_FM_MIRIFULONG_3SHORT_APERCORR_07.00.00.fits',
        'MIRI_FM_MIRIFULONG_3MEDIUM_APERCORR_07.00.00.fits',
        'MIRI_FM_MIRIFULONG_3LONG_APERCORR_07.00.00.fits',
        'MIRI_FM_MIRIFULONG_4SHORT_APERCORR_07.00.00.fits',
        'MIRI_FM_MIRIFULONG_4MEDIUM_APERCORR_07.00.00.fits',
        'MIRI_FM_MIRIFULONG_4LONG_APERCORR_07.00.00.fits'
    ]
    inwave = []
    inap = []
    for file in files:
        fullfile = os.path.join(cdp_dir, file)
        hdu = fits.open(fullfile)
        data = hdu[1].data
        inwave.append(data['wavelength'])
        inap.append(data['a_aperture'])

    # Compile into big vectors
    # Simple polynomial fit to the aperture
    thefit = np.polyfit(np.array(inwave).ravel(), np.array(inap).ravel(), 1)
    poly = np.poly1d(thefit)
    radius = poly(waves)

    # Background annulus
    # Note that Ch1 can be much more generous than Ch4; FWHM increases
    # by a factor of 5 from Ch1 to Ch4 but FOV only by a factor of 2.
    # We also should not apply any sudden steps in the annulus size
    # between channels, otherwise that will manifest as a step in the required
    # aperture correction between channels, and we're assuming that it can be
    # smooth with wavelength so everything interpolates from the same table.

    # Therefore, we'll make annuli that shrink linearly (relative to FWHM)
    # with wavelength
    in1, in2 = np.min(radius) * 2.5, np.max(radius) * 1.02
    out1, out2 = np.min(radius) * 3.0, np.max(radius) * 1.5
    inbkg = np.float32(
        np.interp(waves, np.array([np.min(waves), np.max(waves)]),
                  np.array([in1, in2])))
    outbkg = np.float32(
        np.interp(waves, np.array([np.min(waves), np.max(waves)]),
                  np.array([out1, out2])))

    # QA plot that our aperture and annuli look reasonable
    fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(5, 5), dpi=150)
    tband = ['1A', '2A', '3A', '4A']  # Bands to test
    twave = [7.5, 11.75, 18, 28]  # Wavelengths to test
    ax = [ax1, ax2, ax3, ax4]
    for ii in range(0, len(tband)):
        siaf = mksiaf.create_siaf_oneband(tband[ii])
        indx = np.argmin(np.abs(waves - twave[ii]))
        ax[ii].plot(siaf['inscr_v2_corners'],
                    siaf['inscr_v3_corners'],
                    color='#000000',
                    linewidth=2)
        # Circle showing FWHM
        circle = mpl.patches.Circle((siaf['inscr_v2ref'], siaf['inscr_v3ref']),
                                    0.31 * twave[ii] / 8. / 2,
                                    linewidth=1,
                                    edgecolor='black',
                                    facecolor=(0, 0, 0, .0125))
        ax[ii].add_artist(circle)
        # Circle showing extraction radius
        circle = mpl.patches.Circle((siaf['inscr_v2ref'], siaf['inscr_v3ref']),
                                    radius[indx],
                                    linewidth=1,
                                    edgecolor='r',
                                    facecolor=(0, 0, 0, .0125))
        ax[ii].add_artist(circle)
        # Circles showing annulus
        circle = mpl.patches.Circle((siaf['inscr_v2ref'], siaf['inscr_v3ref']),
                                    inbkg[indx],
                                    linewidth=1,
                                    edgecolor='b',
                                    facecolor=(0, 0, 0, .0125))
        ax[ii].add_artist(circle)
        circle = mpl.patches.Circle((siaf['inscr_v2ref'], siaf['inscr_v3ref']),
                                    outbkg[indx],
                                    linewidth=1,
                                    edgecolor='b',
                                    facecolor=(0, 0, 0, .0125))
        ax[ii].add_artist(circle)
        ax[ii].set_xlim(-508, -499)
        ax[ii].set_ylim(-324, -315)
        ax[ii].set_xlabel('V2 (arcsec)')
        ax[ii].set_ylabel('V3 (arcsec)')
        ax[ii].set_title(tband[ii])
    plt.tight_layout()
    plt.savefig(str.replace(outplot, '.png', 'FOV.png'))
    plt.close()

    # QA plot of final values
    plt.plot(inwave, inap, '.')
    plt.plot(waves, radius)
    plt.plot(waves, inbkg, color='red')
    plt.plot(waves, outbkg, color='red')
    plt.grid()
    plt.xlabel('Wavelength (micron)')
    plt.ylabel('Extraction Radius (arcsec)')
    plt.savefig(outplot)
    plt.close()

    data = {
        'wavelength': waves,
        'wavelength_units': 'micron',
        'radius': radius,
        'radius_units': 'arcsec',
        'inner_bkg': inbkg,
        'inner_bkg_units': 'arcsec',
        'outer_bkg': outbkg,
        'outer_bkg_units': 'arcsec',
        'axis_ratio': axratio,
        'axis_pa': axangle,
        'axis_pa_units': 'degrees',
    }

    tree = {'meta': meta, 'data': data}

    ff = asdf.AsdfFile(tree)

    return ff
def assess_dith(rootdir=False,
                siafdir=False,
                write_result=False,
                channel='1A',
                dith=False,
                wave=False,
                da=None,
                db=None):

    #set root and siaf directories
    if rootdir == False:
        rootdir = os.getenv('MIRICOORD_DATA_DIR')
    if siafdir == False:
        siafdir = os.getenv('MIRICOORD_DATA_DIR')

    #
    if dith == False:
        dith = [1, 2]

    ndith = len(dith)

    #read in list of dithers
    dithers = pd.read_csv('mrs_dithers.txt', header=2, sep='\s+', index_col=0)

    #convert dithers to ra/dec
    dra = dithers.dXIdeal[dith].array / 3600.
    ddec = dithers.dYIdeal[dith].array / 3600.

    siaf = makesiaf.create_siaf_oneband(channel)

    #define shape of channel in alpha/beta
    maxalpha = siaf['inscr_alpha_corners'][0] * 2
    minalpha = siaf['inscr_alpha_corners'][2] * 2
    maxbeta = siaf['inscr_beta_corners'][0] * 2
    minbeta = siaf['inscr_beta_corners'][2] * 2

    racen = 45.
    decen = 0.
    # WARNING- this code will fail if DEC != 0 !!!!
    dtheta = 0.02

    #number of pix in ra/dec dims
    nra = int(np.abs(maxalpha - minalpha) / dtheta)
    ndec = int(np.abs(maxbeta - minbeta) / dtheta)

    #define the wavelength on each pixel
    if wave != False:
        lam = np.ones((nra * ndec)) * wave
    else:
        lam = np.ones((nra * ndec)) * -1

    if (da != None) and (db != None):
        v2, v3 = mmrs.abtov2v3(da, db, channel)

        zpv2, zpv3 = mmrs.abtov2v3(0, 0, channel)

        zpx, zpy = mmrs.v2v3_to_xyideal(zpv2, zpv3)

        tempx, tempy = mmrs.v2v3_to_xyideal(v2, v3)

        dra = (tempx - zpx) / 3600.
        ddec = (tempy - zpy) / 3600.

    #define actual ra/dec range
    ra = (np.arange(nra) * dtheta + minalpha) / 3600. + racen
    dec = (np.arange(ndec) * dtheta + minbeta) / 3600. + decen

    #redefine center
    racen = (min(ra) + max(ra)) / 2.
    decen = (min(dec) + max(dec)) / 2.

    #create a cube of ra/dec coordinates
    skyloc = np.zeros((ndith, ndec, nra))

    for i in range(0, nra - 1):
        skyloc[0, :, i] = ra[i]

    for i in range(0, ndec - 1):
        skyloc[1, i, :] = dec[i]

    rall = skyloc[0, :, :].reshape(nra * ndec)
    deall = skyloc[1, :, :].reshape(nra * ndec)

    # construct phase images
    slice_phase, pixel_phase, wave_phase = make_phase_im(
        rall, deall, racen, decen, dra, ddec, nra, ndec, lam, ndith, channel)

    temp = np.sum(wave_phase, axis=0)
    goodval = np.where(temp > -10)

    #construct coverage map
    covmap = make_covmap(goodval, wave_phase, pixel_phase)

    temp = covmap[0, :, :]
    indx = np.where(temp != 0)
    nindx = len(indx[0])
    print('Coverage area: ' + str(nindx * dtheta * dtheta) + ' arcsec^2')

    offsets = np.sqrt((dra - dra[0])**2 + (ddec - ddec[0])**2)
    maxoffset = max(offsets) * 3600.

    if write_result == True:
        output_result(maxoffset, channel, phase_pix, phase_slice, covmap)

    return wave_phase, pixel_phase, covmap