def test_slicing_on_instances_3():
    """
    Like `test_slicing_on_instances_2` but uses a compound model that does not
    have any invalid slices due to the resulting model being invalid
    (originally test_slicing_on_instances_2 passed without any
    ModelDefinitionErrors being raised, but that was before we prevented
    invalid models from being created).
    """

    model_a = Shift(1, name='a')
    model_b = Shift(2, name='b')
    model_c = Gaussian1D(3, 0, 0.1, name='c')
    model_d = Scale(2, name='d')
    model_e = Scale(3, name='e')

    m = (model_a + model_b) | model_c | (model_d + model_e)

    assert m[1:].submodel_names == ('b', 'c', 'd', 'e')
    assert m[:].submodel_names == ('a', 'b', 'c', 'd', 'e')
    assert m['a':].submodel_names == ('a', 'b', 'c', 'd', 'e')
    assert m['c':'d'].submodel_names == ('c', 'd')
    assert m[1:2].name == 'b'
    assert m[2:7].submodel_names == ('c', 'd', 'e')
    with pytest.raises(IndexError):
        m['x']
    with pytest.raises(IndexError):
        m['a':'r']
    assert m[-4:4].submodel_names == ('b', 'c', 'd')
    assert m[-4:-2].submodel_names == ('b', 'c')
def test_compound_model_with_nonstandard_broadcasting():
    """
    Ensure that the ``standard_broadcasting`` flag is properly propagated when
    creating compound models.

    See the commit message for the commit in which this was added for more
    details.
    """

    offx = Shift(1)
    offy = Shift(2)
    rot = AffineTransformation2D([[0, -1], [1, 0]])
    m = (offx & offy) | rot

    x, y = m(0, 0)
    assert x == -2
    assert y == 1

    # make sure conversion back to scalars is working properly
    assert isinstance(x, float)
    assert isinstance(y, float)

    x, y = m([0, 1, 2], [0, 1, 2])
    assert np.all(x == [-2, -3, -4])
    assert np.all(y == [1, 2, 3])
def test_slicing_on_instance_with_parameterless_model():
    """
    Regression test to fix an issue where the indices attached to parameter
    names on a compound model were not handled properly when one or more
    submodels have no parameters.  This was especially evident in slicing.
    """

    p2 = Polynomial2D(1, c0_0=1, c1_0=2, c0_1=3)
    p1 = Polynomial2D(1, c0_0=1, c1_0=2, c0_1=3)
    mapping = Mapping((0, 1, 0, 1))
    offx = Shift(-2, name='x_translation')
    offy = Shift(-1, name='y_translation')
    aff = AffineTransformation2D(matrix=[[1, 2], [3, 4]], name='rotation')
    model = mapping | (p1 & p2) | (offx & offy) | aff

    assert model.param_names == ('c0_0_1', 'c1_0_1', 'c0_1_1',
                                 'c0_0_2', 'c1_0_2', 'c0_1_2',
                                 'offset_3', 'offset_4',
                                 'matrix_5', 'translation_5')
    assert model(1, 2) == (23.0, 53.0)

    m = model[3:]
    assert m.param_names == ('offset_3', 'offset_4', 'matrix_5',
                             'translation_5')
    assert m(1, 2) == (1.0, 1.0)
Exemple #4
0
def get_refpix(siaf_instance, apername):
    """Return the reference location within the given aperture

    Parameters
    ----------
    siaf_instance : pysiaf.Siaf('nircam')
    """
    siaf_aperture = siaf_instance[apername]
    xref = siaf_aperture.XSciRef
    yref = siaf_aperture.YSciRef
    #return Shift(-xref) & Shift(-yref)

    # Check to see if we can use coeffs from a subarray aperture
    # and have them apply to all apertures. Need to update the shift
    # in that case by adding the distance from detector (0, 0) to the
    # lower left corner of the aperture
    #siaf = pysiaf.Siaf('nircam')
    xc, yc = sci_subarray_corners('nircam',
                                  apername,
                                  siaf=siaf_instance,
                                  verbose=False)
    llx, urx = xc
    lly, ury = yc
    print('Lower left corner x and y:', llx, lly)

    return Shift(-xref - llx) & Shift(-yref - lly)
