Пример #1
0
def Idealtov2v3(XIdl, YIdl, apername, **kwargs):
    import pysiaf

    if ('basepath' in kwargs):
        siaf = pysiaf.Siaf('MIRI', basepath=kwargs['basepath'])
    else:
        siaf = pysiaf.Siaf('MIRI')

    thisentry = siaf[apername]

    v2ref, v3ref = thisentry.V2Ref, thisentry.V3Ref
    angle, parity = thisentry.V3IdlYAngle, thisentry.VIdlParity

    # Per Colin Cox:
    # V2 = V2Ref + VIdlParity*XIdl*cos(a) + YIdl*sin(a)
    # V3 = V3Ref - VIdlParity*XIdl*sin(a) + YIdl*cos(a)

    # Do the math
    rpd = math.pi / 180.  # Radians per degree
    v2 = v2ref + parity * XIdl * math.cos(angle * rpd) + YIdl * math.sin(
        angle * rpd)
    v3 = v3ref - parity * XIdl * math.sin(angle * rpd) + YIdl * math.cos(
        angle * rpd)

    return v2, v3
Пример #2
0
def Idealtov2v3(XIdl, YIdl, apername, **kwargs):
    import pysiaf

    if ('instr' in kwargs):
        instrument = kwargs['instr']
    else:
        instrument = 'MIRI'

    if ('basepath' in kwargs):
        siaf = pysiaf.Siaf(instrument, basepath=kwargs['basepath'])
    else:
        siaf = pysiaf.Siaf(instrument)

    print('SIAF version: ', pysiaf.JWST_PRD_VERSION)

    print(apername)
    thisentry = siaf[apername]

    v2ref, v3ref = thisentry.V2Ref, thisentry.V3Ref
    angle, parity = thisentry.V3IdlYAngle, thisentry.VIdlParity

    # Per Colin Cox:
    # V2 = V2Ref + VIdlParity*XIdl*cos(a) + YIdl*sin(a)
    # V3 = V3Ref - VIdlParity*XIdl*sin(a) + YIdl*cos(a)

    # Do the math
    rpd = math.pi / 180.  # Radians per degree
    v2 = v2ref + parity * XIdl * math.cos(angle * rpd) + YIdl * math.sin(
        angle * rpd)
    v3 = v3ref - parity * XIdl * math.sin(angle * rpd) + YIdl * math.cos(
        angle * rpd)

    return v2, v3
Пример #3
0
def v2v3toIdeal(v2, v3, apername, **kwargs):
    import pysiaf

    if ('basepath' in kwargs):
        siaf = pysiaf.Siaf('MIRI', basepath=kwargs['basepath'])
    else:
        siaf = pysiaf.Siaf('MIRI')

    thisentry = siaf[apername]

    v2ref, v3ref = thisentry.V2Ref, thisentry.V3Ref
    angle, parity = thisentry.V3IdlYAngle, thisentry.VIdlParity

    # Inverting the above equations we get
    # XIdl = VIdlParity*(V2-V2Ref)*cos(a) - VIdlParity*(V3-V3REF)*sin(a)
    # YIdl = (V2-V2Ref)*sin(a) + (V3-V3Ref)*cos(a)

    # Do the math
    rpd = math.pi / 180.  # Radians per degree
    XIdl = parity * (v2 - v2ref) * math.cos(
        angle * rpd) - parity * (v3 - v3ref) * math.sin(angle * rpd)
    YIdl = (v2 - v2ref) * math.sin(angle * rpd) + (v3 - v3ref) * math.cos(
        angle * rpd)

    return XIdl, YIdl
Пример #4
0
def test_specific_day_of_year_background_spectrum():
    """Test this function using specific inputs and compare to the ETC
    output values"""
    sw_gain = MEAN_GAIN_VALUES['nircam']['swa']
    lw_gain = MEAN_GAIN_VALUES['nircam']['lwa']
    lw_etc = 2.26 / lw_gain  # 2.26 e/s/pix divided by gain 2.19 e/ADU, FOR LWA
    sw_etc = 0.20 / sw_gain  # 0.20 e/s/pix divided by gain 2.44 e/ADU for SWA

    # Use the NIRISS Focus Field
    ra = 85.22458
    dec = -69.5225
    obs_date = '2021-10-04'

    lw_filter_file = os.path.join(
        CONFIG_DIR, 'F444W_CLEAR_nircam_plus_ote_throughput_moda_sorted.txt')
    #lw_photflam = 7.7190e-22  # FLAM in cgs
    #lw_pivot = 4.3849  # microns
    lw_siaf = pysiaf.Siaf('nircam')['NRCA5_FULL']
    # Here: etc is 1.03, mirage is 0.84. This may be due to a bug in the ETC.

    sw_filter_file = os.path.join(
        CONFIG_DIR, 'F090W_CLEAR_nircam_plus_ote_throughput_moda_sorted.txt')
    #sw_photflam = 3.3895e-20  # FLAM in cgs
    #sw_pivot = 0.9034  # microns
    sw_siaf = pysiaf.Siaf('nircam')['NRCA2_FULL']

    waves, signals = backgrounds.day_of_year_background_spectrum(
        ra, dec, obs_date)

    sw_bkgd = backgrounds.calculate_background(ra,
                                               dec,
                                               sw_filter_file,
                                               True,
                                               sw_gain,
                                               sw_siaf,
                                               back_wave=waves,
                                               back_sig=signals)
    lw_bkgd = backgrounds.calculate_background(ra,
                                               dec,
                                               lw_filter_file,
                                               True,
                                               lw_gain,
                                               lw_siaf,
                                               back_wave=waves,
                                               back_sig=signals)

    assert np.isclose(sw_bkgd, sw_etc, atol=0, rtol=0.15)
    assert np.isclose(lw_bkgd, lw_etc, atol=0, rtol=0.25)
