Beispiel #1
0
def oteip_to_v23(reference_files):
    """
    Transform from the OTEIP frame to the V2V3 frame.

    Parameters
    ----------
    reference_files: dict
        Dictionary with reference files returned by CRDS.

    Returns
    -------
    model : `~astropy.modeling.core.Model` model.
        Transform from OTEIP to V2V3.

    """
    with AsdfFile.open(reference_files['ote']) as f:
        ote = f.tree['model'].copy()
    fore2ote_mapping = Identity(3, name='fore2ote_mapping')
    fore2ote_mapping.inverse = Mapping((0, 1, 2, 2))
    # Create the transform to v2/v3/lambda.  The wavelength units up to this point are
    # meters as required by the pipeline but the desired output wavelength units is microns.
    # So we are going to Scale the spectral units by 1e6 (meters -> microns)
    # The spatial units are currently in deg. Convertin to arcsec.
    oteip_to_xyan = fore2ote_mapping | (ote & Scale(1e6))
    # Add a shift for the aperture.
    oteip2v23 = oteip_to_xyan | Identity(1) & (Shift(468 / 3600) | Scale(-1)) & Identity(1)

    return oteip2v23
Beispiel #2
0
    def setup_class(cls):
        cls.model1D = Identity(n_inputs=1)
        cls.model2D = Identity(n_inputs=2) | Mapping((0, ), n_inputs=2)
        cls.model3D = Identity(n_inputs=3) | Mapping((0, ), n_inputs=3)

        cls.data = cls.x = cls.y = cls.z = np.linspace(0, 10, num=100)
        cls.lsq_exp = 0
Beispiel #3
0
def run_test(model):
    wcsobj = model.meta.wcs
    for ch in model.meta.instrument.channel:
        ref_data = mrs_ref_data[ch + band_mapping[model.meta.instrument.band]]
        detector_to_alpha_beta = wcsobj.get_transform('detector', 'alpha_beta')
        #ab_to_xan_yan = wcsobj.get_transform('alpha_beta', 'Xan_Yan').set_input(int(ch))
        ab_to_v2v3 = wcsobj.get_transform('alpha_beta',
                                          'v2v3').set_input(int(ch))
        ab_to_xan_yan = ab_to_v2v3 | Scale(1 / 60) & Scale(1 / 60) & Identity(
            1) | Identity(1) & (Scale(-1) | Shift(-7.8)) & Identity(1)
        ref_alpha = ref_data['alpha']
        ref_beta = ref_data['beta']
        ref_lam = ref_data['lam']

        x, y = ref_data['x'], ref_data['y']
        for i, s in enumerate(ref_data['s']):
            sl = int(ch) * 100 + s
            alpha, beta, lam = detector_to_alpha_beta.set_input(sl)(x[i], y[i])
            utils.assert_allclose(alpha, ref_alpha[i], atol=10**-4)
            utils.assert_allclose(beta, ref_beta[i], atol=10**-4)
            utils.assert_allclose(lam, ref_lam[i], atol=10**-4)

        xan, yan, lam = ab_to_xan_yan(ref_alpha, ref_beta, ref_lam)
        utils.assert_allclose(xan, ref_data['v2'], atol=10**-4)
        utils.assert_allclose(yan, ref_data['v3'], atol=10**-4)
        utils.assert_allclose(lam, ref_data['lam'], atol=10**-4)
Beispiel #4
0
    def _convert_item_to_models(self, item, drop_all_non_separable):
        inputs = []
        prepend = []
        axes_to_drop = []

        # Iterate over all the axes and keep a list of models prepend to the
        # transform, and a list of axes to remove from the wcs completely.

        # We always add a model to prepend list so that we maintain consistency
        # with the number of axes. If prepend is entirely identity models, it
        # is not used.
        input_units = self._input_units()
        for i, ax in enumerate(item):
            if isinstance(ax, int):
                if self.separable[i]:
                    axes_to_drop.append(i)
                elif not self.separable[i] and drop_all_non_separable:
                    axes_to_drop.append(i)
                else:
                    inputs.append(ax * input_units[i])
                    prepend.append(Identity(1))
            elif ax.start:
                inputs.append(None)
                prepend.append(Shift(ax.start * input_units[i]))
            else:
                inputs.append(None)
                prepend.append(Identity(1))

        return inputs, prepend, axes_to_drop
Beispiel #5
0
def ifu_msa_to_oteip(reference_files):
    """
    Transform from the MSA frame to the OTEIP frame.

    Parameters
    ----------
    reference_files: dict
        Dictionary with reference files returned by CRDS.

    Returns
    -------
    model : `~astropy.modeling.core.Model` model.
        Transform from MSA to OTEIP.
    """
    with AsdfFile.open(reference_files['fore']) as f:
        fore = f.tree['model'].copy()
    with AsdfFile.open(reference_files['ifufore']) as f:
        ifufore = f.tree['model'].copy()

    msa2fore_mapping = Mapping((0, 1, 2, 2))
    msa2fore_mapping.inverse = Identity(3)
    ifu_fore_transform = ifufore & Identity(1)
    ifu_fore_transform.inverse = Mapping(
        (0, 1, 2, 2)) | ifufore.inverse & Identity(1)
    fore_transform = msa2fore_mapping | fore & Identity(1)
    return msa2fore_mapping | ifu_fore_transform | fore_transform