Exemple #5
0
def compute_spec_transform(fiducial, refwcs):
    """
    Compute a simple transform given a fidicial point in a spatial-spectral wcs.
    """
    cdelt1 = refwcs.wcsinfo.cdelt1 / 3600.
    cdelt2 = refwcs.wcsinfo.cdelt2 / 3600.
    cdelt3 = refwcs.wcsinfo.cdelt3
    roll_ref = refwcs.wcsinfo.roll_ref

    y, x = grid_from_spec_domain(refwcs)
    ra, dec, lam = refwcs(x, y)

    min_lam = np.nanmin(lam)

    offset = Shift(0.) & Shift(0.)
    rot = Rotation2D(roll_ref)
    scale = Scale(cdelt1) & Scale(cdelt2)
    tan = Pix2Sky_TAN()
    skyrot = RotateNative2Celestial(fiducial[0][0], fiducial[0][1], 180.0)
    spatial = offset | rot | scale | tan | skyrot
    spectral = Scale(cdelt3) | Shift(min_lam)
    mapping = Mapping((1, 1, 0), )
    mapping.inverse = Mapping((2, 1))
    transform = mapping | spatial & spectral
    transform.outputs = ('ra', 'dec', 'lamda')
    return transform
def test_compound_input_units_equivalencies():
    """
    Test setting input_units_equivalencies on one of the models.
    """

    s1 = Shift(10 * u.deg)
    s1.input_units_equivalencies = {'x': u.pixel_scale(0.5 * u.deg / u.pix)}
    s2 = Shift(10 * u.deg)
    sp = Shift(10 * u.pix)

    cs = s1 | s2

    out = cs(10 * u.pix)
    assert_quantity_allclose(out, 25 * u.deg)

    cs = sp | s1

    out = cs(10 * u.pix)
    assert_quantity_allclose(out, 20 * u.deg)

    cs = s1 & s2
    cs = cs.rename('TestModel')
    out = cs(20 * u.pix, 10 * u.deg)
    assert_quantity_allclose(out, 20 * u.deg)

    with pytest.raises(UnitsError) as exc:
        out = cs(20 * u.pix, 10 * u.pix)
    assert exc.value.args[
        0] == "TestModel: Units of input 'x1', pix (unknown), could not be converted to required input units of deg (angle)"
def test_compound_input_units_equivalencies():
    """
    Test setting input_units_equivalencies on one of the models.
    """

    s1 = Shift(10 * u.deg)
    s1.input_units_equivalencies = {'x': u.pixel_scale(0.5 * u.deg / u.pix)}
    s2 = Shift(10 * u.deg)
    sp = Shift(10 * u.pix)

    cs = s1 | s2

    out = cs(10 * u.pix)
    assert_quantity_allclose(out, 25 * u.deg)

    cs = sp | s1

    out = cs(10 * u.pix)
    assert_quantity_allclose(out, 20 * u.deg)

    cs = s1 & s2
    cs = cs.rename('TestModel')
    out = cs(20 * u.pix, 10 * u.deg)
    assert_quantity_allclose(out, 20 * u.deg)

    with pytest.raises(UnitsError) as exc:
        out = cs(20 * u.pix, 10 * u.pix)
    assert exc.value.args[0] == "TestModel: Units of input 'x1', pix (unknown), could not be converted to required input units of deg (angle)"
Exemple #8
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)
Exemple #9
0
def test_basic_compound_inverse():
    """
    Test basic inversion of compound models in the limited sense supported for
    models made from compositions and joins only.
    """

    t = (Shift(2) & Shift(3)) | (Scale(2) & Scale(3)) | Rotation2D(90)
    assert_allclose(t.inverse(*t(0, 1)), (0, 1))