Пример #5
0
def get_v2v3_limits(pupil=None, border=10, return_corners=False, **kwargs):
    """
    V2/V3 Limits for a given module stored within an dictionary

    border : float
        Extend a border by some number of arcsec.
    return_corners : bool
        Return the actualy aperture corners.
        Otherwise, values are chosen to be a square in V2/V3.
    """
    
    siaf = pysiaf.Siaf('NIRCam')
    siaf.generate_toc()

    names_dict = {
        'SW' : 'NRCALL_FULL',
        'LW' : 'NRCALL_FULL',
        'SWA': 'NRCAS_FULL', 
        'SWB': 'NRCBS_FULL',
        'LWA': 'NRCA5_FULL',
        'LWB': 'NRCB5_FULL',
    }

    v2v3_limits = {}
    for name in names_dict.keys():
       
        apname = names_dict[name]

        # Do all four apertures for each SWA & SWB
        ap = siaf[apname]
        if ('S_' in apname) or ('ALL_' in apname):
            v2_ref, v3_ref = ap.corners('tel', False)
        else:
            xsci, ysci = ap.corners('sci', False)
            v2_ref, v3_ref = ap.sci_to_tel(xsci, ysci)

        # Offset by 50" if coronagraphy
        if (pupil is not None) and ('LYOT' in pupil):
            v2_ref -= 2.1
            v3_ref += 47.7

        # Add border margin
        v2_avg = np.mean(v2_ref)
        v2_ref[v2_ref<v2_avg] -= border
        v2_ref[v2_ref>v2_avg] += border
        v3_avg = np.mean(v3_ref)
        v3_ref[v3_ref<v3_avg] -= border
        v3_ref[v3_ref>v3_avg] += border

        if return_corners:

            v2v3_limits[name] = {'V2': v2_ref / 60.,
                                 'V3': v3_ref / 60.}
        else:
            v2_minmax = np.array([v2_ref.min(), v2_ref.max()])
            v3_minmax = np.array([v3_ref.min(), v3_ref.max()])
            v2v3_limits[name] = {'V2': v2_minmax / 60.,
                                 'V3': v3_minmax / 60.}
        
    return v2v3_limits
def checkheaders(model):

    # check that the data have the correct header keywords
    # input is a JWST datamodel

    if model.meta.visit.tsovisit != True:
        model.meta.visit.tsovisit = True
        #print('Setting TSOVISIT keyword')

    # check that CRPIX1 and CRPIX2 are set to the center of the siaf aperture for the array being used.
    array_cfg = model.meta.subarray.name
    #print('Data uses {0}'.format(array_cfg))

    siaf_ap = 'MIRIM_' + array_cfg
    siaf = pysiaf.Siaf('MIRI')
    ap = siaf[siaf_ap]
    # Now set the crpix keywords to the right value we take from the Siaf
    model.meta.wcsinfo.crpix1 = ap.XSciRef
    model.meta.wcsinfo.crpix2 = ap.YSciRef
    #print(model.meta.wcsinfo.crpix1, model.meta.wcsinfo.crpix2)

    # also set these coordinates in another attribute of the model
    model.meta.wcsinfo.siaf_xref_sci = ap.XSciRef
    model.meta.wcsinfo.siaf_yref_sci = ap.YSciRef

    # we also need to add a couple of attributes for the TSO photometry step.
    nints = model.meta.exposure.nints
    model.meta.exposure.integration_start = 1
    model.meta.exposure.integration_end = nints

    return model
Пример #7
0
def test_specific_low_medium_high_background_value():
    """Test specific cases of this function and compare to ETC outputs
    """
    # etc = {'low': 0.24, 'medium': 0.26, 'high': 0.27}  # MJy/sr from webform
    etc = {
        'low': 1.246,
        'medium': 1.352,
        'high': 1.402
    }  # e-/sec/pixel measured from output image

    # Use the NIRISS Focus Field
    ra = 85.22458
    dec = -69.5225

    siaf = pysiaf.Siaf('niriss')['NIS_CEN']
    filter_throughput_file = os.path.join(CONFIG_DIR,
                                          'f150w_niriss_throughput1.txt')
    filter_waves, filter_thru = file_io.read_filter_throughput(
        filter_throughput_file)

    bkgd_high = backgrounds.low_medium_high_background_value(
        ra, dec, "high", filter_waves, filter_thru, siaf)
    bkgd_med = backgrounds.low_medium_high_background_value(
        ra, dec, "medium", filter_waves, filter_thru, siaf)
    bkgd_low = backgrounds.low_medium_high_background_value(
        ra, dec, "low", filter_waves, filter_thru, siaf)

    assert np.isclose(bkgd_high, etc['high'], atol=0., rtol=0.05)
    assert np.isclose(bkgd_med, etc['medium'], atol=0., rtol=0.05)
    assert np.isclose(bkgd_low, etc['low'], atol=0., rtol=0.05)
Пример #8
0
def _get_default_siaf(instrument, aper_name):
    """
    Create instance of pysiaf for the input instrument and aperture
    to be used later to pull SIAF values like distortion polynomial
    coefficients and rotation.

    Parameters
    ----------
    instrument : str
        The name of the instrument
    aper_name : str
        The name of the specific instrument aperture

    Returns
    -------
    aper : instance of pysiaf
    """

    # Create new naming because SIAF requires special capitalization
    if instrument == "NIRCAM":
        siaf_name = "NIRCam"
    elif instrument == "NIRSPEC":
        siaf_name = "NIRSpec"
    else:
        siaf_name = instrument

    # Select a single SIAF aperture
    siaf = pysiaf.Siaf(siaf_name)
    aper = siaf.apertures[aper_name]

    return aper
Пример #9
0
def get_angle(instrument, aperture, angle_name):
    """Get angle requested by user

    Parameters
    ----------
    instrument : JWST instrument of interest
        type : str
    
    aperture : instrument observing aperture
        type : str

    angle_name : angle of interest
        type : str

    Returns
    -------
    angle : the angle obtained from the SIAF.
        type : float
    """

    siaf = pysiaf.Siaf(instrument)
    meta = siaf[aperture]
    angle = getattr(meta, angle_name)

    return angle