Beispiel #6
0
def mask_slit(ymin=-.5, ymax=.5):
    """
    Returns a model which masks out pixels in a NIRSpec cutout outside the slit.

    Uses ymin, ymax for the slit and the wavelength range to define the location of the slit.

    Parameters
    ----------
    ymin, ymax : float
        ymin and ymax relative boundary of a slit.

    Returns
    -------
    model : `~astropy.modeling.core.Model`
        A model which takes x_slit, y_slit, lam inputs and substitutes the
        values outside the slit with NaN.

    """
    greater_than_ymax = Logical(condition='GT', compareto=ymax, value=np.nan)
    less_than_ymin = Logical(condition='LT', compareto=ymin, value=np.nan)

    model = Mapping((0, 1, 2, 1)) | Identity(3) & (greater_than_ymax | less_than_ymin | models.Scale(0)) | \
          Mapping((0, 1, 3, 2, 3)) | Identity(1) & Mapping((0,), n_inputs=2) + Mapping((1,)) & \
          Mapping((0,), n_inputs=2) + Mapping((1,))
    model.inverse = Identity(3)
    return model
Beispiel #7
0
def pcf_forward(pcffile, outname):
    """
    Create the **IDT** forward transform from collimator to gwa.
    """
    with open(pcffile) as f:
        lines = [l.strip() for l in f.readlines()]

    factors = lines[lines.index('*Factor 2') + 1].split()
    # factor==1/factor in backward msa2ote direction and factor==factor in sky2detector direction
    scale = models.Scale(float(factors[0]), name="x_scale") & \
          models.Scale(float(factors[1]), name="y_scale")

    rotation_angle = lines[lines.index('*Rotation') + 1]
    # The minius sign here is because astropy.modeling has the opposite direction of rotation than the idl implementation
    rotation = models.Rotation2D(-float(rotation_angle), name='rotation')


    # Here the model is called "output_shift" but in the team version it is the "input_shift".
    input_rot_center = lines[lines.index('*InputRotationCentre 2') + 1].split()
    input_rot_shift = models.Shift(-float(input_rot_center[0]), name='input_x_shift') & \
                 models.Shift(-float(input_rot_center[1]), name='input_y_shift')


    # Here the model is called "input_shift" but in the team version it is the "output_shift".
    output_rot_center = lines[lines.index('*OutputRotationCentre 2') + 1].split()
    output_rot_shift = models.Shift(float(output_rot_center[0]), name='output_x_shift') & \
                  models.Shift(float(output_rot_center[1]), name='output_y_shift')

    degree = int(lines[lines.index('*FitOrder') + 1])
    xcoeff_index = lines.index('*xForwardCoefficients 21 2')
    xlines = lines[xcoeff_index + 1: xcoeff_index + 22]
    xcoeff_forward = coeffs_from_pcf(degree, xlines)
    x_poly_forward = models.Polynomial2D(degree, name='x_poly_forward', **xcoeff_forward)

    ycoeff_index = lines.index('*yForwardCoefficients 21 2')
    ycoeff_forward = coeffs_from_pcf(degree, lines[ycoeff_index + 1: ycoeff_index + 22])
    y_poly_forward = models.Polynomial2D(degree, name='y_poly_forward', **ycoeff_forward)

    xcoeff_index = lines.index('*xBackwardCoefficients 21 2')
    xcoeff_backward = coeffs_from_pcf(degree, lines[xcoeff_index + 1: xcoeff_index + 22])
    x_poly_backward = models.Polynomial2D(degree, name='x_poly_backward', **xcoeff_backward)

    ycoeff_index = lines.index('*yBackwardCoefficients 21 2')
    ycoeff_backward = coeffs_from_pcf(degree, lines[ycoeff_index + 1: ycoeff_index + 22])
    y_poly_backward = models.Polynomial2D(degree, name='y_poly_backward', **ycoeff_backward)

    x_poly_forward.inverse = x_poly_backward
    y_poly_forward.inverse = y_poly_backward

    poly_mapping1  = Mapping((0, 1, 0, 1))
    poly_mapping1.inverse = Identity(2)
    poly_mapping2 = Identity(2)
    poly_mapping2.inverse = Mapping((0, 1, 0, 1))

    model = input_rot_shift | rotation | scale | output_rot_shift | \
          poly_mapping1 | x_poly_forward & y_poly_forward | poly_mapping2
    f = AsdfFile()
    f.tree = {'model': model}
    f.write_to(outname)
Beispiel #8
0
def imaging(input_model, reference_files):
    """
    Imaging pipeline

    frames : detector, gwa, msa, sky
    """
    # Get the corrected disperser model
    disperser = get_disperser(input_model, reference_files['disperser'])

    # DETECTOR to GWA transform
    det2gwa = detector_to_gwa(reference_files,
                              input_model.meta.instrument.detector, disperser)

    gwa_through = Const1D(-1) * Identity(1) & Const1D(-1) * Identity(
        1) & Identity(1)

    angles = [
        disperser['theta_x'], disperser['theta_y'], disperser['theta_z'],
        disperser['tilt_y']
    ]
    rotation = Rotation3DToGWA(angles, axes_order="xyzy",
                               name='rotaton').inverse
    dircos2unitless = DirCos2Unitless(name='directional_cosines2unitless')

    col = AsdfFile.open(reference_files['collimator']).tree['model']

    # Get the default spectral order and wavelength range and record them in the model.
    sporder, wrange = get_spectral_order_wrange(
        input_model, reference_files['wavelengthrange'])
    input_model.meta.wcsinfo.waverange_start = wrange[0]
    input_model.meta.wcsinfo.waverange_end = wrange[1]
    input_model.meta.wcsinfo.spectral_order = sporder

    lam = wrange[0] + (wrange[1] - wrange[0]) * .5

    lam_model = Mapping((0, 1, 1)) | Identity(2) & Const1D(lam)

    gwa2msa = gwa_through | rotation | dircos2unitless | col | lam_model
    gwa2msa.inverse = col.inverse | dircos2unitless.inverse | rotation.inverse | gwa_through

    # MSA to OTEIP transform
    msa2ote = msa_to_oteip(reference_files)
    msa2oteip = msa2ote | Mapping((0, 1), n_inputs=3)
    msa2oteip.inverse = Mapping((0, 1, 0, 1)) | msa2ote.inverse | Mapping(
        (0, 1), n_inputs=3)
    # OTEIP to V2,V3 transform
    with AsdfFile.open(reference_files['ote']) as f:
        oteip2v23 = f.tree['model'].copy()

    # Create coordinate frames in the NIRSPEC WCS pipeline
    # "detector", "gwa", "msa", "oteip", "v2v3", "world"
    det, gwa, msa_frame, oteip, v2v3 = create_imaging_frames()

    imaging_pipeline = [(det, det2gwa), (gwa, gwa2msa), (msa_frame, msa2oteip),
                        (oteip, oteip2v23), (v2v3, None)]

    return imaging_pipeline