Exemple #10
0
def wcs_from_spec_footprints(wcslist,
                             refwcs=None,
                             transform=None,
                             domain=None):
    """
    Create a WCS from a list of spatial/spectral WCS.

    Build-7 workaround.
    """
    if not isiterable(wcslist):
        raise ValueError("Expected 'wcslist' to be an iterable of gwcs.WCS")
    if not all([isinstance(w, WCS) for w in wcslist]):
        raise TypeError(
            "All items in 'wcslist' must have instance of gwcs.WCS")
    if refwcs is None:
        refwcs = wcslist[0]
    else:
        if not isinstance(refwcs, WCS):
            raise TypeError("Expected refwcs to be an instance of gwcs.WCS.")

    # TODO: generalize an approach to do this for more than one wcs.  For
    # now, we just do it for one, using the api for a list of wcs.
    # Compute a fiducial point for the output frame at center of input data
    fiducial = compute_spec_fiducial(wcslist, domain=domain)
    # Create transform for output frame
    transform = compute_spec_transform(fiducial, refwcs)
    output_frame = refwcs.output_frame
    wnew = WCS(output_frame=output_frame, forward_transform=transform)

    # Build the domain in the output frame wcs object by running the input wcs
    # footprints through the backward transform of the output wcs
    sky = [spec_footprint(w) for w in wcslist]
    domain_grid = [wnew.backward_transform(*f) for f in sky]

    sky0 = sky[0]
    det = domain_grid[0]
    offsets = []
    input_frame = refwcs.input_frame
    for axis in input_frame.axes_order:
        axis_min = np.nanmin(det[axis])
        offsets.append(axis_min)
    transform = Shift(offsets[0]) & Shift(offsets[1]) | transform
    wnew = WCS(output_frame=output_frame,
               input_frame=input_frame,
               forward_transform=transform)

    domain = []
    for axis in input_frame.axes_order:
        axis_min = np.nanmin(domain_grid[0][axis])
        axis_max = np.nanmax(domain_grid[0][axis]) + 1
        domain.append({
            'lower': axis_min,
            'upper': axis_max,
            'includes_lower': True,
            'includes_upper': False
        })
    wnew.domain = domain
    return wnew
Exemple #11
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
Exemple #12
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
Exemple #13
0
def test_regions_selector(tmpdir):
    m1 = Mapping([0, 1, 1]) | Shift(1) & Shift(2) & Shift(3)
    m2 = Mapping([0, 1, 1]) | Scale(2) & Scale(3) & Scale(3)
    sel = {1: m1, 2: m2}
    a = np.zeros((5, 6), dtype=np.int32)
    a[:, 1:3] = 1
    a[:, 4:5] = 2
    mask = selector.LabelMapperArray(a)
    rs = selector.RegionsSelector(inputs=('x', 'y'), outputs=('ra', 'dec', 'lam'),
                                  selector=sel, label_mapper=mask)
    assert_selector_roundtrip(rs, tmpdir)
def test_compound_incompatible_units_fail():
    """
    Test incompatible model units in chain.
    """
    s1 = Shift(10 * u.pix)
    s2 = Shift(10 * u.deg)

    cs = s1 | s2

    with pytest.raises(UnitsError):
        cs(10 * u.pix)