Пример #10
0
def RADec_To_XY(ra, dec, array_name, attitude_matrix):
    """Translate backwards, RA, Dec to V2, V3. If a distortion reference file is
        provided, use that. Otherwise fall back to pysiaf.
        Parameters:
        -----------
        ra : float
            Right ascention value, in degrees, to be translated.
        dec : float
            Declination value, in degrees, to be translated.
        Returns:
        --------
        pixelx : float
            X coordinate value in the aperture corresponding to the input location
        pixely : float
            Y coordinate value in the aperture corresponding to the input location
        """
    siaf = pysiaf.Siaf('nircam')[array_name]
    loc_v2, loc_v3 = pysiaf.utils.rotations.getv2v3(attitude_matrix, ra, dec)

    pixelx, pixely = siaf.tel_to_sci(loc_v2, loc_v3)

    # Subtract 1 from SAIF-derived results since SIAF works in a 1-indexed coord system
    pixelx -= 1
    pixely -= 1
    return pixelx, pixely
Пример #11
0
def read_aperture(mode='slit', verbose=True):
    '''
	Function that loads and returns the right SIAF aperture for LRS as specified in the 'mode' parameter: 'slit' or 'slitless'

	'''
    if verbose:
        print("Pysiaf uses PRD version {}".format(pysiaf.JWST_PRD_VERSION))

    # check that the mode is a valid option
    assert (mode in ['slit', 'slitless'
                     ]), "Mode not supported. Please use 'slit' or 'slitless'."

    # Read in the SIAF file using PySiaf
    instrument = 'MIRI'
    siaf = pysiaf.Siaf(instrument)

    # Load in the aperture corresponding to the specified mode:
    if (mode == 'slit'):
        ap = siaf['MIRIM_SLIT']

    elif (mode == 'slitless'):
        ap = siaf['MIRIM_SLITLESSPRISM']

    else:
        raise IOError('Mode not supported!')

    return ap
Пример #12
0
def XY_To_RADec(pixelx, pixely, array_name, attitude_matrix):
    """Translate a given x, y location on the detector to RA, Dec. If a
        distortion reference file is provided, use that. Otherwise fall back to
        using pysiaf.
        Parameters:
        -----------
        pixelx : float
            X coordinate value in the aperture
        pixely : float
            Y coordinate value in the aperture
        Returns:
        --------
        ra : float
            Right ascention value in degrees
        dec : float
            Declination value in degrees
        ra_str : str
            Right ascention value in HH:MM:SS
        dec_str : str
            Declination value in DD:MM:SS
        """
    siaf = pysiaf.Siaf('nircam')[array_name]

    # Use SIAF to do the calculations
    #In this case, add 1 to the input pixel values
    # since SIAF works in a 1-indexed coordinate system.
    loc_v2, loc_v3 = siaf.sci_to_tel(pixelx + 1, pixely + 1)

    ra, dec = pysiaf.utils.rotations.pointing(attitude_matrix, loc_v2, loc_v3)

    return ra, dec
Пример #13
0
def v2v3_to_pixel(ap_obs, v2_obj, v3_obj, frame='det'):
    """V2/V3 to pixel coordinates
    
    Convert object V2/V3 coordinates into detector pixel position.

    Parameters
    ==========
    ap_obs : str
        Name of observed aperture (e.g., NRCA5_FULL)
    v2_obj : ndarray
        V2 locations of stellar sources.
    v3_obj : ndarray
        V3 locations of stellar soruces.

    Keywords
    ========
    frame : str
        'det' or 'sci' coordinate frame. 'det' is always full frame reference.
        'sci' is relative to subarray size if not a full frame aperture.
    """
    
    # xpix and ypix locations
    siaf = pysiaf.Siaf('NIRCAM')
    ap_siaf = siaf[ap_obs]

    if frame=='det':
        xpix, ypix = ap_siaf.tel_to_det(v2_obj, v3_obj)
    elif frame=='sci':
        xpix, ypix = ap_siaf.tel_to_sci(v2_obj, v3_obj)
    else:
        raise ValueError("Do not recognize frame keyword value: {}".format(frame))
        
    return (xpix, ypix)
Пример #14
0
    def __init__(self, RA, DEC, INSTRUMENT):
        self.ra = RA
        self.dec = DEC
        self.instrument = INSTRUMENT

        if 'NIRCam' in self.instrument:
            siaf = pysiaf.Siaf('NIRCam')
            dimX, dimY = 51, 1343
            rad = 2.5
            pixel_scale = siaf.
            xSweet, ySweet = siaf. , siaf.
        elif 'MIRI' in self.instrument:
            siaf = pysiaf.Siaf('MIRI')
            dimX, dimY = 51, 1343
            rad = 2.5
            pixel_scale = siaf.
            xSweet, ySweet = siaf. , siaf.