Beispiel #9
0
def gwa_to_ifuslit(slits, disperser, wrange, order, reference_files):
    """
    GWA to SLIT transform.

    Parameters
    ----------
    slits : list
        A list of slit IDs for all IFU slits 0-29.
    disperser : dict
        A corrected disperser ASDF object.
    filter : str
        The filter used.
    grating : str
        The grating used in the observation.
    reference_files: dict
        Dictionary with reference files returned by CRDS.

    Returns
    -------
    model : `~jwst_lib.pipeline_models.Gwa2Slit` model.
        Transform from GWA frame to SLIT frame.
   """
    agreq = AngleFromGratingEquation(disperser['groove_density'],
                                     order,
                                     name='alpha_from_greq')
    lgreq = WavelengthFromGratingEquation(disperser['groove_density'],
                                          order,
                                          name='lambda_from_greq')
    collimator2gwa = collimator_to_gwa(reference_files, disperser)
    lam = (wrange[1] - wrange[0]) / 2 + wrange[0]

    ifuslicer = AsdfFile.open(reference_files['ifuslicer'])
    ifupost = AsdfFile.open(reference_files['ifupost'])
    slit_models = {}
    ifuslicer_model = ifuslicer.tree['model']
    for slit in slits:
        slitdata = ifuslicer.tree['data'][slit]
        slitdata_model = get_slit_location_model(slitdata)
        ifuslicer_transform = (slitdata_model | ifuslicer_model)
        ifupost_transform = ifupost.tree[slit]['model']
        msa2gwa = ifuslicer_transform | ifupost_transform | collimator2gwa
        gwa2msa = gwa_to_ymsa(msa2gwa)  # TODO: Use model sets here
        bgwa2msa = Mapping((0, 1, 0, 1), n_inputs=3) | \
                 Const1D(0) * Identity(1) & Const1D(-1) * Identity(1) & Identity(2) | \
                 Identity(1) & gwa2msa & Identity(2) | \
                 Mapping((0, 1, 0, 1, 2, 3)) | Identity(2) & msa2gwa & Identity(2) | \
                 Mapping((0, 1, 2, 5), n_inputs=7)| Identity(2) & lgreq

        # msa to before_gwa
        #msa2bgwa = Mapping((0, 1, 2, 2)) | msa2gwa & Identity(1) | Mapping((3, 0, 1, 2)) | agreq
        msa2bgwa = msa2gwa & Identity(1) | Mapping((3, 0, 1, 2)) | agreq
        bgwa2msa.inverse = msa2bgwa
        slit_models[slit] = bgwa2msa

    ifuslicer.close()
    ifupost.close()
    return Gwa2Slit(slit_models)
Beispiel #10
0
def gwa_to_slit(slits_id, disperser, wrange, order, reference_files):
    """
    GWA to SLIT transform.

    Parameters
    ----------
    slits_id : list
        A list of slit IDs for all open shutters/slitlets.
    disperser : dict
        A corrected disperser ASDF object.
    filter : str
        The filter used.
    grating : str
        The grating used in the observation.
    reference_files: dict
        Dictionary with reference files returned by CRDS.

    Returns
    -------
    model : `~jwst_lib.pipeline_models.Gwa2Slit` model.
        Transform from GWA frame to SLIT frame.
    """
    agreq = AngleFromGratingEquation(disperser['groove_density'],
                                     order,
                                     name='alpha_from_greq')
    lgreq = WavelengthFromGratingEquation(disperser['groove_density'],
                                          order,
                                          name='lambda_from_greq')
    collimator2gwa = collimator_to_gwa(reference_files, disperser)

    msa = AsdfFile.open(reference_files['msa'])
    slit_models = {}
    for i in range(1, 6):
        slit_names = slits_id[slits_id[:, 0] == i]
        if slit_names.any():
            msa_model = msa.tree[i]['model']
            for slit in slit_names:
                index = slit[1] - 1
                slitdata = msa.tree[slit[0]]['data'][index]
                slitdata_model = get_slit_location_model(slitdata)
                msa_transform = slitdata_model | msa_model
                msa2gwa = (msa_transform | collimator2gwa)
                gwa2msa = gwa_to_ymsa(msa2gwa)  # TODO: Use model sets here
                bgwa2msa = Mapping((0, 1, 0, 1), n_inputs=3) | \
                    Const1D(0) * Identity(1) & Const1D(-1) * Identity(1) & Identity(2) | \
                    Identity(1) & gwa2msa & Identity(2) | \
                    Mapping((0, 1, 0, 1, 2, 3)) | Identity(2) & msa2gwa & Identity(2) | \
                    Mapping((0, 1, 2, 5), n_inputs=7)| Identity(2) & lgreq

                # msa to before_gwa
                msa2bgwa = msa2gwa & Identity(1) | Mapping(
                    (3, 0, 1, 2)) | agreq
                bgwa2msa.inverse = msa2bgwa
                s = slitid_to_slit(np.array([slit]))[0]
                slit_models[s] = bgwa2msa
    msa.close()
    return Gwa2Slit(slit_models)