Exemple #15
0
def test_replace_submodel():
    """
    Replace a model in a Compound model
    """
    S1 = Shift(2, name='shift2') | Scale(
        3, name='scale3')  # First shift then scale
    S2 = Scale(2, name='scale2') | Shift(
        3, name='shift3')  # First scale then shift

    m = S1 & S2
    assert m(1, 2) == (9, 7)

    m2 = m.replace_submodel('scale3', Scale(4, name='scale4'))
    assert m2(1, 2) == (12, 7)
    assert m(1, 2) == (9, 7)
    # Check the inverse has been updated
    assert m2.inverse(12, 7) == (1, 2)

    # Produce the same result by replacing a single model with a compound
    m3 = m.replace_submodel('shift2', Shift(2) | Scale(2))
    assert m(1, 2) == (9, 7)
    assert m3(1, 2) == (18, 7)
    # Check the inverse has been updated
    assert m3.inverse(18, 7) == (1, 2)

    # Test with arithmetic model compunding operator
    m = S1 + S2
    assert m(1) == 14
    m2 = m.replace_submodel('scale2', Scale(4, name='scale4'))
    assert m2(1) == 16

    # Test with fix_inputs()
    R = fix_inputs(Rotation2D(angle=90, name='rotate'), {0: 1})
    m4 = S1 | R
    assert_allclose(m4(0), (-6, 1))

    m5 = m4.replace_submodel('rotate', Rotation2D(180))
    assert_allclose(m5(0), (-1, -6))

    # Check we get a value error when model name doesn't exist
    with pytest.raises(ValueError):
        m2 = m.replace_submodel('not_there', Scale(2))

    # And now a model set
    P = Polynomial1D(degree=1, n_models=2, name='poly')
    S = Shift([1, 2], n_models=2)
    m = P | S
    assert_array_equal(m([0, 1]), (1, 2))
    with pytest.raises(ValueError):
        m2 = m.replace_submodel('poly', Polynomial1D(degree=1, c0=1))
    m2 = m.replace_submodel('poly',
                            Polynomial1D(degree=1, c0=[1, 2], n_models=2))
    assert_array_equal(m2([0, 1]), (2, 4))
Exemple #16
0
def imaging_distortion(input_model, reference_files):
    """
    Create the "detector" to "v2v3" transform for imaging mode.

    Parameters
    ----------
    input_model : `~jwst.datamodel.DataModel`
        Input datamodel for processing
    reference_files : dict
        The dictionary of reference file names and their associated files.

    Returns
    -------
    The transform model

    """
    dist = DistortionModel(reference_files['distortion'])
    transform = dist.model

    try:
        bbox = transform.bounding_box
    except NotImplementedError:
        # Check if the transform in the reference file has a ``bounding_box``.
        # If not set a ``bounding_box`` equal to the size of the image after
        # assembling all distortion corrections.
        bbox = None
    dist.close()

    # Add an offset for the filter
    if reference_files['filteroffset'] is not None:
        obsfilter = input_model.meta.instrument.filter
        obspupil = input_model.meta.instrument.pupil
        with asdf.open(reference_files['filteroffset']) as filter_offset:
            filters = filter_offset.tree['filters']

        match_keys = {'filter': obsfilter, 'pupil': obspupil}
        row = find_row(filters, match_keys)
        if row is not None:
            col_offset = row.get('column_offset', 'N/A')
            row_offset = row.get('row_offset', 'N/A')
            log.debug(
                f"Offsets from filteroffset file are {col_offset}, {row_offset}"
            )
            if col_offset != 'N/A' and row_offset != 'N/A':
                transform = Shift(col_offset) & Shift(row_offset) | transform
        else:
            log.debug("No match in fitleroffset file.")
    if bbox is None:
        transform.bounding_box = transform_bbox_from_shape(
            input_model.data.shape)
    else:
        transform.bounding_box = bbox
    return transform
def test_compound_pipe_equiv_call():
    """
    Check that equivalencies work when passed to evaluate, for a chained model
    (which has one input).
    """
    s1 = Shift(10 * u.deg)
    s2 = Shift(10 * u.deg)

    cs = s1 | s2

    out = cs(10 * u.pix, equivalencies={'x': u.pixel_scale(0.5 * u.deg / u.pix)})
    assert_quantity_allclose(out, 25 * u.deg)