Пример #15
0
def test_get_zernike_coeffs_from_smif():
    """ 
    Test that the OTE SM Influence function returns expected Hexike coefficients.
    """
    
    # Create an instance of the OTE linear model
    otelm = webbpsf.opds.OTE_Linear_Model_WSS()

    # Case 1: otelm.v2v3 is None, should return None
    otelm._apply_field_dependence_model()
    assert ( otelm._apply_field_dependence_model() is None)

    # Case 2: check coefficient at control point; should return zeros.
    assert(np.allclose(otelm._get_hexike_coeffs_from_smif(0., 0.), np.asarray([0.] * 9)))

    # Case 3: dx=1, dy=1, SM Poses all equal to 1 um
    telfer_zern = [-0.055279643, -0.037571947, -0.80840763, -0.035680581, -0.0036747300, 0.0033910640] # Taken from Telfer's tool
    # Convert Telfer's Zernikes to Hexikes:
    hexikes = [-telfer_zern[1], 
               2.*telfer_zern[0] - (60984./69531.)*telfer_zern[5], 
               telfer_zern[2], 
               (33./25)*telfer_zern[3], 
               (-33./25)*telfer_zern[4], 
               (1386./860.)*telfer_zern[5]]

    otelm.segment_state[-1, :] = 1.0
    
    assert (np.allclose(otelm._get_hexike_coeffs_from_smif(1.0, 1.0)[3:], hexikes, rtol=1e-3))

    # Case 4: test at MIRIM_FP1MIMF field point
    otelm.ote_ctrl_pt = pysiaf.Siaf('NIRCAM')['NRCA3_FP1'].reference_point('tel') *u.arcsec
    otelm.v2v3 = pysiaf.Siaf('MIRI')['MIRIM_FP1MIMF'].reference_point('tel') *u.arcsec
    telfer_zern_mirim_fp1mimf = np.asarray( [-0.25066019, 0.22840080, -0.53545999, -0.024227464, -0.0025191352, 0.00050082553]) # Taken from Telfer's tool
    # Convert Telfer's Zernikes to Hexikes:
    hexikes = hexikes = [-telfer_zern_mirim_fp1mimf[1], 
                         2.*telfer_zern_mirim_fp1mimf[0] - (60984./69531.)*telfer_zern_mirim_fp1mimf[5], 
                         telfer_zern_mirim_fp1mimf[2], 
                         (33./25)*telfer_zern_mirim_fp1mimf[3], 
                         (-33./25)*telfer_zern_mirim_fp1mimf[4], 
                         (1386./860.)*telfer_zern_mirim_fp1mimf[5]]
    
    otelm.segment_state[-1, :] = [300., 400., 100., 200., 5., 0.]
    dx =-(otelm.v2v3[0] - otelm.ote_ctrl_pt[0]).to(u.rad).value 
    dy = (otelm.v2v3[1] - otelm.ote_ctrl_pt[1]).to(u.rad).value

    assert (np.allclose(otelm._get_hexike_coeffs_from_smif(dx, dy)[3:], hexikes, rtol=1e-3))
Пример #16
0
    def get_siaf_info(self, instrument_name, aperture_name):
        """Get v2,v3 reference values and y3yangle for a given aperture

        Parameters
        ----------
        instrument_name : str
            JWST instrument name

        aperture_name : str
            Aperture name to use in pysiaf (e.g. 'NRCA1_FULL')
        """
        self.siaf = pysiaf.Siaf(instrument_name)[aperture_name]
Пример #17
0
    def make_photom(self):
        """MAIN FUNCTION"""
        # Check inputs
        if self.imaging_throughput_files is None:
            raise ValueError(
                "No imaging throughput files specified! Quitting.")
        if self.detector is None:
            raise ValueError("No detector specified! Quitting.")

        self.siaf = pysiaf.Siaf('nircam')['NRC{}_FULL'.format(self.detector)]

        # Lists of polynomial coefficients from SIAF
        self.xcoeffs, self.ycoeffs = self.get_coefficients()

        # Find the nominal pixel area from the SIAF
        self.pixel_area_a2 = self.get_pixel_area()

        # Required header keyword outputs
        sterrad_per_arcsec2 = (1. / 3600. * np.pi / 180.)**2
        self.str_per_detector = (
            self.detector_width * self.detector_length *
            self.pixel_area_a2) * sterrad_per_arcsec2 * u.sr
        self.pixel_area_sr = self.pixel_area_a2.to(u.sr)

        # Calculate the appropriate gain value to use
        #self.find_gain()
        self.find_gain_pre_launch()

        # Calculations for imaging filters
        img_tab = self.imaging_calibrations(self.imaging_throughput_files)

        # Now do the calculations for the grisms
        if self.grism_throughput_files is not None:
            gfiles = self.read_listfile(self.grism_throughput_files)
            grism_table = self.grism_cal(gfiles)

            # Combine the imaging and grism photom tables
            print(grism_table.shape, grism_table[0].shape)
            print(img_tab.shape, img_tab[0].shape)

            photom_table = np.append(img_tab, grism_table)
            print(photom_table.shape, photom_table[0].shape)
        else:
            photom_table = img_tab

        # Get module name from the detector name input
        self.module = self.detector[0].upper()

        # Now you should be ready to write out the reference file
        if self.photom_outfile is None:
            self.photom_outfile = 'NIRCam_{}_photom.fits'.format(self.detector)
        self.save_photom_model(photom_table, self.photom_outfile)
Пример #18
0
def get_instance(instrument):
    """Return an instance of a pysiaf.Siaf object for the given instrument

    Parameters
    ----------
    instrument : str
        Name of instrument

    Returns
    -------
    siaf : pysiaf.Siaf
        Siaf object for the requested instrument
    """
    if instrument.lower() == 'nircam':
        print("NOTE: Using pre-delivery SIAF data for {}".format(instrument))
        siaf_instrument = 'NIRCam'
        pre_delivery_dir = os.path.join(JWST_DELIVERY_DATA_ROOT, 'NIRCam')
        siaf = pysiaf.Siaf(siaf_instrument, basepath=pre_delivery_dir)
    else:
        siaf_instrument = instrument
        siaf = pysiaf.Siaf(siaf_instrument)
    return siaf
Пример #19
0
def Tel2Sci_info(channel, coords, output="Sci"):
    """Telescope coords converted to Science coords
    
    Returns the detector name and position associated with input coordinates.

    Parameters
    ----------
    channel : str
        'SW' or 'LW'
    coords : tuple
        Telescope coordinates (V2,V3) in arcsec.
    output : str
        Type of desired output coordinates. 

            * Det: pixels, in raw detector read out axes orientation
            * Sci: pixels, in conventional DMS axes orientation
            * Idl: arcsecs relative to aperture reference location.
            * Tel: arcsecs V2,V3
    """
    
    V2, V3 = coords
    
    # Figure out the detector and pixel position for some (V2,V3) coord
#    mysiaf = webbpsf.webbpsf_core.SIAF('NIRCam')
    mysiaf = pysiaf.Siaf('NIRCam')
    swa = ['A1', 'A2', 'A3', 'A4']
    swb = ['B1', 'B2', 'B3', 'B4']
    lwa = ['A5']
    lwb = ['B5']
    
    detnames = swa + swb if 'SW' in channel else lwa + lwb
    apnames = ['NRC'+det+'_FULL' for det in detnames]
    
    # Find center positions for each apname
    cens = []
    for apname in apnames:
        ap = mysiaf[apname]
        cens.append(ap.Tel2Sci(V2, V3))
    cens = np.array(cens)

    # Select that with the closest position
    dist = np.sqrt((cens[:,0]-1024)**2 + (cens[:,1]-1024)**2)
    ind = np.where(dist==dist.min())[0][0]
    
    # Find detector "science" coordinates
    detector = detnames[ind]
    apname = apnames[ind]
    ap = mysiaf[apname]
    detector_position = ap.convert(V2, V3, frame_from='Tel', frame_to=output)
    
    return detector, detector_position