Beispiel #11
0
def make_mock_jwst_pipeline(v2ref=0,
                            v3ref=0,
                            roll=0,
                            crpix=[512, 512],
                            cd=[[1e-5, 0], [0, 1e-5]],
                            crval=[0, 0],
                            enable_vacorr=True):
    detector = gwcs.coordinate_frames.Frame2D(name='detector',
                                              axes_order=(0, 1),
                                              unit=(u.pix, u.pix))
    v2v3 = gwcs.coordinate_frames.Frame2D(name='v2v3',
                                          axes_order=(0, 1),
                                          unit=(u.arcsec, u.arcsec))
    v2v3vacorr = gwcs.coordinate_frames.Frame2D(name='v2v3vacorr',
                                                axes_order=(0, 1),
                                                unit=(u.arcsec, u.arcsec))
    world = gwcs.coordinate_frames.CelestialFrame(reference_frame=coord.ICRS(),
                                                  name='world')
    det2v2v3 = create_DetToV2V3(v2ref=v2ref / 3600.0,
                                v3ref=v3ref / 3600.0,
                                roll=roll,
                                cd=cd,
                                crpix=crpix)

    v23sky = V2V3ToSky(
        [-v2ref / 3600.0, v3ref / 3600.0, -roll, -crval[1], crval[0]],
        [2, 1, 0, 1, 2])
    if enable_vacorr:
        pipeline = [(detector, det2v2v3), (v2v3, Identity(2)),
                    (v2v3vacorr, v23sky), (world, None)]
    else:
        pipeline = [(detector, det2v2v3), (v2v3, v23sky), (world, None)]

    return pipeline
Beispiel #12
0
def nrs_wcs_set_input(wcsobj, quadrant, slitid, wavelength_range):
    """
    Returns a WCS object for this slit.

    Parameters
    ----------
    wcsobj : `~gwcs.WCS`
        A WCS object for the all open slitlets in an observation.
    quadrant : int
        MSA Quadrant number.
    slit : int
        Slit id within this quadrant.
    wavelength_range: list
        Wavelength range for the combination of fliter and grating.

    Returns
    -------
    wcsobj : `~gwcs.wcs.WCS`
        WCS object for this slit.
    """
    import copy  # TODO: Add a copy method to gwcs.WCS
    slit = slitid_to_slit(np.array([(quadrant, slitid)]))[0]
    slit_wcs = copy.deepcopy(wcsobj)
    #slit_wcs.set_transform('detector', 'gwa', wcsobj.pipeline[0][1][1:])
    slit_wcs.set_transform('detector', 'gwa', wcsobj.pipeline[0][1])
    slit_wcs.set_transform('gwa', 'slit_frame',
                           wcsobj.pipeline[1][1].models[slit])
    slit_wcs.set_transform('slit_frame', 'msa_frame',
                           wcsobj.pipeline[2][1][1].models[slit] & Identity(1))

    slit2detector = slit_wcs.get_transform('slit_frame', 'detector')

    domain = compute_domain(slit2detector, wavelength_range)
    slit_wcs.domain = domain
    return slit_wcs
Beispiel #13
0
def ifu(input_model, reference_files):
    """
    IFU pipeline
    """
    slits = np.arange(30)
    # Get the corrected disperser model
    disperser = get_disperser(input_model, reference_files['disperser'])

    # Get the default spectral order and wavelength range and record them in the model.
    sporder, wrange = get_spectral_order_wrange(
        input_model, reference_files['wavelengthrange'])
    input_model.meta.wcsinfo.waverange_start = wrange[0]
    input_model.meta.wcsinfo.waverange_end = wrange[1]
    input_model.meta.wcsinfo.spectral_order = sporder

    # DMS to SCA transform
    dms2detector = dms_to_sca(input_model)
    # DETECTOR to GWA transform
    det2gwa = Identity(2) & detector_to_gwa(
        reference_files, input_model.meta.instrument.detector, disperser)

    # GWA to SLIT
    gwa2slit = gwa_to_ifuslit(slits, disperser, wrange, sporder,
                              reference_files)

    # SLIT to MSA transform
    slit2msa = ifuslit_to_msa(slits, reference_files)

    det, sca, gwa, slit_frame, msa_frame, oteip, v2v3, world = create_frames()
    if input_model.meta.instrument.filter != 'OPAQUE':
        # MSA to OTEIP transform
        msa2oteip = ifu_msa_to_oteip(reference_files)

        # OTEIP to V2,V3 transform
        # This includes a wavelength unit conversion from meters to microns.
        oteip2v23 = oteip_to_v23(reference_files)

        # Create coordinate frames in the NIRSPEC WCS pipeline"
        #
        # The oteip2v2v3 transform converts the wavelength from meters (which is assumed
        # in the whole pipeline) to microns (which is the expected output)
        #
        # "detector", "gwa", "slit_frame", "msa_frame", "oteip", "v2v3", "world"

        pipeline = [(det, dms2detector), (sca, det2gwa.rename('detector2gwa')),
                    (gwa, gwa2slit.rename('gwa2slit')),
                    (slit_frame, (Mapping(
                        (0, 1, 2, 3, 4)) | slit2msa).rename('slit2msa')),
                    (msa_frame, msa2oteip.rename('msa2oteip')),
                    (oteip, oteip2v23.rename('oteip2v23')), (v2v3, None)]
    else:

        pipeline = [(det, dms2detector), (sca, det2gwa.rename('detector2gwa')),
                    (gwa, gwa2slit.rename('gwa2slit')),
                    (slit_frame, (Mapping(
                        (0, 1, 2, 3, 4)) | slit2msa).rename('slit2msa')),
                    (msa_frame, None)]

    return pipeline