Exemple #18
0
def test_regions_selector(tmpdir):
    m1 = Mapping([0, 1, 1]) | Shift(1) & Shift(2) & Shift(3)
    m2 = Mapping([0, 1, 1]) | Scale(2) & Scale(3) & Scale(3)
    sel = {1:m1, 2:m2}
    a = np.zeros((5,6), dtype=np.int32)
    a[:, 1:3] = 1
    a[:, 4:5] = 2
    mask = selector.LabelMapperArray(a)
    rs = selector.RegionsSelector(inputs=('x', 'y'), outputs=('ra', 'dec', 'lam'),
                                  selector=sel, label_mapper=mask)
    tree = {'model': rs}
    helpers.assert_roundtrip_tree(tree, tmpdir, extensions=GWCSExtension())
def test_compound_input_units():
    """
    Test units to first model in chain.
    """
    s1 = Shift(10 * u.deg)
    s2 = Shift(10 * u.deg)

    cs = s1 | s2

    out = cs(10 * u.arcsecond)

    assert_quantity_allclose(out, 20 * u.deg + 10 * u.arcsec)
def test_update_parameters():
    offx = Shift(1)
    scl = Scale(2)
    m = offx | scl
    assert m(1) == 4

    offx.offset = 42
    assert m(1) == 86

    m.factor_1 = 100
    assert m(1) == 4300
    m2 = m | offx
    assert m2(1) == 4342
def test_and_input_units():
    """
    Test units to first model in chain.
    """
    s1 = Shift(10 * u.deg)
    s2 = Shift(10 * u.deg)

    cs = s1 & s2

    out = cs(10 * u.arcsecond, 20 * u.arcsecond)

    assert_quantity_allclose(out[0], 10 * u.deg + 10 * u.arcsec)
    assert_quantity_allclose(out[1], 10 * u.deg + 20 * u.arcsec)
def test_update_parameters():
    offx = Shift(1)
    scl = Scale(2)
    m = offx | scl
    assert (m(1) == 4)

    offx.offset = 42
    assert (m(1) == 4)

    m.factor_1 = 100
    assert (m(1) == 200)
    m2 = m | offx
    assert (m2(1) == 242)
Exemple #23
0
def test_update_parameters():
    offx = Shift(1)
    scl = Scale(2)
    m = offx | scl
    assert(m(1) == 4)

    offx.offset = 42
    assert(m(1) == 4)

    m.factor_1 = 100
    assert(m(1) == 200)
    m2 = m | offx
    assert(m2(1) == 242)
Exemple #24
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
Exemple #25
0
def test_is_wcs_correction_small(offset, is_good):
    path = os.path.join(os.path.dirname(__file__), "mosaic_long_i2d_gwcs.asdf")
    with asdf.open(path) as af:
        wcs = af.tree["wcs"]

    # Make a copy and add an offset at the end of the transform
    twcs = deepcopy(wcs)
    step = twcs.pipeline[0]
    step.transform = step.transform | Shift(offset) & Shift(offset)
    twcs.bounding_box = wcs.bounding_box

    step = TweakRegStep()

    assert step._is_wcs_correction_small(wcs, twcs) == is_good
def test_compound_and_equiv_call():
    """
    Check that equivalencies work when passed to evaluate, for a composite model
    with two inputs.
    """
    s1 = Shift(10 * u.deg)
    s2 = Shift(10 * u.deg)

    cs = s1 & s2

    out = cs(10 * u.pix, 10 * u.pix, equivalencies={'x0': u.pixel_scale(0.5 * u.deg / u.pix),
                                                    'x1': u.pixel_scale(0.5 * u.deg / u.pix)})
    assert_quantity_allclose(out[0], 15 * u.deg)
    assert_quantity_allclose(out[1], 15 * u.deg)
Exemple #27
0
def create_slit(model, x0, y0, order):
    """ Create a SlitModel representing a grism slit."""
    ymin = 0
    xmin = 0
    # ymax = 58
    # xmax = 1323
    model = Mapping((0, 1, 0, 0, 0)) | (Shift(xmin) & Shift(ymin) & Const1D(x0)
                                        & Const1D(y0) & Const1D(order)) | model
    wcsobj = wcs.WCS([('det', model), ('world', None)])
    wcsobj.bounding_box = ((20, 25), (800, 805))
    slit = SlitModel()
    slit.meta.wcs = wcsobj
    slit.source_xpos = x0
    slit.source_ypos = y0
    return slit