Пример #20
0
def radec_to_v2v3(coord_objs,
                  siaf_ref_name,
                  coord_ref,
                  pa_ref,
                  base_off=(0, 0),
                  dith_off=(0, 0)):
    """RA/Dec to V2/V3
    
    Convert a series of RA/Dec positions to telescope V2/V3 coordinates (in arcsec).
    
    Parameters
    ----------
    coord_objs : tuple 
        (RA, Dec) positions (deg), where RA and Dec are numpy arrays.    
    siaf_ref_name : str
        Reference SIAF name (e.g., 'NRCALL_FULL') 
    coord_ref : list or tuple
        RA and Dec towards which reference SIAF points
    pa_ref : float
        Position angle of reference SIAF
        
    Keywords
    --------
    base_off : list or tuple
        X/Y offset of overall aperture offset (see APT pointing file)
    dither_off : list or tuple
        Additional offset from dithering (see APT pointing file)
    """

    # SIAF object setup
    nrc_siaf = pysiaf.Siaf('NIRCam')
    siaf_ref = nrc_siaf[siaf_ref_name]

    # RA and Dec of ap ref location and the objects in the field
    ra_ref, dec_ref = coord_ref
    ra_obj, dec_obj = coord_objs

    # Field offset as specified in APT Special Requirements
    x_off, y_off = (base_off[0] + dith_off[0], base_off[1] + dith_off[1])

    # V2/V3 reference location aligned with RA/Dec reference
    v2_ref, v3_ref = np.array(siaf_ref.reference_point('tel'))

    # Attitude correction matrix relative to NRCALL_FULL aperture
    att = pysiaf.utils.rotations.attitude(v2_ref - x_off, v3_ref + y_off,
                                          ra_ref, dec_ref, pa_ref)

    # Convert all RA/Dec coordinates into V2/V3 positions for objects
    v2_obj, v3_obj = pysiaf.utils.rotations.getv2v3(att, ra_obj, dec_obj)

    return (v2_obj, v3_obj)
Пример #21
0
def aperture_size_check(mast_dicts, instrument_name, aperture_name):
    """Check that the aperture size in a science file is consistent with
    what is listed in the SUBARRAY header keyword. The motivation for this
    check comes from NIRCam ASIC Tuning data, where file apertures are listed
    as FULL, but the data are in fact SUBSTRIPE256. Note that at the moment
    this function will only work for a subset of apertures, because the mapping
    of SUBARRAY header keyword value to pysiaf-recognized aperture name is
    not always straightforward. Initially, this function is being built only
    to support checking files listed as full frame.

    Parameters
    ----------
    mast_dicts : list
        List of file metadata dictionaries, as returned from a MAST query

    instrument_name : str
        JWST instrument name

    aperture_name : str
        Name of the aperture, in order to load the proper SIAF information

    Returns
    -------
    consistent_files : list
        List of metadata dictionaries where the array size in the metadata matches
        that retrieved from SIAF
    """
    consistent_files = []
    siaf = pysiaf.Siaf(instrument_name)

    # If the basic formula for aperture name does not produce a name recognized by
    # pysiaf, then skip the check and assume the file is ok. This should only be the
    # case for lesser-used apertures. For our purposes here, where we are focusing
    # on full frame apertures, it should be ok.
    try:
        siaf_ap = siaf[aperture_name]
    except KeyError:
        consistent_files.extend(mast_dicts)
        return consistent_files

    # Most cases will end up here. Compare SIAF aperture size to that in the metadata
    for mast_dict in mast_dicts:
        array_size_y, array_size_x = mast_dict['subsize2'], mast_dict[
            'subsize1']
        if ((array_size_y == siaf_ap.YSciSize) &
            (array_size_x == siaf_ap.XSciSize)):
            consistent_files.append(mast_dict)

    return consistent_files
Пример #22
0
def get_instance(instrument):
    """Return an instance of a pysiaf.Siaf object for the given instrument

    Parameters
    ----------
    instrument : str
        Name of instrument

    Returns
    -------
    siaf : pysiaf.Siaf
        Siaf object for the requested instrument
    """
    siaf = pysiaf.Siaf(instrument)
    return siaf
Пример #23
0
def fromsiaf(apername):
    siaf=pysiaf.Siaf('MIRI')
    thissiaf=siaf[apername]

    v2ref,v3ref=thissiaf.V2Ref,thissiaf.V3Ref
    xvert=np.array([thissiaf.XIdlVert1,thissiaf.XIdlVert2,thissiaf.XIdlVert3,thissiaf.XIdlVert4])
    yvert=np.array([thissiaf.YIdlVert1,thissiaf.YIdlVert2,thissiaf.YIdlVert3,thissiaf.YIdlVert4])
    # Convert the Ideal frame corner coordinates to v2,v3 corner coordinates
    v2vert,v3vert=mt.Idealtov2v3(xvert,yvert,apername)

    # Convert from SIAF order (lower-left, lower-right, upper-right, upper-left) to 
    # lower-left, upper-left, upper-right, lower-right
    v2vert=v2vert[[0,3,2,1]]
    v3vert=v3vert[[0,3,2,1]]
    
    return v2vert,v3vert
Пример #24
0
def _get_default_siaf(instrument, aper_name):
    """ Store the default SIAF values for distortion and rotation """

    # Create new naming because SIAF requires special capitalization
    if instrument == "NIRCAM":
        siaf_name = "NIRCam"
    elif instrument == "NIRSPEC":
        siaf_name = "NIRSpec"
    else:
        siaf_name = instrument

    # Select a single SIAF aperture
    siaf = pysiaf.Siaf(siaf_name)
    aper = siaf.apertures[aper_name]

    return aper