Beispiel #14
0
def spatial_like_model():
    crpix1, crpix2 = (100, 100) * u.pix
    cdelt1, cdelt2 = (10, 10) * (u.arcsec / u.pix)

    shiftu = Shift(-crpix1) & Shift(-crpix2)
    scale = Multiply(cdelt1) & Multiply(cdelt2)

    return (shiftu | scale | Pix2Sky_AZP()) & Identity(1)
Beispiel #15
0
def test_snell_sellmeier_combined(sellmeier_glass):
    fromdircos = geometry.FromDirectionCosines()
    todircos = geometry.ToDirectionCosines()
    model = sellmeier_glass & todircos | sp.Snell3D() & Identity(
        1) | fromdircos

    expected = (0.07013833805527926, 0.07013833805527926, 1.0050677723764139)
    assert_allclose(model(2, .1, .1, .9), expected)
Beispiel #16
0
def _make_reference_gwcs_wcs(fits_hdr):
    hdr = fits.Header.fromfile(get_pkg_data_filename(fits_hdr))
    fw = fitswcs.WCS(hdr)

    unit_conv = Scale(1.0 / 3600.0, name='arcsec_to_deg_1D')
    unit_conv = unit_conv & unit_conv
    unit_conv.name = 'arcsec_to_deg_2D'

    unit_conv_inv = Scale(3600.0, name='deg_to_arcsec_1D')
    unit_conv_inv = unit_conv_inv & unit_conv_inv
    unit_conv_inv.name = 'deg_to_arcsec_2D'

    c2s = CartesianToSpherical(name='c2s', wrap_lon_at=180)
    s2c = SphericalToCartesian(name='s2c', wrap_lon_at=180)
    c2tan = ((Mapping((0, 1, 2), name='xyz') / Mapping(
        (0, 0, 0), n_inputs=3, name='xxx')) | Mapping((1, 2), name='xtyt'))
    c2tan.name = 'Cartesian 3D to TAN'

    tan2c = (Mapping((0, 0, 1), n_inputs=2, name='xtyt2xyz') |
             (Const1D(1, name='one') & Identity(2, name='I(2D)')))
    tan2c.name = 'TAN to cartesian 3D'

    tan2c.inverse = c2tan
    c2tan.inverse = tan2c

    aff = AffineTransformation2D(matrix=fw.wcs.cd)

    offx = Shift(-fw.wcs.crpix[0])
    offy = Shift(-fw.wcs.crpix[1])

    s = 5e-6
    scale = Scale(s) & Scale(s)

    det2tan = (offx & offy) | scale | tan2c | c2s | unit_conv_inv

    taninv = s2c | c2tan
    tan = Pix2Sky_TAN()
    n2c = RotateNative2Celestial(fw.wcs.crval[0], fw.wcs.crval[1], 180)
    wcslin = unit_conv | taninv | scale.inverse | aff | tan | n2c

    sky_frm = cf.CelestialFrame(reference_frame=coord.ICRS())
    det_frm = cf.Frame2D(name='detector')
    v2v3_frm = cf.Frame2D(name="v2v3",
                          unit=(u.arcsec, u.arcsec),
                          axes_names=('x', 'y'),
                          axes_order=(0, 1))
    pipeline = [(det_frm, det2tan), (v2v3_frm, wcslin), (sky_frm, None)]

    gw = gwcs.WCS(input_frame=det_frm,
                  output_frame=sky_frm,
                  forward_transform=pipeline)
    gw.crpix = fw.wcs.crpix
    gw.crval = fw.wcs.crval
    gw.bounding_box = ((-0.5, fw.pixel_shape[0] - 0.5),
                       (-0.5, fw.pixel_shape[1] - 0.5))

    return gw
Beispiel #17
0
def dva_corr_model(va_scale, v2_ref, v3_ref):
    """
    Create transformation that accounts for differential velocity aberration
    (scale).

    Parameters
    ----------
    va_scale : float, None
        Ratio of the apparent plate scale to the true plate scale. When
        ``va_scale`` is `None`, it is assumed to be identical to ``1`` and
        an ``astropy.modeling.models.Identity`` model will be returned.

    v2_ref : float, None
        Telescope ``v2`` coordinate of the reference point in ``arcsec``. When
        ``v2_ref`` is `None`, it is assumed to be identical to ``0``.

    v3_ref : float, None
        Telescope ``v3`` coordinate of the reference point in ``arcsec``. When
        ``v3_ref`` is `None`, it is assumed to be identical to ``0``.

    Returns
    -------
    va_corr : astropy.modeling.CompoundModel, astropy.modeling.models.Identity
        A 2D compound model that corrects DVA. If ``va_scale`` is `None` or 1
        then `astropy.modeling.models.Identity` will be returned.

    """
    if va_scale is None or va_scale == 1:
        return Identity(2)

    if va_scale <= 0:
        raise ValueError(
            "'Velocity aberration scale must be a positive number.")

    va_corr = Scale(va_scale, name='dva_scale_v2') & Scale(va_scale,
                                                           name='dva_scale_v3')

    if v2_ref is None:
        v2_ref = 0

    if v3_ref is None:
        v3_ref = 0

    if v2_ref == 0 and v3_ref == 0:
        return va_corr

    # NOTE: it is assumed that v2, v3 angles and va scale are small enough
    # so that for expected scale factors the issue of angle wrapping
    # (180 degrees) can be neglected.
    v2_shift = (1 - va_scale) * v2_ref
    v3_shift = (1 - va_scale) * v3_ref

    va_corr |= Shift(v2_shift, name='dva_v2_shift') & Shift(
        v3_shift, name='dva_v3_shift')
    va_corr.name = 'DVA_Correction'
    return va_corr