Exemple #28
0
def test_levmar2x2_multivariate():
    inputs = [np.array([10., 10., 20., 20.]), np.array([10., 20., 20., 10.])]
    outputs = [
        np.array([8.06101731, 0.98994949, 8.06101731, 15.13208512]),
        np.array([12.16223664, 19.23330445, 26.30437226, 19.23330445])
    ]
    rot = Rotation2D()
    rot.fittable = True
    model = (Shift() & Shift()) | rot
    fitter = linearfit._LevMarLSQFitter2x2()
    finfo = fitter(model, inputs, outputs)
    assert np.allclose(finfo.parameters,
                       np.array([4.3, -7.1, 45.]),
                       rtol=1e-5,
                       atol=1e-5)
Exemple #29
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
Exemple #30
0
def test_compound_custom_inverse():
    """
    Test that a compound model with a custom inverse has that inverse applied
    when the inverse of another model, of which it is a component, is computed.
    Regression test for https://github.com/astropy/astropy/issues/3542
    """

    poly = Polynomial1D(1, c0=1, c1=2)
    scale = Scale(1)
    shift = Shift(1)

    model1 = poly | scale
    model1.inverse = poly

    # model1 now has a custom inverse (the polynomial itself, ignoring the
    # trivial scale factor)
    model2 = shift | model1

    assert_allclose(model2.inverse(1), (poly | shift.inverse)(1))

    # Make sure an inverse is not allowed if the models were combined with the
    # wrong operator, or if one of the models doesn't have an inverse defined
    with pytest.raises(NotImplementedError):
        (shift + model1).inverse

    with pytest.raises(NotImplementedError):
        (model1 & poly).inverse
Exemple #31
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)
Exemple #32
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
Exemple #33
0
def offset_wcs(slit_wcs):
    """
    Prepend a Shift transform to the slit WCS to account for subarrays.

    Parameters
    ----------
    slit_wcs : `~gwcs.wcs.WCS`
        The WCS for this  slit.
    slit_name : str
        The name of the slit.
    """
    xlo, xhi = _toindex(slit_wcs.bounding_box[0])
    ylo, yhi = _toindex(slit_wcs.bounding_box[1])

    # Add the slit offset to each slit WCS object
    tr = slit_wcs.get_transform('detector', 'sca')
    tr = Shift(xlo) & Shift(ylo) | tr
    slit_wcs.set_transform('detector', 'sca', tr.rename('dms2sca'))

    return xlo, xhi, ylo, yhi