Пример #25
0
def test_low_medium_high_background_value():
    """Test that the proper integrated background value is calculated for
    a given filter and level"""
    ra = 57.2
    dec = -27.6

    filt_waves = np.array([1., 2., 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 4., 5.])
    filt_thru = np.array([0., 0., 0., 1., 1., 1., 1., 1., 0., 0., 0.])

    siaf = pysiaf.Siaf('nircam')['NRCA1_FULL']
    bkgd_high = backgrounds.low_medium_high_background_value(
        ra, dec, "high", filt_waves, filt_thru, siaf)
    bkgd_med = backgrounds.low_medium_high_background_value(
        ra, dec, "medium", filt_waves, filt_thru, siaf)
    bkgd_low = backgrounds.low_medium_high_background_value(
        ra, dec, "low", filt_waves, filt_thru, siaf)

    assert bkgd_high > bkgd_med
    assert bkgd_med > bkgd_low
Пример #26
0
    def get_wcs(self, aperture, useafter):
        """
        Query the SIAF database file and get WCS values.

        Given an ``APERTURE_NAME`` and a ``USEAFTER`` date query the SIAF database
        and extract the following keywords:
        ``V2Ref``, ``V3Ref``, ``V3IdlYAngle``, ``VIdlParity``,
        ``XSciRef``, ``YSciRef``, ``XSciScale``, ``YSciScale``,
        ``XIdlVert1``, ``XIdlVert2``, ``XIdlVert3``, ``XIdlVert4``,
        ``YIdlVert1``, ``YIdlVert2``, ``YIdlVert3``, ``YIdlVert4``

        Parameters
        ----------
        aperture : str
            The name of the aperture to retrieve.
        useafter : str
            The date of observation (``model.meta.date``)

        Returns
        -------
        siaf : namedtuple
            The SIAF namedtuple with values from the PRD database.
        """
        instrument = INSTRUMENT_MAP[aperture[:3].lower()]
        siaf = pysiaf.Siaf(instrument, basepath=self._source)
        aperture = siaf[aperture.upper()]

        # Fill out the Siaf
        vertices = tuple(getattr(aperture, key) for key in SIAF_VERTICIES)
        siaf = SIAF(v2_ref=aperture.V2Ref,
                    v3_ref=aperture.V3Ref,
                    v3yangle=aperture.V3IdlYAngle,
                    vparity=aperture.VIdlParity,
                    crpix1=aperture.XSciRef,
                    crpix2=aperture.YSciRef,
                    cdelt1=aperture.XSciScale,
                    cdelt2=aperture.YSciScale,
                    vertices_idl=vertices)

        return siaf
Пример #27
0
"""Script adaptation of make_nircam_siaf_figures.ipynb that also includes saving figures to PDF. """
import os
import matplotlib.pyplot as pl
import pysiaf

show_plot = True
save_plot = True

pl.close('all')
plot_dir = os.environ['HOME']

# Load NIRCam SIAF
instrument = 'NIRCam'
siaf = pysiaf.Siaf(instrument)

####################################################################################################
# Create a plot that shows the SUB160 apertures on Module B.

# Figure setup
fig = pl.figure(figsize=(8, 8), facecolor='w', edgecolor='k')
# Plot the outline of each aperture, with reference points marked (plus symbol is default).
# Plotting blue and red lines separately, blue for short wavelength and red for long wavelength.
for aperture_name in [
        'NRCB1_SUB160', 'NRCB2_SUB160', 'NRCB3_SUB160', 'NRCB4_SUB160'
]:
    aperture = siaf[aperture_name]
    aperture.plot(color='b', fill_color='b', fill_alpha=0.3, mark_ref=True)

for aperture_name in ['NRCB5_SUB160']:
    aperture = siaf[aperture_name]
    aperture.plot(color='r', fill_color='r', fill_alpha=0.3, mark_ref=True)
Пример #28
0
def ap_radec(ap_obs, ap_ref, coord_ref, pa_ref, base_off=(0,0), dith_off=(0,0),
             get_cenpos=True, get_vert=False):
    """Aperture reference point(s) RA/Dec
    
    Return RA/Dec associated with the reference point (usually center) 
    of a specific aperture.
    
    Parameters
    ----------
    ap_obs : str
        Name of observed aperture (e.g., NRCA5_FULL)
    ap_ref : str
        Name of reference aperture (e.g., NRCALL_FULL)
    coord_ref : tuple or list
        Center position of reference aperture (RA/Dec deg)
    pa_ref : float
        Position angle of ap_ref
        
    Keywords
    --------
    base_off : list or tuple
        X/Y offset of overall aperture offset (see APT pointing file)
    dither_off : list or tuple
        Additional offset from dithering (see APT pointing file)
    get_cenpos : bool
        Return aperture reference location coordinates?
    get_vert: bool
        Return closed polygon vertices (useful for plotting)?
    """

    if (get_cenpos==False) and (get_vert==False):
        _log.warning("Neither get_cenpos nor get_vert were set to True. Nothing to return.")
        return

    nrc_siaf = pysiaf.Siaf('NIRCAM')
    ap_siaf = nrc_siaf[ap_ref]
    ap_siaf_obs = nrc_siaf[ap_obs]

    # RA and Dec of ap ref location and the objects in the field
    ra_ref, dec_ref = coord_ref

    # Field offset as specified in APT Special Requirements
    x_off, y_off  = (base_off[0] + dith_off[0], base_off[1] + dith_off[1])

    # V2/V3 reference location aligned with RA/Dec reference
    v2_ref, v3_ref = np.array(ap_siaf.reference_point('tel'))
    
    # Attitude correction matrix relative to reference aperture
    att = pysiaf.utils.rotations.attitude(v2_ref-x_off, v3_ref+y_off, ra_ref, dec_ref, pa_ref)

    # Get V2/V3 position of observed SIAF aperture and convert to RA/Dec
    if get_cenpos==True:
        v2_obs, v3_obs  = ap_siaf_obs.reference_point('tel')
        ra_obs, dec_obs = pysiaf.utils.rotations.pointing(att, v2_obs, v3_obs)
        cen_obs = (ra_obs, dec_obs)
    
    # Get V2/V3 vertices of observed SIAF aperture and convert to RA/Dec
    if get_vert==True:
        v2_vert, v3_vert  = ap_siaf_obs.closed_polygon_points('tel', rederive=False)
        ra_vert, dec_vert = pysiaf.utils.rotations.pointing(att, v2_vert, v3_vert)
        vert_obs = (ra_vert, dec_vert)

    if (get_cenpos==True) and (get_vert==True):
        return cen_obs, vert_obs
    elif get_cenpos==True:
        return cen_obs
    elif get_vert==True:
        return vert_obs
    else:
        _log.warning("Neither get_cenpos nor get_vert were set to True. Nothing to return.")
        return