Beispiel #18
0
def test_fittable_compound():
    m = Identity(1) | Mapping((0, )) | Gaussian1D(1, 5, 4)
    x = np.arange(10)
    y_real = m(x)
    dy = 0.005
    with NumpyRNGContext(1234567):
        n = np.random.normal(0., dy, x.shape)
    y_noisy = y_real + n
    pfit = LevMarLSQFitter()
    new_model = pfit(m, x, y_noisy)
    y_fit = new_model(x)
    assert_allclose(y_fit, y_real, atol=dy)
Beispiel #19
0
def gwcs_1d():
    detector_frame = cf.CoordinateFrame(
        name="detector",
        naxes=1,
        axes_order=(0, ),
        axes_type=("pixel"),
        axes_names=("x"),
        unit=(u.pix))

    spec_frame = cf.SpectralFrame(name="spectral", axes_order=(2, ), unit=u.nm)

    return WCS(forward_transform=Identity(1), input_frame=detector_frame, output_frame=spec_frame)
Beispiel #20
0
def oteip_to_v23(reference_files):
    """
    Transform from the OTEIP frame to the V2V3 frame.

    Parameters
    ----------
    reference_files: dict
        Dictionary with reference files returned by CRDS.

    Returns
    -------
    model : `~astropy.modeling.core.Model` model.
        Transform from OTEIP to V2V3.

    """
    with AsdfFile.open(reference_files['ote']) as f:
        ote = f.tree['model'].copy()
    fore2ote_mapping = Identity(3, name='fore2ote_mapping')
    fore2ote_mapping.inverse = Mapping((0, 1, 2, 2))
    # Convert the wavelength to microns
    return fore2ote_mapping | (ote & Identity(1) / Const1D(1e-6))
Beispiel #21
0
def test_dont_drop_one_half(spatial_like):
    """
    Test the situation where we are not just dropping one half of the tree.
    """
    spatial_like = spatial_like & Identity(1)
    tree = spatial_like._tree
    ginp_map = make_tree_input_map(tree)
    r_ginp_map = {tuple(v): k for k, v in ginp_map.items()}

    trees = remove_input_frame(tree, "x01")
    assert r_ginp_map[("x0", )] in trees
    assert tree.left not in trees
Beispiel #22
0
def assign_moving_target_wcs(input_model):

    if not isinstance(input_model, datamodels.ModelContainer):
        raise ValueError("Expected a ModelContainer object")

    # Get the MT RA/Dec values from all the input exposures
    mt_ra = np.array(
        [model.meta.wcsinfo.mt_ra for model in input_model._models])
    mt_dec = np.array(
        [model.meta.wcsinfo.mt_dec for model in input_model._models])

    # Compute the mean MT RA/Dec over all exposures
    if (None in mt_ra) or (None in mt_dec):
        log.warning("One or more MT RA/Dec values missing in input images")
        log.warning("Step will be skipped, resulting in target misalignment")
        for model in input_model:
            model.meta.cal_step.assign_mtwcs = 'SKIPPED'
        return input_model
    else:
        mt_avra = mt_ra.mean()
        mt_avdec = mt_dec.mean()

    for model in input_model:
        pipeline = model.meta.wcs._pipeline[:-1]

        mt = deepcopy(model.meta.wcs.output_frame)
        mt.name = 'moving_target'

        mt_ra = model.meta.wcsinfo.mt_ra
        mt_dec = model.meta.wcsinfo.mt_dec
        model.meta.wcsinfo.mt_avra = mt_avra
        model.meta.wcsinfo.mt_avdec = mt_avdec

        rdel = mt_avra - mt_ra
        ddel = mt_avdec - mt_dec

        if isinstance(mt, cf.CelestialFrame):
            transform_to_mt = Shift(rdel) & Shift(ddel)
        elif isinstance(mt, cf.CompositeFrame):
            transform_to_mt = Shift(rdel) & Shift(ddel) & Identity(1)
        else:
            raise ValueError("Unrecognized coordinate frame.")

        pipeline.append((model.meta.wcs.output_frame, transform_to_mt))
        pipeline.append((mt, None))
        new_wcs = WCS(pipeline)
        del model.meta.wcs
        model.meta.wcs = new_wcs
        model.meta.cal_step.assign_mtwcs = 'COMPLETE'

    return input_model