Exemple #34
0
    def build_miri_output_wcs(self, refwcs=None):
        """
        Create a simple output wcs covering footprint of the input datamodels
        """
        # TODO: generalize this for more than one input datamodel
        # TODO: generalize this for imaging modes with distorted wcs
        input_model = self.input_models[0]
        if refwcs == None:
            refwcs = input_model.meta.wcs

        # Generate grid of sky coordinates for area within domain
        x, y = wcstools.grid_from_domain(refwcs.domain)
        ra, dec, lam = refwcs(x.flatten(), y.flatten())
        # TODO: once astropy.modeling._Tabular is fixed, take out the
        # flatten() and reshape() code above and below
        ra = ra.reshape(x.shape)
        dec = dec.reshape(x.shape)
        lam = lam.reshape(x.shape)

        # Find rotation of the slit from y axis from the wcs forward transform
        # TODO: figure out if angle is necessary for MIRI.  See for discussion
        # https://github.com/STScI-JWST/jwst/pull/347
        rotation = [m for m in refwcs.forward_transform if \
            isinstance(m, Rotation2D)]
        if rotation:
            rot_slit = functools.reduce(lambda x, y: x | y, rotation)
            rot_angle = rot_slit.inverse.angle.value
            unrotate = rot_slit.inverse
            refwcs_minus_rot = refwcs.forward_transform | \
                unrotate & Identity(1)
            # Correct for this rotation in the wcs
            ra, dec, lam = refwcs_minus_rot(x.flatten(), y.flatten())
            ra = ra.reshape(x.shape)
            dec = dec.reshape(x.shape)
            lam = lam.reshape(x.shape)

        # Get the slit size at the center of the dispersion
        sky_coords = SkyCoord(ra=ra, dec=dec, unit=u.deg)
        slit_coords = sky_coords[int(sky_coords.shape[0] / 2)]
        slit_angular_size = slit_coords[0].separation(slit_coords[-1])
        log.debug('Slit angular size: {0}'.format(slit_angular_size.arcsec))

        # Compute slit center from domain
        dx0 = refwcs.domain[0]['lower']
        dx1 = refwcs.domain[0]['upper']
        dy0 = refwcs.domain[1]['lower']
        dy1 = refwcs.domain[1]['upper']
        slit_center_pix = (dx1 - dx0) / 2
        dispersion_center_pix = (dy1 - dy0) / 2
        slit_center = refwcs_minus_rot(dx0 + slit_center_pix, dy0 +
            dispersion_center_pix)
        slit_center_sky = SkyCoord(ra=slit_center[0], dec=slit_center[1],
            unit=u.deg)
        log.debug('slit center: {0}'.format(slit_center))

        # Compute spatial and spectral scales
        spatial_scale = slit_angular_size / slit_coords.shape[0]
        log.debug('Spatial scale: {0}'.format(spatial_scale.arcsec))
        tcenter = int((dx1 - dx0) / 2)
        trace = lam[:, tcenter]
        trace = trace[~np.isnan(trace)]
        spectral_scale = np.abs((trace[-1] - trace[0]) / trace.shape[0])
        log.debug('spectral scale: {0}'.format(spectral_scale))

        # Compute transform for output frame
        log.debug('Slit center %s' % slit_center_pix)
        offset = Shift(-slit_center_pix) & Shift(-slit_center_pix)
        # TODO: double-check the signs on the following rotation angles
        roll_ref = input_model.meta.wcsinfo.roll_ref * u.deg
        rot = Rotation2D(roll_ref)
        tan = Pix2Sky_TAN()
        lon_pole = _compute_lon_pole(slit_center_sky, tan)
        skyrot = RotateNative2Celestial(slit_center_sky.ra, slit_center_sky.dec,
            lon_pole)
        min_lam = np.nanmin(lam)
        mapping = Mapping((0, 0, 1))

        transform = Shift(-slit_center_pix) & Identity(1) | \
            Scale(spatial_scale) & Scale(spectral_scale) | \
            Identity(1) & Shift(min_lam) | mapping | \
            (rot | tan | skyrot) & Identity(1)

        transform.inputs = (x, y)
        transform.outputs = ('ra', 'dec', 'lamda')

        # Build the output wcs
        input_frame = refwcs.input_frame
        output_frame = refwcs.output_frame
        wnew = WCS(output_frame=output_frame, forward_transform=transform)

        # Build the domain in the output frame wcs object
        domain_grid = wnew.backward_transform(ra, dec, lam)

        domain = []
        for axis in input_frame.axes_order:
            axis_min = np.nanmin(domain_grid[axis])
            axis_max = np.nanmax(domain_grid[axis]) + 1
            domain.append({'lower': axis_min, 'upper': axis_max,
                'includes_lower': True, 'includes_upper': False})
        log.debug('Domain: {0} {1}'.format(domain[0]['lower'], domain[0]['upper']))
        log.debug('Domain: {0} {1}'.format(domain[1]['lower'], domain[1]['upper']))
        wnew.domain = domain

        # Update class properties
        self.output_spatial_scale = spatial_scale
        self.output_spectral_scale = spectral_scale
        self.output_wcs = wnew