Пример #29
0
aperture_collection = pysiaf.ApertureCollection(aperture_dict)

emulate_delivery = True

if emulate_delivery:
    pre_delivery_dir = os.path.join(JWST_DELIVERY_DATA_ROOT, instrument)
    if not os.path.isdir(pre_delivery_dir):
        os.makedirs(pre_delivery_dir)

    # write the SIAF files to disk
    filenames = pysiaf.iando.write.write_jwst_siaf(aperture_collection,
                                                   basepath=pre_delivery_dir,
                                                   file_format=['xml', 'xlsx'])

    pre_delivery_siaf = pysiaf.Siaf(instrument, basepath=pre_delivery_dir)
    # pre_delivery_siaf = pysiaf.Siaf(instrument, filename=filenames[0])

    compare_against_prd = True
    compare_against_cdp7b = True

    for compare_to in [pysiaf.JWST_PRD_VERSION, 'outdated pre-delivery']:
        if compare_to == 'outdated pre-delivery':
            ref_siaf = pysiaf.Siaf(instrument,
                                   filename=os.path.join(
                                       pre_delivery_dir,
                                       'NIRCam_SIAF_outdated.xml'))
        else:
            # compare new SIAF with PRD version
            ref_siaf = pysiaf.Siaf(instrument)
Пример #30
0
def contamVerify(RA, DEC, INSTRUMENT, APAlist, binComp=[], PDF='', web=False):
    """ Generates a PDF file of figures displaying a simulation
    of the science image for any given observation using the parameters provided.

    Parameter(s)
    ------------
    RA  : str
        The Right Ascension of your target in HH:MM:SS
    DEC : str
        The Declination of your target in DD:MM:SS
    INSTRUMENT : str
        The instrument you are observing with (case-sensitive).
        The software currently supports:
        'MIRI', 'NIRISS', 'NIRCam F322W2', 'NIRCam F444W'
    APAlist : list
        A list of Aperture Position Angle(s). Element(s) must be in integers.
        Example 1:
        [1, 25, 181, 205]
        Example 2:
        [25]
    binComp : list
        A list containing parameters of a missing companion that is not
        in the 2MASS IRSA point-source catalog. The format is:
        [RA (arcseconds), DEC (arcseconds), J mag, H mag, K mag]
        [string, string, integer, integer, integer]
    PDF : string
        The path to where the PDF file will be saved. If left blank, the PDF
        file will be saved in your current working directory.
        Example:
        'path/to/my/file.pdf'
    web : boolean
        Makes it easier to integrate it onto the website. Leave this as false,
        unless you're running this in app_exoctk.py

    Returns
    -------
    A .PDF file containing a simulation of the FOV of your target in the
    science coordinate system. Some things to consider when reading the figures:

    1. The target is circled in red
    2. Stellar temperatures of all sources are plotted by color
    3. The gray region oulined in blue represents the aperture for the given
       instrument.
    4. The blue square represents the readout region, or the "origin"

    """
    print('Generating FOV...')
    # Decimal degrees --> HMSDMS for Irsa.query_region()
    targetcrd = crd.SkyCoord(ra=RA, dec=DEC, unit='deg').to_string('hmsdms')
    targetRA, targetDEC = RA, DEC

    # Querying for neighbors with 2MASS IRSA's fp_psc (point-source catalog)
    rad = 2.5
    print('Querying for point-sources within {} arcminutes...'.format(
        str(rad)))
    info = Irsa.query_region(targetcrd,
                             catalog='fp_psc',
                             spatial='Cone',
                             radius=rad * u.arcmin)

    # Coordinates of all stars in FOV, including target
    allRA = info['ra'].data.data
    allDEC = info['dec'].data.data

    # Initiating a dictionary to hold all relevant star information
    stars = {}
    stars['RA'], stars['DEC'] = allRA, allDEC

    print('Total point-sources found in region: {}'.format(len(stars['RA'])))
    # Finding the target using relative distances
    sindRA = (targetRA - stars['RA']) * np.cos(targetDEC)
    cosdRA = targetDEC - stars['DEC']
    distance = np.sqrt(sindRA**2 + cosdRA**2)
    targetIndex = np.argmin(distance)

    # Appending missing companion to the above lists (if any)
    if binComp != []:
        print('Adding missing companion...')
        bb = binComp[0] / 3600 / np.cos(allDEC[targetIndex] * deg2rad)
        allRA = np.append(allRA, (allRA[targetIndex] + bb))
        allDEC = np.append(allDEC, (allDEC[targetIndex] + binComp[1] / 3600))
        Jmag = np.append(Jmag, binComp[2])
        Hmag = np.append(Kmag, binComp[3])
        Kmag = np.append(Kmag, binComp[4])
        J_Hobs = Jmag - Hmag
        H_Kobs = Hmag - Kmag

    # Restoring model parameters
    modelParam = readsav(os.path.join(TRACES_PATH, 'NIRISS', 'modelsInfo.sav'),
                         verbose=False)
    models = modelParam['models']
    modelPadX = modelParam['modelpadx']
    modelPadY = modelParam['modelpady']
    dimXmod = modelParam['dimxmod']
    dimYmod = modelParam['dimymod']
    jhMod = modelParam['jhmod']
    hkMod = modelParam['hkmod']
    teffMod = modelParam['teffmod']

    # JHK bands of all stars in FOV, including target
    Jmag = info['j_m'].data.data
    Hmag = info['h_m'].data.data
    Kmag = info['k_m'].data.data
    # J-H band, H-K band. This will be used to derive the stellar Temps later
    J_Hobs = Jmag - Hmag
    H_Kobs = Hmag - Kmag

    # Number of stars
    nStars = stars['RA'].size

    # Find/assign Teff of each star
    print('Calculating effective temperatures...')
    starsT = np.empty(nStars)
    for j in range(nStars):
        color_separation = (J_Hobs[j] - jhMod)**2 + (H_Kobs[j] - hkMod)**2
        min_separation_ind = np.argmin(color_separation)
        starsT[j] = teffMod[min_separation_ind]

    # Record keeping
    stars['Temp'] = starsT

    # Initiating a dictionary for customizability
    apertures = {}
    apertures['NIRISS'] = ['NIS_SOSSFULL', 'NIS_SOSSFULL']
    apertures['NIRCam F444W'] = ['NRCA5_GRISM256_F444W', 'NRCA5_FULL']
    apertures['NIRCam F322W2'] = ['NRCA5_GRISM256_F322W2', 'NRCA5_FULL']
    apertures['MIRI'] = ['MIRIM_SLITLESSPRISM', 'MIRIM_FULL']

    # Instantiate SIAF object
    siaf = pysiaf.Siaf(INSTRUMENT.split(' ')[0])

    aper = siaf.apertures[apertures[INSTRUMENT][0]]
    full = siaf.apertures[apertures[INSTRUMENT][1]]

    # DET_targ -> TEL_targ -> get attitude matrix for target
    # -> TEL_neighbor -> DET_neighbor -> SCI_neighbor
    print('Converting Sky --> Science coordinates...')
    xSweet, ySweet = aper.reference_point('det')

    v2targ, v3targ = aper.det_to_tel(xSweet, ySweet)

    contam = {}

    if not web:
        filename = 'contam_{}_{}_{}.pdf'.format(RA, DEC, INSTRUMENT)
        defaultPDF = os.path.join(os.getcwd(), filename).replace(' ', '_')
        PDF = defaultPDF if PDF == '' else PDF
    elif web:
        filename = 'contam_{}_{}_{}.pdf'.format(RA, DEC, INSTRUMENT)
        PDF = os.path.join(TRACES_PATH, filename)

    print('Saving figures to: {}'.format(PDF))
    print('This will take a second...')
    pdfobj = PdfPages(PDF)
    for APA in APAlist:

        attitude = pysiaf.utils.rotations.attitude_matrix(
            v2targ, v3targ, targetRA, targetDEC, APA)

        xdet, ydet = [], []
        xsci, ysci = [], []

        for starRA, starDEC in zip(stars['RA'], stars['DEC']):
            # Get the TEL coordinates of each star using the attitude
            # matrix of the target
            V2, V3 = pysiaf.utils.rotations.sky_to_tel(attitude, starRA,
                                                       starDEC)
            # Convert to arcsec and turn to a float
            V2, V3 = V2.to(u.arcsec).value, V3.to(u.arcsec).value

            XDET, YDET = aper.tel_to_det(V2, V3)
            XSCI, YSCI = aper.det_to_sci(XDET, YDET)

            xdet.append(XDET)
            ydet.append(YDET)
            xsci.append(XSCI)
            ysci.append(YSCI)

        XDET, YDET = np.array(xdet), np.array(ydet)
        XSCI, YSCI = np.array(xsci), np.array(ysci)

        starsAPA = {'xdet': XDET, 'ydet': YDET, 'xsci': XSCI, 'ysci': YSCI}

        # Finding indexes of neighbor sources that land on detector
        rows, cols = full.corners('det')

        minrow, maxrow = rows.min(), rows.max()
        mincol, maxcol = cols.min(), cols.max()

        inFOV = []
        for star in range(0, nStars):

            x, y = starsAPA['xdet'][star], starsAPA['ydet'][star]
            if (mincol < x) & (x < maxcol) & (minrow < y) & (y < maxrow):
                inFOV.append(star)

        inFOV = np.array(inFOV)

        # Making final plot
        fig = plt.figure(figsize=(15, 15))
        aper.plot(frame='sci', fill_color='gray', color='blue')
        plt.scatter(XSCI[targetIndex],
                    YSCI[targetIndex],
                    s=400,
                    lw=1.5,
                    facecolor='gray',
                    edgecolor='red')
        plotTemps(starsT[inFOV], XSCI[inFOV], YSCI[inFOV])
        aper.plot_frame_origin(frame='sci', which='sci')

        # Fine-tune trace lengths
        start, stop = traceLength(INSTRUMENT)

        # Plotting the trace footprints
        for x, y in zip(XSCI[inFOV], YSCI[inFOV]):

            if 'F322W2' in INSTRUMENT:
                plt.plot([x - stop, x + start], [y, y],
                         lw=40,
                         color='white',
                         alpha=0.2)
                plt.plot([x - stop, x + start], [y, y], lw=2., color='white')
            elif 'F444W' in INSTRUMENT:
                plt.plot([x - start, x + stop], [y, y],
                         lw=40,
                         color='white',
                         alpha=0.2)
                plt.plot([x - start, x + stop], [y, y], lw=2., color='white')
            else:
                plt.plot([x, x], [y - stop, y + start],
                         lw=40,
                         color='white',
                         alpha=0.2)
                plt.plot([x, x], [y - stop, y + start], lw=2., color='white')

        # Labeling
        aperstr = str(aper.AperName.replace('_', ' '))
        tx, ty = str(round(XSCI[targetIndex])), str(round(YSCI[targetIndex]))
        plt.title(
            'The FOV in SCIENCE coordinates at APA {}$^o$'.format(str(APA)) +
            '\n' + '{}'.format(aperstr) + '\n' +
            'Target (X,Y): {}, {}'.format(tx, ty),
            fontsize=20)

        # Adding to PDF
        pdfobj.savefig(fig, bbox_inches='tight')

    pdfobj.close()

    if web:
        return PDF