Beispiel #23
0
    def _v2v3_to_tpcorr_from_full(tpcorr):
        s2c = tpcorr['s2c']
        c2s = tpcorr['c2s']

        # unit_conv = _get_submodel(tpcorr, 'arcsec_to_deg_2D')
        # unit_conv_inv = _get_submodel(tpcorr, 'deg_to_arcsec_2D')
        #
        # The code below is a work-around to the code above not working.
        # TODO: understand why _get_submodel is unable to retrieve
        #       some submodels in a compound model.
        #
        unit_conv = _get_submodel(tpcorr, 'arcsec_to_deg_1D')
        unit_conv = unit_conv & unit_conv
        unit_conv.name = 'arcsec_to_deg_2D'
        unit_conv_inv = _get_submodel(tpcorr, 'deg_to_arcsec_1D')
        unit_conv_inv = unit_conv_inv & unit_conv_inv
        unit_conv_inv.name = 'deg_to_arcsec_2D'

        affine = tpcorr['tp_affine']
        affine_inv = affine.inverse
        affine_inv.name = 'tp_affine_inv'

        rot = tpcorr['det_to_optic_axis']
        rot_inv = rot.inverse
        rot_inv.name = 'optic_axis_to_det'

        # c2tan = _get_submodel(tpcorr, 'Cartesian 3D to TAN')
        # tan2c = _get_submodel(tpcorr, 'TAN to cartesian 3D')
        #
        # The code below is a work-around to the code above not working.
        # TODO: understand why _get_submodel is unable to retrieve
        #       some submodels in a compound model.
        #
        c2tan = ((Mapping((0, 1, 2), name='xyz') / Mapping(
            (0, 0, 0), n_inputs=3, name='xxx')) | Mapping((1, 2), name='xtyt'))
        c2tan.name = 'Cartesian 3D to TAN'
        tan2c = (Mapping((0, 0, 1), n_inputs=2, name='xtyt2xyz') |
                 (Const1D(1, name='one') & Identity(2, name='I(2D)')))
        tan2c.name = 'TAN to cartesian 3D'

        v2v3_to_tpcorr = unit_conv | s2c | rot | c2tan | affine
        v2v3_to_tpcorr.name = 'jwst_v2v3_to_tpcorr'

        tpcorr_to_v2v3 = affine_inv | tan2c | rot_inv | c2s | unit_conv_inv
        tpcorr_to_v2v3.name = 'jwst_tpcorr_to_v2v3'

        v2v3_to_tpcorr.inverse = tpcorr_to_v2v3
        tpcorr_to_v2v3.inverse = v2v3_to_tpcorr

        return v2v3_to_tpcorr
Beispiel #24
0
def test_identity_input():
    """
    Test a case where an Identity (or Mapping) model is the first in a chain
    of composite models and thus is responsible for handling input broadcasting
    properly.

    Regression test for https://github.com/astropy/astropy/pull/3362
    """

    ident1 = Identity(1)
    shift = Shift(1)
    rotation = Rotation2D(angle=90)
    model = ident1 & shift | rotation
    assert_allclose(model(1, 2), [-3.0, 1.0])
Beispiel #25
0
def test_identity():
    x = np.zeros((2, 3))
    y = np.ones((2, 3))

    ident1 = Identity(1)
    shift = Shift(1)
    rotation = Rotation2D(angle=60)
    model = ident1 & shift | rotation
    assert_allclose(model(1, 2), (-2.098076211353316, 2.3660254037844393))
    res_x, res_y = model(x, y)
    assert_allclose((res_x, res_y),
                    (np.array([[-1.73205081, -1.73205081, -1.73205081],
                               [-1.73205081, -1.73205081, -1.73205081]
                               ]), np.array([[1., 1., 1.], [1., 1., 1.]])))
    assert_allclose(model.inverse(res_x, res_y), (x, y), atol=1.e-10)
Beispiel #26
0
def nrs_wcs_set_input(input_model, slit_name, wavelength_range=None):
    """
    Returns a WCS object for this slit.

    Parameters
    ----------
    input_model : `~jwst.datamodels.DataModel`
        A WCS object for the all open slitlets in an observation.
    slit_name : int or str
        Slit.name of an open slit.
    wavelength_range: list
        Wavelength range for the combination of fliter and grating.

    Returns
    -------
    wcsobj : `~gwcs.wcs.WCS`
        WCS object for this slit.
    """
    import copy  # TODO: Add a copy method to gwcs.WCS
    wcsobj = input_model.meta.wcs
    if wavelength_range is None:
        _, wrange = spectral_order_wrange_from_model(input_model)
    else:
        wrange = wavelength_range
    slit_wcs = copy.deepcopy(wcsobj)
    slit_wcs.set_transform('sca', 'gwa', wcsobj.pipeline[1][1][1:])
    # get the open slits from the model
    # Need them to get the slit ymin,ymax
    g2s = wcsobj.pipeline[2][1]
    open_slits = g2s.slits

    slit_wcs.set_transform('gwa', 'slit_frame', g2s.get_model(slit_name))
    slit_wcs.set_transform(
        'slit_frame', 'msa_frame',
        wcsobj.pipeline[3][1][1].get_model(slit_name) & Identity(1))
    slit2detector = slit_wcs.get_transform('slit_frame', 'detector')

    if input_model.meta.exposure.type.lower() != 'nrs_ifu':
        slit = [s for s in open_slits if s.name == slit_name][0]
        domain = compute_domain(slit2detector,
                                wrange,
                                slit_ymin=slit.ymin,
                                slit_ymax=slit.ymax)
    else:
        domain = compute_domain(slit2detector, wrange)
    slit_wcs.domain = domain
    return slit_wcs
Beispiel #27
0
    def _tpcorr_init(v2_ref, v3_ref, roll_ref):
        s2c = SphericalToCartesian(name='s2c', wrap_lon_at=180)
        c2s = CartesianToSpherical(name='c2s', wrap_lon_at=180)

        unit_conv = Scale(1.0 / 3600.0, name='arcsec_to_deg_1D')
        unit_conv = unit_conv & unit_conv
        unit_conv.name = 'arcsec_to_deg_2D'

        unit_conv_inv = Scale(3600.0, name='deg_to_arcsec_1D')
        unit_conv_inv = unit_conv_inv & unit_conv_inv
        unit_conv_inv.name = 'deg_to_arcsec_2D'

        affine = AffineTransformation2D(name='tp_affine')
        affine_inv = AffineTransformation2D(name='tp_affine_inv')

        rot = RotationSequence3D([v2_ref, -v3_ref, roll_ref],
                                 'zyx',
                                 name='det_to_optic_axis')
        rot_inv = rot.inverse
        rot_inv.name = 'optic_axis_to_det'

        # projection submodels:
        c2tan = ((Mapping((0, 1, 2), name='xyz') / Mapping(
            (0, 0, 0), n_inputs=3, name='xxx')) | Mapping((1, 2), name='xtyt'))
        c2tan.name = 'Cartesian 3D to TAN'
        tan2c = (Mapping((0, 0, 1), n_inputs=2, name='xtyt2xyz') |
                 (Const1D(1, name='one') & Identity(2, name='I(2D)')))
        tan2c.name = 'TAN to cartesian 3D'

        total_corr = (unit_conv | s2c | rot | c2tan | affine | tan2c | rot_inv
                      | c2s | unit_conv_inv)
        total_corr.name = 'JWST tangent-plane linear correction. v1'

        inv_total_corr = (unit_conv | s2c | rot | c2tan | affine_inv | tan2c
                          | rot_inv | c2s | unit_conv_inv)
        inv_total_corr.name = 'Inverse JWST tangent-plane linear correction. v1'

        # TODO
        # re-enable circular inverse definitions once
        # https://github.com/spacetelescope/asdf/issues/744 or
        # https://github.com/spacetelescope/asdf/issues/745 are resolved.
        #
        # inv_total_corr.inverse = total_corr
        total_corr.inverse = inv_total_corr

        return total_corr
Beispiel #28
0
def ifu(input_model, reference_files):
    """
    IFU pipeline
    """
    slits = np.arange(30)
    # Get the corrected disperser model
    disperser = get_disperser(input_model, reference_files['disperser'])

    # Get the default spectral order and wavelength range and record them in the model.
    sporder, wrange = get_spectral_order_wrange(
        input_model, reference_files['wavelengthrange'])
    input_model.meta.wcsinfo.waverange_start = wrange[0]
    input_model.meta.wcsinfo.waverange_end = wrange[1]
    input_model.meta.wcsinfo.spectral_order = sporder

    # DETECTOR to GWA transform
    det2gwa = Identity(2) & detector_to_gwa(
        reference_files, input_model.meta.instrument.detector, disperser)

    # GWA to SLIT
    gwa2slit = gwa_to_ifuslit(slits, disperser, wrange, sporder,
                              reference_files)

    # SLIT to MSA transform
    slit2msa = ifuslit_to_msa(slits, reference_files)

    # MSA to OTEIP transform
    msa2oteip = ifu_msa_to_oteip(reference_files)

    # OTEIP to V2,V3 transform
    oteip2v23 = oteip_to_v23(reference_files)

    # Create coordinate frames in the NIRSPEC WCS pipeline"
    # "detector", "gwa", "slit_frame", "msa_frame", "oteip", "v2v3", "world"
    det, gwa, slit_frame, msa_frame, oteip, v2v3 = create_frames()
    pipeline = [(det, det2gwa.rename('detector2gwa')),
                (gwa, gwa2slit.rename('gwa2slit')),
                (slit_frame, (Mapping(
                    (0, 1, 2, 3, 4)) | slit2msa).rename('slit2msa')),
                (msa_frame, msa2oteip.rename('msa2oteip')),
                (oteip, oteip2v23.rename('oteip2v23')), (v2v3, None)]

    return pipeline
Beispiel #29
0
    def from_tree_transform(cls, node, ctx):
        mapping = node['mapping']
        n_inputs = node.get('n_inputs')
        if all([isinstance(x, int) for x in mapping]):
            return Mapping(tuple(mapping), n_inputs)

        if n_inputs is None:
            n_inputs = max([x for x in mapping if isinstance(x, int)]) + 1

        transform = Identity(n_inputs)
        new_mapping = []
        i = n_inputs
        for entry in mapping:
            if isinstance(entry, int):
                new_mapping.append(entry)
            else:
                new_mapping.append(i)
                transform = transform & Const1D(entry.value)
                i += 1
        return transform | Mapping(new_mapping)
Beispiel #30
0
def assign_moving_target_wcs(input_model):

    if not isinstance(input_model, datamodels.ModelContainer):
        raise ValueError("Expected a ModelContainer object")

    mt_ra = np.array(
        [model.meta.wcsinfo.mt_ra for model in input_model._models])
    mt_dec = np.array(
        [model.meta.wcsinfo.mt_dec for model in input_model._models])
    mt_avra = mt_ra.mean()
    mt_avdec = mt_dec.mean()

    for model in input_model:
        pipeline = model.meta.wcs._pipeline[:-1]

        mt = deepcopy(model.meta.wcs.output_frame)
        mt.name = 'moving_target'

        mt_ra = model.meta.wcsinfo.mt_ra
        mt_dec = model.meta.wcsinfo.mt_dec
        model.meta.wcsinfo.mt_avra = mt_avra
        model.meta.wcsinfo.mt_avdec = mt_avdec

        rdel = mt_avra - mt_ra
        ddel = mt_avdec - mt_dec

        if isinstance(mt, cf.CelestialFrame):
            transform_to_mt = Shift(rdel) & Shift(ddel)
        elif isinstance(mt, cf.CompositeFrame):
            transform_to_mt = Shift(rdel) & Shift(ddel) & Identity(1)
        else:
            raise ValueError("Unrecognized coordinate frame.")
        pipeline.append((model.meta.wcs.output_frame, transform_to_mt))
        pipeline.append((mt, None))
        new_wcs = WCS(pipeline)
        del model.meta.wcs
        model.meta.wcs = new_wcs
        model.meta.cal_step.assign_mtwcs = 'COMPLETE'
    return input_model