Ejemplo n.º 1
0
def test_frames(tmpdir):
    frames = [
        cf.CelestialFrame(reference_frame=coord.ICRS()),
        cf.CelestialFrame(reference_frame=coord.FK5(
            equinox=time.Time('2010-01-01'))),
        cf.CelestialFrame(reference_frame=coord.FK4(
            equinox=time.Time('2010-01-01'), obstime=time.Time('2015-01-01'))),
        cf.CelestialFrame(reference_frame=coord.FK4NoETerms(
            equinox=time.Time('2010-01-01'), obstime=time.Time('2015-01-01'))),
        cf.CelestialFrame(reference_frame=coord.Galactic()),
        cf.CelestialFrame(
            reference_frame=coord.Galactocentric(galcen_distance=5.0 * u.m,
                                                 galcen_ra=45 * u.deg,
                                                 galcen_dec=1 * u.rad,
                                                 z_sun=3 * u.pc,
                                                 roll=3 * u.deg)),
        cf.CelestialFrame(
            reference_frame=coord.GCRS(obstime=time.Time('2010-01-01'),
                                       obsgeoloc=[1, 3, 2000] * u.pc,
                                       obsgeovel=[2, 1, 8] * (u.m / u.s))),
        cf.CelestialFrame(reference_frame=coord.CIRS(
            obstime=time.Time('2010-01-01'))),
        cf.CelestialFrame(reference_frame=coord.ITRS(
            obstime=time.Time('2022-01-03'))),
        cf.CelestialFrame(reference_frame=coord.PrecessedGeocentric(
            obstime=time.Time('2010-01-01'),
            obsgeoloc=[1, 3, 2000] * u.pc,
            obsgeovel=[2, 1, 8] * (u.m / u.s)))
    ]

    tree = {'frames': frames}

    helpers.assert_roundtrip_tree(tree, tmpdir)
Ejemplo n.º 2
0
def ifu(input_model, reference_files):
    """
    Create the WCS pipeline for a MIRI IFU observation.
    """

    #reference_files = {'distortion': 'jwst_miri_distortion_00001.asdf', #files must hold 2 channels each
                        #'specwcs': 'jwst_miri_specwcs_00001.asdf',
                        #'regions': 'jwst_miri_regions_00001.asdf',
                        #'v2v3': 'jwst_miri_v2v3_00001.asdf'
                        #'wavelengthrange': 'jwst_miri_wavelengthrange_0001.asdf'}
    detector = cf.Frame2D(name='detector', axes_order=(0, 1), unit=(u.pix, u.pix))
    alpha_beta = cf.Frame2D(name='alpha_beta_spatial', axes_order=(0, 1), unit=(u.arcsec, u.arcsec), axes_names=('alpha', 'beta'))
    spec_local = cf.SpectralFrame(name='alpha_beta_spectral', axes_order=(2,), unit=(u.micron,), axes_names=('lambda',))
    miri_focal = cf.CompositeFrame([alpha_beta, spec_local], name='alpha_beta')
    xyan_spatial = cf.Frame2D(name='Xan_Yan_spatial', axes_order=(0, 1), unit=(u.arcmin, u.arcmin), axes_names=('v2', 'v3'))
    spec = cf.SpectralFrame(name='Xan_Yan_spectral', axes_order=(2,), unit=(u.micron,), axes_names=('lambda',))
    xyan = cf.CompositeFrame([xyan_spatial, spec], name='Xan_Yan')
    v23_spatial = cf.Frame2D(name='V2_V3_spatial', axes_order=(0, 1), unit=(u.arcmin, u.arcmin), axes_names=('v2', 'v3'))
    spec = cf.SpectralFrame(name='V2_v3_spectral', axes_order=(2,), unit=(u.micron,), axes_names=('lambda',))
    v2v3 = cf.CompositeFrame([v23_spatial, spec], name='V2_V3')
    icrs = cf.CelestialFrame(name='icrs', reference_frame=coord.ICRS(),
                             axes_order=(0, 1), unit=(u.deg, u.deg), axes_names=('RA', 'DEC'))
    sky = cf.CompositeFrame([icrs, spec], name='sky_and_wavelength')
    det2alpha_beta = (detector_to_alpha_beta(input_model, reference_files)).rename(
        "detector_to_alpha_beta")
    ab2xyan = (alpha_beta2XanYan(input_model, reference_files)).rename("alpha_beta_to_Xan_Yan")
    xyan2v23 = models.Identity(1) & (models.Shift(7.8) | models.Scale(-1)) & models.Identity(1)
    fitswcs_transform = pointing.create_fitswcs_transform(input_model) & models.Identity(1)
    pipeline = [(detector, det2alpha_beta),
                (miri_focal, ab2xyan),
                (xyan, xyan2v23),
                (v2v3, fitswcs_transform),
                (sky, None)
                ]
    return pipeline
Ejemplo n.º 3
0
def imaging(input_model, reference_files):
    """
    Create MIRI Imagng WCS.

    Parameters
    ----------
    input_model : `jwst.datamodels.ImagingModel`
        Data model.
    reference_files : dict
        Dictionary {reftype: reference file name}.

    The MIRI imaging pipeline includes 3 coordinate frames - detector,
    focal plane and sky

    reference_files={'distortion': 'test.asdf', 'filter_offsets': 'filter_offsets.asdf'}
    """

    # Create the Frames
    detector = cf.Frame2D(name='detector',
                          axes_order=(0, 1),
                          unit=(u.pix, u.pix))
    v2v3 = cf.Frame2D(name='v2v3', axes_order=(0, 1), unit=(u.deg, u.deg))
    world = cf.CelestialFrame(reference_frame=coord.ICRS(), name='world')

    # Create the transforms
    distortion = imaging_distortion(input_model, reference_files)
    tel2sky = pointing.v23tosky(input_model)

    # Create the pipeline
    pipeline = [(detector, distortion), (v2v3, tel2sky), (world, None)]

    return pipeline
Ejemplo n.º 4
0
def imaging(input_model, reference_files):
    """
    The MIRI Imaging WCS pipeline.

    It includes three coordinate frames -
    "detector", "v2v3" and "world".

    Parameters
    ----------
    input_model : `jwst.datamodels.ImagingModel`
        Data model.
    reference_files : dict
        Dictionary {reftype: reference file name}.
        Uses "distortion" and "filteroffset" reference files.

    """

    # Create the Frames
    detector = cf.Frame2D(name='detector',
                          axes_order=(0, 1),
                          unit=(u.pix, u.pix))
    v2v3 = cf.Frame2D(name='v2v3',
                      axes_order=(0, 1),
                      axes_names=('v2', 'v3'),
                      unit=(u.arcsec, u.arcsec))
    v2v3vacorr = cf.Frame2D(name='v2v3vacorr',
                            axes_order=(0, 1),
                            axes_names=('v2', 'v3'),
                            unit=(u.arcsec, u.arcsec))
    world = cf.CelestialFrame(reference_frame=coord.ICRS(), name='world')

    # Create the transforms
    distortion = imaging_distortion(input_model, reference_files)
    subarray2full = subarray_transform(input_model)
    if subarray2full is not None:
        distortion = subarray2full | distortion
        distortion.bounding_box = bounding_box_from_subarray(input_model)
    else:
        # TODO: remove setting the bounding box if it is set in the new ref file.
        try:
            bb = distortion.bounding_box
        except NotImplementedError:
            shape = input_model.data.shape
            # Note: Since bounding_box is attached to the model here it's in reverse order.
            bb = ((-0.5, shape[0] - 0.5), (3.5, shape[1] - 4.5))
            distortion.bounding_box = bb

    # Compute differential velocity aberration (DVA) correction:
    va_corr = pointing.dva_corr_model(
        va_scale=input_model.meta.velocity_aberration.scale_factor,
        v2_ref=input_model.meta.wcsinfo.v2_ref,
        v3_ref=input_model.meta.wcsinfo.v3_ref)

    tel2sky = pointing.v23tosky(input_model)

    # Create the pipeline
    pipeline = [(detector, distortion), (v2v3, va_corr), (v2v3vacorr, tel2sky),
                (world, None)]

    return pipeline
Ejemplo n.º 5
0
def imaging(input_model, reference_files):
    """
    The FGS imaging WCS pipeline.

    It includes 3 coordinate frames -
    "detector", "v2v3" and "world".

    Uses a ``distortion`` reference file.
    """
    detector = cf.Frame2D(name='detector', axes_order=(0, 1), unit=(u.pix, u.pix))
    v2v3 = cf.Frame2D(name='v2v3', axes_order=(0, 1), unit=(u.arcsec, u.arcsec))
    world = cf.CelestialFrame(name='world', reference_frame=coord.ICRS())
    # Crete the v2v3 to sky transform.
    tel2sky = pointing.v23tosky(input_model)

    # If subarray, ceate an offset transform to be prepended to the distortion.
    subarray2full = subarray_transform(input_model)
    if reference_files:
        imdistortion = imaging_distortion(input_model, reference_files)
        distortion = subarray2full | imdistortion
        # If the bounding box is saved in the model, move it to the first transform.
        distortion.bounding_box = imdistortion.bounding_box
        del imdistortion.bounding_box
    else:
        distortion = subarray2full

    pipeline = [(detector, distortion),
                (v2v3, tel2sky),
                (world, None)]
    return pipeline
Ejemplo n.º 6
0
def fitswcs_to_gwcs(hdr):
    """
    Create and return a gWCS object from a FITS header. If it can't
    construct one, it should quietly return None.
    """
    # Type of CoordinateFrame to construct for a FITS keyword
    frame_mapping = {'WAVE': cf.SpectralFrame}
    # coordinate names for CelestialFrame
    coordinate_outputs = {'alpha_C', 'delta_C'}

    # transform = gw.make_fitswcs_transform(hdr)
    try:
        transform = make_fitswcs_transform(hdr)
    except Exception as e:
        return None
    outputs = transform.outputs

    naxes = transform.n_inputs
    axes_names = ('x', 'y', 'z', 'u', 'v', 'w')[:naxes]
    in_frame = cf.CoordinateFrame(naxes=naxes, axes_type=['SPATIAL'] * naxes,
                                  axes_order=tuple(range(naxes)), name="pixels",
                                  axes_names=axes_names, unit=[u.pix] * naxes)

    out_frames = []
    for i, output in enumerate(outputs):
        unit_name = hdr.get(f'CUNIT{i+1}')
        try:
            unit = u.Unit(unit_name)
        except TypeError:
            unit = None
        try:
            frame = frame_mapping[output[:4].upper()](axes_order=(i,), unit=unit,
                                          axes_names=(output,), name=output)
        except KeyError:
            if output in coordinate_outputs:
                continue
            frame = cf.CoordinateFrame(naxes=1, axes_type=("SPATIAL",),
                                       axes_order=(i,), unit=unit,
                                       axes_names=(output,), name=output)
        out_frames.append(frame)

    if coordinate_outputs.issubset(outputs):
        frame_name = hdr.get('RADESYS') or hdr.get('RADECSYS')  # FK5, etc.
        try:
            ref_frame = getattr(coord, frame_name)()
            # TODO? Work out how to stuff EQUINOX and OBS-TIME into the frame
        except (AttributeError, TypeError):
            ref_frame = None
        axes_order = (outputs.index('alpha_C'), outputs.index('delta_C'))

        # Call it 'world' if there are no other axes, otherwise 'sky'
        name = 'SKY' if len(outputs) > 2 else 'world'
        cel_frame = cf.CelestialFrame(reference_frame=ref_frame, name=name,
                                      axes_order=axes_order)
        out_frames.append(cel_frame)

    out_frame = (out_frames[0] if len(out_frames) == 1
                 else cf.CompositeFrame(out_frames, name='world'))
    return gWCS([(in_frame, transform),
                 (out_frame, None)])
Ejemplo n.º 7
0
def ifu(input_model, reference_files):
    """
    Create the WCS pipeline for a MIRI IFU observation.
    Goes from 0-indexed detector pixels (0,0) middle of lower left reference pixel
    to V2,V3 in arcsec.

    Parameters
    ----------
    input_model : `jwst.datamodels.ImagingModel`
        Data model.
    reference_files : dict
        Dictionary {reftype: reference file name}.
    """

    #reference_files = {'distortion': 'jwst_miri_distortion_00001.asdf', #files must hold 2 channels each
    #'specwcs': 'jwst_miri_specwcs_00001.asdf',
    #'regions': 'jwst_miri_regions_00001.asdf',
    #'wavelengthrange': 'jwst_miri_wavelengthrange_0001.asdf'}
    # Define reference frames
    detector = cf.Frame2D(name='detector',
                          axes_order=(0, 1),
                          unit=(u.pix, u.pix))
    alpha_beta = cf.Frame2D(name='alpha_beta_spatial',
                            axes_order=(0, 1),
                            unit=(u.arcsec, u.arcsec),
                            axes_names=('alpha', 'beta'))
    spec_local = cf.SpectralFrame(name='alpha_beta_spectral',
                                  axes_order=(2, ),
                                  unit=(u.micron, ),
                                  axes_names=('lambda', ))
    miri_focal = cf.CompositeFrame([alpha_beta, spec_local], name='alpha_beta')
    v23_spatial = cf.Frame2D(name='V2_V3_spatial',
                             axes_order=(0, 1),
                             unit=(u.deg, u.deg),
                             axes_names=('v2', 'v3'))
    spec = cf.SpectralFrame(name='spectral',
                            axes_order=(2, ),
                            unit=(u.micron, ),
                            axes_names=('lambda', ))
    v2v3 = cf.CompositeFrame([v23_spatial, spec], name='v2v3')
    icrs = cf.CelestialFrame(name='icrs',
                             reference_frame=coord.ICRS(),
                             axes_order=(0, 1),
                             unit=(u.deg, u.deg),
                             axes_names=('RA', 'DEC'))
    world = cf.CompositeFrame([icrs, spec], name='world')

    # Define the actual transforms
    det2abl = (detector_to_abl(input_model,
                               reference_files)).rename("detector_to_abl")
    abl2v2v3l = (abl_to_v2v3l(input_model,
                              reference_files)).rename("abl_to_v2v3l")
    tel2sky = pointing.v23tosky(input_model) & models.Identity(1)

    # Put the transforms together into a single transform
    shape = input_model.data.shape
    det2abl.bounding_box = ((-0.5, shape[0] - 0.5), (-0.5, shape[1] - 0.5))
    pipeline = [(detector, det2abl), (miri_focal, abl2v2v3l), (v2v3, tel2sky),
                (world, None)]
    return pipeline
Ejemplo n.º 8
0
def test_simple_gwcs():
    # https://gwcs.readthedocs.io/en/latest/#getting-started
    shift_by_crpix = models.Shift(-(2048 - 1) * u.pix) & models.Shift(-(1024 - 1) * u.pix)
    matrix = np.array([[1.290551569736E-05, 5.9525007864732E-06],
                       [5.0226382102765E-06, -1.2644844123757E-05]])
    rotation = models.AffineTransformation2D(matrix * u.deg, translation=[0, 0] * u.deg)
    rotation.input_units_equivalencies = {"x": u.pixel_scale(1 * (u.deg / u.pix)),
                                          "y": u.pixel_scale(1 * (u.deg / u.pix))}
    rotation.inverse = models.AffineTransformation2D(np.linalg.inv(matrix) * u.pix,
                                                     translation=[0, 0] * u.pix)
    rotation.inverse.input_units_equivalencies = {"x": u.pixel_scale(1 * (u.pix / u.deg)),
                                                  "y": u.pixel_scale(1 * (u.pix / u.deg))}
    tan = models.Pix2Sky_TAN()
    celestial_rotation = models.RotateNative2Celestial(
        5.63056810618 * u.deg, -72.05457184279 * u.deg, 180 * u.deg)
    det2sky = shift_by_crpix | rotation | tan | celestial_rotation
    det2sky.name = "linear_transform"
    detector_frame = cf.Frame2D(name="detector", axes_names=("x", "y"), unit=(u.pix, u.pix))
    sky_frame = cf.CelestialFrame(reference_frame=ICRS(), name='icrs', unit=(u.deg, u.deg))
    pipeline = [(detector_frame, det2sky), (sky_frame, None)]
    w = gwcs.wcs.WCS(pipeline)

    result = wcs_utils.get_compass_info(w, (1024, 2048), r_fac=0.25)
    assert_allclose(result[:-1], (1024.0, 512.0,
                                  1131.0265005852038, 279.446189124443,
                                  1262.0057201165127, 606.2863901330095,
                                  155.2870478938214, -86.89813081941797))
    assert not result[-1]
Ejemplo n.º 9
0
    def _from_skycoord(self,
                       lookup_tables,
                       mesh=False,
                       names=None,
                       physical_types=None,
                       **kwargs):
        if len(lookup_tables) > 1:
            raise ValueError("Can only parse one SkyCoord lookup table.")

        def _generate_skycoord_lookup(components):
            return self._model_from_quantity(components, mesh=mesh)

        sc = lookup_tables[0]
        components = tuple(
            getattr(sc.data, comp) for comp in sc.data.components)
        ref_frame = sc.frame.replicate_without_data()
        units = list(c.unit for c in components)

        if names and len(names) != 2:
            names = None

        # TODO: Currently this limits you to 2D due to gwcs#120
        frame = cf.CelestialFrame(reference_frame=ref_frame,
                                  unit=units,
                                  axes_names=names,
                                  axis_physical_types=physical_types,
                                  name="CelestialFrame")

        return DelayedLookupTable(components, _generate_skycoord_lookup,
                                  mesh), frame
Ejemplo n.º 10
0
Archivo: niriss.py Proyecto: sosey/jwst
def niriss_soss_set_input(model, order_number):
    """
    Get the right model given the order number.

    Parameters
    ----------
    model - Input model
    order_number - the, well, order number desired

    Returns
    -------
    WCS - the WCS corresponding to the order_number

    """

    # Make sure the order number is correct.
    if order_number < 1 or order_number > 3:
        raise ValueError('Order must be between 1 and 3')

    # Return the correct transform based on the order_number
    obj = model.meta.wcs.forward_transform.get_model(order_number)

    # use the size of the input subarray7
    detector = cf.Frame2D(name='detector', axes_order=(0, 1), unit=(u.pix, u.pix))
    spec = cf.SpectralFrame(name='spectral', axes_order=(2,), unit=(u.micron,),
                            axes_names=('wavelength',))
    sky = cf.CelestialFrame(reference_frame=coord.ICRS(),
                            axes_names=('ra', 'dec'),
                            axes_order=(0, 1), unit=(u.deg, u.deg), name='sky')
    world = cf.CompositeFrame([sky, spec], name='world')
    pipeline = [(detector, obj),
                (world, None)
                ]

    return wcs.WCS(pipeline)
Ejemplo n.º 11
0
    def make_spatial(self):
        """
        Add a helioprojective spatial pair to the builder.

        .. note::
            This increments the counter by two.

        """
        i = self._i
        name = self.header[f'DWNAME{self.n}']
        name = name.split(' ')[0]
        axes_names = [(self.header[f'DWNAME{nn}'].rsplit(' ')[1])
                      for nn in (self.n, self._n(i + 1))]

        obstime = Time(self.header['DATE-BGN'])
        self._frames.append(
            cf.CelestialFrame(axes_order=(i, i + 1),
                              name=name,
                              reference_frame=Helioprojective(obstime=obstime),
                              axes_names=axes_names,
                              unit=self.get_units(self._i, self._i + 1)))

        self._transforms.append(spatial_model_from_header(self.header))

        self._i += 2
Ejemplo n.º 12
0
def generate_s3d_wcs():
    """ create a fake gwcs for a cube """
    # create input /output frames
    detector = cf.CoordinateFrame(name='detector', axes_order=(0,1,2), axes_names=['x', 'y', 'z'],
                                  axes_type=['spatial', 'spatial', 'spatial'], naxes=3,
                                  unit=['pix', 'pix', 'pix'])
    sky = cf.CelestialFrame(reference_frame=coord.ICRS(), name='sky', axes_names=("RA", "DEC"))
    spec = cf.SpectralFrame(name='spectral', unit=['um'], axes_names=['wavelength'], axes_order=(2,))
    world = cf.CompositeFrame(name="world", frames=[sky, spec])

    # create fake transform to at least get a bounding box
    # for the s3d jwst loader

    # shape 30,10,10 (spec, y, x)
    crpix1, crpix2, crpix3 = 5, 5, 15  # (x, y, spec)
    crval1, crval2, crval3 = 1, 1, 1
    cdelt1, cdelt2, cdelt3 = 0.01, 0.01, 0.05

    shift = models.Shift(-crpix2) & models.Shift(-crpix1)
    scale = models.Multiply(cdelt2) & models.Multiply(cdelt1)
    proj = models.Pix2Sky_TAN()
    skyrot = models.RotateNative2Celestial(crval2, 90 + crval1, 180)
    celestial = shift | scale | proj | skyrot
    wave_model = models.Shift(-crpix3) | models.Multiply(cdelt3) | models.Shift(crval3)
    transform = models.Mapping((2, 0, 1)) | celestial & wave_model | models.Mapping((1, 2, 0))
    # bounding box based on shape (30,10,10) in test
    transform.bounding_box = ((0, 29), (0, 9), (0, 9))

    # create final wcs
    pipeline = [(detector, transform),
                (world, None)]
    return WCS(pipeline)
Ejemplo n.º 13
0
def create_imaging_frames():
    """
    Create the coordinate frames in the NIRSPEC WCS pipeline.
    These are
    "detector", "gwa", "msa_frame", "oteip", "v2v3", "world".
    """
    det = cf.Frame2D(name='detector', axes_order=(0, 1))
    sca = cf.Frame2D(name='sca', axes_order=(0, 1))
    gwa = cf.Frame2D(name="gwa",
                     axes_order=(0, 1),
                     unit=(u.rad, u.rad),
                     axes_names=('alpha_in', 'beta_in'))
    msa = cf.Frame2D(name='msa',
                     axes_order=(0, 1),
                     unit=(u.m, u.m),
                     axes_names=('x_msa', 'y_msa'))
    v2v3 = cf.Frame2D(name='v2v3',
                      axes_order=(0, 1),
                      unit=(u.deg, u.deg),
                      axes_names=('v2', 'v3'))
    oteip = cf.Frame2D(name='oteip',
                       axes_order=(0, 1),
                       unit=(u.deg, u.deg),
                       axes_names=('x_oteip', 'y_oteip'))
    world = cf.CelestialFrame(name='world',
                              axes_order=(0, 1),
                              reference_frame=coord.ICRS())
    return det, sca, gwa, msa, oteip, v2v3, world
Ejemplo n.º 14
0
def create_frames():
    """
    Create the coordinate frames in the NIRSPEC WCS pipeline.

    These are
    "detector", "gwa", "slit_frame", "msa_frame", "oteip", "v2v3", "world".
    """
    det = cf.Frame2D(name='detector', axes_order=(0, 1))
    sca = cf.Frame2D(name='sca', axes_order=(0, 1))
    gwa = cf.Frame2D(name="gwa", axes_order=(0, 1), unit=(u.rad, u.rad),
                      axes_names=('alpha_in', 'beta_in'))
    msa_spatial = cf.Frame2D(name='msa_spatial', axes_order=(0, 1), unit=(u.m, u.m),
                             axes_names=('x_msa', 'y_msa'))
    slit_spatial = cf.Frame2D(name='slit_spatial', axes_order=(0, 1), unit=("", ""),
                             axes_names=('x_slit', 'y_slit'))
    sky = cf.CelestialFrame(name='sky', axes_order=(0, 1), reference_frame=coord.ICRS())
    v2v3_spatial = cf.Frame2D(name='v2v3_spatial', axes_order=(0, 1), unit=(u.deg, u.deg),
                             axes_names=('V2', 'V3'))

    # The oteip_to_v23 incorporates a scale to convert the spectral units from
    # meters to microns.  So the v2v3 output frame will be in u.deg, u.deg, u.micron
    spec = cf.SpectralFrame(name='spectral', axes_order=(2,), unit=(u.micron,),
                            axes_names=('wavelength',))
    v2v3 = cf.CompositeFrame([v2v3_spatial, spec], name='v2v3')
    slit_frame = cf.CompositeFrame([slit_spatial, spec], name='slit_frame')
    msa_frame = cf.CompositeFrame([msa_spatial, spec], name='msa_frame')
    oteip_spatial = cf.Frame2D(name='oteip', axes_order=(0, 1), unit=(u.deg, u.deg),
                               axes_names=('X_OTEIP', 'Y_OTEIP'))
    oteip = cf.CompositeFrame([oteip_spatial, spec], name='oteip')
    world = cf.CompositeFrame([sky, spec], name='world')
    return det, sca, gwa, slit_frame, msa_frame, oteip, v2v3, world
Ejemplo n.º 15
0
def identity_gwcs_3d():
    """
    A simple 1-1 gwcs that converts from pixels to arcseconds
    """
    identity = (TwoDScale(1 * u.arcsec / u.pixel)
                & m.Multiply(1 * u.nm / u.pixel))

    sky_frame = cf.CelestialFrame(
        axes_order=(0, 1),
        name='helioprojective',
        reference_frame=Helioprojective(obstime="2018-01-01"),
        axes_names=("longitude", "latitude"),
        unit=(u.arcsec, u.arcsec),
        axis_physical_types=("custom:pos.helioprojective.lon",
                             "custom:pos.helioprojective.lat"))
    wave_frame = cf.SpectralFrame(axes_order=(2, ),
                                  unit=u.nm,
                                  axes_names=("wavelength", ))

    frame = cf.CompositeFrame([sky_frame, wave_frame])

    detector_frame = cf.CoordinateFrame(name="detector",
                                        naxes=3,
                                        axes_order=(0, 1, 2),
                                        axes_type=("pixel", "pixel", "pixel"),
                                        axes_names=("x", "y", "z"),
                                        unit=(u.pix, u.pix, u.pix))

    wcs = gwcs.wcs.WCS(forward_transform=identity,
                       output_frame=frame,
                       input_frame=detector_frame)
    wcs.pixel_shape = (10, 20, 30)
    wcs.array_shape = wcs.pixel_shape[::-1]

    return wcs
Ejemplo n.º 16
0
def identity_gwcs():
    """
    A simple 1-1 gwcs that converts from pixels to arcseconds

    Note this WCS does not have a correct axis correlation matrix.
    """
    identity = m.Multiply(1 * u.arcsec / u.pixel) & m.Multiply(
        1 * u.arcsec / u.pixel)
    sky_frame = cf.CelestialFrame(
        axes_order=(0, 1),
        name='helioprojective',
        reference_frame=Helioprojective(obstime="2018-01-01"),
        unit=(u.arcsec, u.arcsec),
        axis_physical_types=("custom:pos.helioprojective.lat",
                             "custom:pos.helioprojective.lon"))
    detector_frame = cf.CoordinateFrame(name="detector",
                                        naxes=2,
                                        axes_order=(0, 1),
                                        axes_type=("pixel", "pixel"),
                                        axes_names=("x", "y"),
                                        unit=(u.pix, u.pix))
    wcs = gwcs.wcs.WCS(forward_transform=identity,
                       output_frame=sky_frame,
                       input_frame=detector_frame)
    wcs.pixel_shape = (10, 20)
    wcs.array_shape = wcs.pixel_shape[::-1]
    return wcs
Ejemplo n.º 17
0
def create_coord_frames():
    gdetector = cf.Frame2D(name='grism_detector',
                           axes_order=(0, 1),
                           unit=(u.pix, u.pix))
    detector = cf.Frame2D(name='full_detector',
                          axes_order=(0, 1),
                          axes_names=('dx', 'dy'),
                          unit=(u.pix, u.pix))
    v2v3_spatial = cf.Frame2D(name='v2v3_spatial',
                              axes_order=(0, 1),
                              axes_names=('v2', 'v3'),
                              unit=(u.deg, u.deg))
    v2v3vacorr_spatial = cf.Frame2D(name='v2v3vacorr_spatial',
                                    axes_order=(0, 1),
                                    axes_names=('v2', 'v3'),
                                    unit=(u.arcsec, u.arcsec))
    sky_frame = cf.CelestialFrame(reference_frame=coord.ICRS(), name='icrs')
    spec = cf.SpectralFrame(name='spectral',
                            axes_order=(2, ),
                            unit=(u.micron, ),
                            axes_names=('wavelength', ))
    frames = {
        'grism_detector':
        gdetector,
        'direct_image':
        cf.CompositeFrame([detector, spec], name='direct_image'),
        'v2v3':
        cf.CompositeFrame([v2v3_spatial, spec], name='v2v3'),
        'v2v3vacorr':
        cf.CompositeFrame([v2v3vacorr_spatial, spec], name='v2v3vacorr'),
        'world':
        cf.CompositeFrame([sky_frame, spec], name='world')
    }
    return frames
Ejemplo n.º 18
0
    def _generate_wcs_transform(dispaxis):
        """Create mock gwcs.WCS object for resampled s2d data"""
        detector = cf.Frame2D(name='detector',
                              axes_order=(0, 1),
                              unit=(u.pix, u.pix))
        icrs = cf.CelestialFrame(name='icrs',
                                 reference_frame=coord.ICRS(),
                                 axes_order=(0, 1),
                                 unit=(u.deg, u.deg),
                                 axes_names=('RA', 'DEC'))
        spec = cf.SpectralFrame(name='spec',
                                axes_order=(2, ),
                                unit=(u.micron, ),
                                axes_names=('lambda', ))
        world = cf.CompositeFrame(name="world", frames=[icrs, spec])

        if dispaxis == 1:
            mapping = models.Mapping((0, 1, 0))
        if dispaxis == 2:
            mapping = models.Mapping((0, 1, 1))

        transform = mapping | (models.Const1D(42) & models.Const1D(42)
                               & (models.Shift(30) | models.Scale(0.1)))
        pipeline = [(detector, transform), (world, None)]
        wcs = WCS(pipeline)

        return wcs
Ejemplo n.º 19
0
def identity_gwcs_4d():
    """
    A simple 1-1 gwcs that converts from pixels to arcseconds
    """
    identity = (m.Multiply(1 * u.arcsec / u.pixel)
                & m.Multiply(1 * u.arcsec / u.pixel)
                & m.Multiply(1 * u.nm / u.pixel)
                & m.Multiply(1 * u.nm / u.pixel))
    sky_frame = cf.CelestialFrame(
        axes_order=(0, 1),
        name='helioprojective',
        reference_frame=Helioprojective(obstime="2018-01-01"))
    wave_frame = cf.SpectralFrame(axes_order=(2, ), unit=u.nm)
    time_frame = cf.TemporalFrame(axes_order=(3, ), unit=u.s)

    frame = cf.CompositeFrame([sky_frame, wave_frame, time_frame])

    detector_frame = cf.CoordinateFrame(name="detector",
                                        naxes=4,
                                        axes_order=(0, 1, 2, 3),
                                        axes_type=("pixel", "pixel", "pixel",
                                                   "pixel"),
                                        axes_names=("x", "y", "z", "s"),
                                        unit=(u.pix, u.pix, u.pix, u.pix))

    return gwcs.wcs.WCS(forward_transform=identity,
                        output_frame=frame,
                        input_frame=detector_frame)
Ejemplo n.º 20
0
def imaging(input_model, reference_files):
    """
    The FGS imaging pipeline includes 3 coordinate frames -
    detector, focal plane and sky.

    reference_files={'distortion': 'jwst_fgs_distortioon_0001.asdf'}
    """
    detector = cf.Frame2D(name='detector',
                          axes_order=(0, 1),
                          unit=(u.pix, u.pix))
    v2v3 = cf.Frame2D(name='v2v3', axes_order=(0, 1), unit=(u.deg, u.deg))
    world = cf.CelestialFrame(name='world', reference_frame=coord.ICRS())
    # V2, V3 to sky
    tel2sky = pointing.v23tosky(input_model)

    subarray2full = subarray_transform(input_model)
    if reference_files:
        imdistortion = imaging_distortion(input_model, reference_files)
        distortion = subarray2full | imdistortion
        distortion.bounding_box = imdistortion.bounding_box
        del imdistortion.bounding_box
    else:
        distortion = subarray2full

    pipeline = [(detector, distortion), (v2v3, tel2sky), (world, None)]
    return pipeline
Ejemplo n.º 21
0
def imaging(input_model, reference_files):
    """
    The NIRISS imaging WCS pipeline.

    It includes three coordinate frames -
    "detector" "v2v3" and "world".

    It uses the "distortion" reference file.
    """
    detector = cf.Frame2D(name='detector',
                          axes_order=(0, 1),
                          unit=(u.pix, u.pix))
    v2v3 = cf.Frame2D(name='v2v3',
                      axes_order=(0, 1),
                      unit=(u.arcsec, u.arcsec))
    world = cf.CelestialFrame(reference_frame=coord.ICRS(), name='world')

    subarray2full = subarray_transform(input_model)
    imdistortion = imaging_distortion(input_model, reference_files)
    distortion = subarray2full | imdistortion
    distortion.bounding_box = imdistortion.bounding_box
    del imdistortion.bounding_box
    tel2sky = pointing.v23tosky(input_model)
    pipeline = [(detector, distortion), (v2v3, tel2sky), (world, None)]
    return pipeline
def test1(tmpdir, ret=False):
    shift_by_crpix = models.Shift(-2048 * u.pix) & models.Shift(-1024 * u.pix)
    matrix = np.array([[1.290551569736E-05, 5.9525007864732E-06],
                       [5.0226382102765E-06, -1.2644844123757E-05]])
    rotation = models.AffineTransformation2D(matrix * u.deg,
                                             translation=[0, 0] * u.deg)
    rotation.input_units_equivalencies = {
        "x": u.pixel_scale(1 * u.deg / u.pix),
        "y": u.pixel_scale(1 * u.deg / u.pix)
    }
    rotation.inverse = models.AffineTransformation2D(
        np.linalg.inv(matrix) * u.pix, translation=[0, 0] * u.pix)
    rotation.inverse.input_units_equivalencies = {
        "x": u.pixel_scale(1 * u.pix / u.deg),
        "y": u.pixel_scale(1 * u.pix / u.deg)
    }
    tan = models.Pix2Sky_TAN()
    celestial_rotation = models.RotateNative2Celestial(5.63056810618 * u.deg,
                                                       -72.05457184279 * u.deg,
                                                       180 * u.deg)
    det2sky = shift_by_crpix | rotation | tan | celestial_rotation
    det2sky.name = "linear_transform"
    detector_frame = cf.Frame2D(name="detector",
                                axes_names=("x", "y"),
                                unit=(u.pix, u.pix))
    sky_frame = cf.CelestialFrame(reference_frame=coords.ICRS(),
                                  name='icrs',
                                  unit=(u.deg, u.deg))
    pipeline = [(detector_frame, det2sky), (sky_frame, None)]
    wcsobj = gwcs.wcs.WCS(pipeline)
    wcs_set = WcsSet(default=wcsobj, extra=wcsobj)
    tree = {'wcs_set': wcs_set}
    if ret:
        return wcs_set
    helpers.assert_roundtrip_tree(tree, tmpdir)
Ejemplo n.º 23
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
Ejemplo n.º 24
0
def lrs(input_model, reference_files):
    """
    The LRS-FIXEDSLIT and LRS-SLITLESS WCS pipeline.

    Notes
    -----
    It includes three coordinate frames -
    "detector", "v2v3" and "world".
    "v2v3" and "world" each have (spatial, spatial, spectral) components.

    Uses the "specwcs" and "distortion" reference files.

    """
    # Define the various coordinate frames.
    # Original detector frame
    detector = cf.Frame2D(name='detector', axes_order=(0, 1), unit=(u.pix, u.pix))
    # Spectral component
    spec = cf.SpectralFrame(name='spec', axes_order=(2,), unit=(u.micron,), axes_names=('lambda',))
    # v2v3 spatial component
    v2v3_spatial = cf.Frame2D(name='v2v3_spatial', axes_order=(0, 1), unit=(u.arcsec, u.arcsec),
                              axes_names=('v2', 'v3'))
    v2v3vacorr_spatial = cf.Frame2D(
        name='v2v3vacorr_spatial',
        axes_order=(0, 1),
        unit=(u.arcsec, u.arcsec),
        axes_names=('v2', 'v3')
    )

    # v2v3 spatial+spectra
    v2v3 = cf.CompositeFrame([v2v3_spatial, spec], name='v2v3')
    v2v3vacorr = cf.CompositeFrame([v2v3vacorr_spatial, spec], name='v2v3vacorr')

    # 'icrs' frame which is the spatial sky component
    icrs = cf.CelestialFrame(name='icrs', reference_frame=coord.ICRS(),
                             axes_order=(0, 1), unit=(u.deg, u.deg), axes_names=('RA', 'DEC'))
    # Final 'world' composite frame with spatial and spectral components
    world = cf.CompositeFrame(name="world", frames=[icrs, spec])

    # Create the transforms
    dettotel = lrs_distortion(input_model, reference_files)
    v2v3tosky = pointing.v23tosky(input_model)
    teltosky = v2v3tosky & models.Identity(1)

    # Compute differential velocity aberration (DVA) correction:
    va_corr = pointing.dva_corr_model(
        va_scale=input_model.meta.velocity_aberration.scale_factor,
        v2_ref=input_model.meta.wcsinfo.v2_ref,
        v3_ref=input_model.meta.wcsinfo.v3_ref
    ) & models.Identity(1)

    # Put the transforms together into a single pipeline
    pipeline = [(detector, dettotel),
                (v2v3, va_corr),
                (v2v3vacorr, teltosky),
                (world, None)]

    return pipeline
Ejemplo n.º 25
0
def imaging(input_model, reference_files):
    """
    The FGS imaging WCS pipeline.

    It includes 3 coordinate frames - "detector", "v2v3" and "world".
    Uses a ``distortion`` reference file.

    Parameters
    ----------
    input_model : `~jwst.datamodels.DataModel`
        The data model.
    reference_files : dict
        {reftype: file_name} mapping.
        Reference files.

    Returns
    -------
    pipeline : list
        The WCS pipeline.
    """
    # Create coordinate frames for the ``imaging`` mode.
    detector = cf.Frame2D(name='detector',
                          axes_order=(0, 1),
                          unit=(u.pix, u.pix))
    v2v3 = cf.Frame2D(name='v2v3',
                      axes_order=(0, 1),
                      axes_names=('v2', 'v3'),
                      unit=(u.arcsec, u.arcsec))
    v2v3vacorr = cf.Frame2D(name='v2v3vacorr',
                            axes_order=(0, 1),
                            axes_names=('v2', 'v3'),
                            unit=(u.arcsec, u.arcsec))
    world = cf.CelestialFrame(name='world', reference_frame=coord.ICRS())

    # Create the v2v3 to sky transform.
    tel2sky = pointing.v23tosky(input_model)

    # Read the distortion from the reference file
    distortion = imaging_distortion(input_model, reference_files)

    # If subarray, create an offset transform to be prepended to the distortion.
    subarray2full = subarray_transform(input_model)
    if subarray2full is not None:
        # Assign a bounding_box based on subarray's xsize and ysize
        distortion = subarray2full | distortion
        distortion.bounding_box = bounding_box_from_subarray(input_model)

    # Compute differential velocity aberration (DVA) correction:
    va_corr = pointing.dva_corr_model(
        va_scale=input_model.meta.velocity_aberration.scale_factor,
        v2_ref=input_model.meta.wcsinfo.v2_ref,
        v3_ref=input_model.meta.wcsinfo.v3_ref)

    pipeline = [(detector, distortion), (v2v3, va_corr), (v2v3vacorr, tel2sky),
                (world, None)]
    return pipeline
Ejemplo n.º 26
0
def load_wcs(input_model, reference_files=None):
    """ Create a gWCS object and store it in ``Model.meta``.

    Parameters
    ----------
    input_model : `~roman_datamodels.datamodels.WfiImage`
        The exposure.
    reference_files : dict
        A dict {reftype: reference_file_name} containing all
        reference files that apply to this exposure.

    Returns
    -------
    output_model : `~roman_datamodels.ImageModel`
        The input image file with attached gWCS object.
        The data is not modified.
    """
    output_model = input_model.copy()

    if reference_files is not None:
        for ref_type, ref_file in reference_files.items():
            if ref_file not in ["N/A", ""]:
                reference_files[ref_type] = ref_file
            else:
                reference_files[ref_type] = None
    else:
        reference_files = {}

    # Frames
    detector = cf.Frame2D(name='detector',
                          axes_order=(0, 1),
                          unit=(u.pix, u.pix))
    v2v3 = cf.Frame2D(name='v2v3',
                      axes_order=(0, 1),
                      axes_names=('v2', 'v3'),
                      unit=(u.arcsec, u.arcsec))
    world = cf.CelestialFrame(reference_frame=coord.ICRS(), name='world')

    # Transforms between frames
    distortion = wfi_distortion(output_model, reference_files)
    tel2sky = pointing.v23tosky(output_model)

    pipeline = [
        Step(detector, distortion),
        Step(v2v3, tel2sky),
        Step(world, None)
    ]
    wcs = WCS(pipeline)
    if wcs.bounding_box is None:
        wcs.bounding_box = wcs_bbox_from_shape(output_model.data.shape)

    output_model.meta['wcs'] = wcs
    output_model.meta.cal_step['assign_wcs'] = 'COMPLETE'

    return output_model
Ejemplo n.º 27
0
def imaging(input_model, reference_files):
    """
    The NIRISS imaging WCS pipeline.

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

    Returns
    -------
    pipeline : list
        The pipeline list that is returned is suitable for
        input into  gwcs.wcs.WCS to create a GWCS object.

    Notes
    -----
    It includes three coordinate frames -
    "detector" "v2v3" and "world".
    It uses the "distortion" reference file.
    """
    detector = cf.Frame2D(name='detector',
                          axes_order=(0, 1),
                          unit=(u.pix, u.pix))
    v2v3 = cf.Frame2D(name='v2v3',
                      axes_order=(0, 1),
                      axes_names=('v2', 'v3'),
                      unit=(u.arcsec, u.arcsec))
    v2v3vacorr = cf.Frame2D(name='v2v3vacorr',
                            axes_order=(0, 1),
                            axes_names=('v2', 'v3'),
                            unit=(u.arcsec, u.arcsec))
    world = cf.CelestialFrame(reference_frame=coord.ICRS(), name='world')

    distortion = imaging_distortion(input_model, reference_files)

    # Compute differential velocity aberration (DVA) correction:
    va_corr = pointing.dva_corr_model(
        va_scale=input_model.meta.velocity_aberration.scale_factor,
        v2_ref=input_model.meta.wcsinfo.v2_ref,
        v3_ref=input_model.meta.wcsinfo.v3_ref)

    subarray2full = subarray_transform(input_model)
    if subarray2full is not None:
        distortion = subarray2full | distortion
        distortion.bounding_box = bounding_box_from_subarray(input_model)

    tel2sky = pointing.v23tosky(input_model)
    pipeline = [(detector, distortion), (v2v3, va_corr), (v2v3vacorr, tel2sky),
                (world, None)]
    return pipeline
Ejemplo n.º 28
0
def test_composite_frame(tmpdir):
    icrs = coord.ICRS()
    fk5 = coord.FK5()
    cel1 = cf.CelestialFrame(reference_frame=icrs)
    cel2 = cf.CelestialFrame(reference_frame=fk5)

    spec1 = cf.SpectralFrame(name='freq', unit=[
        u.Hz,
    ], axes_order=(2, ))
    spec2 = cf.SpectralFrame(name='wave', unit=[
        u.m,
    ], axes_order=(2, ))

    comp1 = cf.CompositeFrame([cel1, spec1])
    comp2 = cf.CompositeFrame([cel2, spec2])
    comp = cf.CompositeFrame(
        [comp1, cf.SpectralFrame(axes_order=(3, ), unit=(u.m, ))])

    tree = {'comp1': comp1, 'comp2': comp2, 'comp': comp}

    helpers.assert_roundtrip_tree(tree, tmpdir)
Ejemplo n.º 29
0
def ifu(input_model, reference_files):
    """
    The MIRI MRS WCS pipeline.

    It has the following coordinate frames:
    "detector", "alpha_beta", "v2v3", "world".

    It uses the "distortion", "regions", "specwcs"
    and "wavelengthrange" reference files.
    """
    # Define coordinate frames.
    detector = cf.Frame2D(name='detector',
                          axes_order=(0, 1),
                          unit=(u.pix, u.pix))
    alpha_beta = cf.Frame2D(name='alpha_beta_spatial',
                            axes_order=(0, 1),
                            unit=(u.arcsec, u.arcsec),
                            axes_names=('alpha', 'beta'))
    spec_local = cf.SpectralFrame(name='alpha_beta_spectral',
                                  axes_order=(2, ),
                                  unit=(u.micron, ),
                                  axes_names=('lambda', ))
    miri_focal = cf.CompositeFrame([alpha_beta, spec_local], name='alpha_beta')
    v23_spatial = cf.Frame2D(name='V2_V3_spatial',
                             axes_order=(0, 1),
                             unit=(u.arcsec, u.arcsec),
                             axes_names=('v2', 'v3'))
    spec = cf.SpectralFrame(name='spectral',
                            axes_order=(2, ),
                            unit=(u.micron, ),
                            axes_names=('lambda', ))
    v2v3 = cf.CompositeFrame([v23_spatial, spec], name='v2v3')
    icrs = cf.CelestialFrame(name='icrs',
                             reference_frame=coord.ICRS(),
                             axes_order=(0, 1),
                             unit=(u.deg, u.deg),
                             axes_names=('RA', 'DEC'))
    world = cf.CompositeFrame([icrs, spec], name='world')

    # Define the actual transforms
    det2abl = (detector_to_abl(input_model,
                               reference_files)).rename("detector_to_abl")
    abl2v2v3l = (abl_to_v2v3l(input_model,
                              reference_files)).rename("abl_to_v2v3l")

    tel2sky = pointing.v23tosky(input_model) & models.Identity(1)

    # Put the transforms together into a single transform
    shape = input_model.data.shape
    det2abl.bounding_box = ((-0.5, shape[0] - 0.5), (-0.5, shape[1] - 0.5))
    pipeline = [(detector, det2abl), (miri_focal, abl2v2v3l), (v2v3, tel2sky),
                (world, None)]
    return pipeline
Ejemplo n.º 30
0
def load_wcs(input_model, reference_files={}):
    """
    Create a gWCS object and store it in ``Model.meta``.

    Parameters
    ----------
    input_model : `~jwst.datamodels.DataModel`
        The exposure.
    reference_files : dict
        A dict {reftype: reference_file_name} containing all
        reference files that apply to this exposure.
    """

    if "wcsinfo" not in input_model.meta:
        input_model.meta.cal_step.assign_wcs = "SKIPPED"
        log.warning("assign_wcs: SKIPPED")
        return input_model
    else:
        output_model = input_model.copy()
        shift_by_crpix = models.Shift(
            -(input_model.meta.wcsinfo.crpix1 - 1) * u.pix
        ) & models.Shift(-(input_model.meta.wcsinfo.crpix2 - 1) * u.pix)
        pix2sky = getattr(
            models, "Pix2Sky_{}".format(input_model.meta.wcsinfo.ctype1[-3:])
        )()
        celestial_rotation = models.RotateNative2Celestial(
            input_model.meta.wcsinfo.crval1 * u.deg,
            input_model.meta.wcsinfo.crval2 * u.deg,
            180 * u.deg,
        )
        pix2sky.input_units_equivalencies = {
            "x": u.pixel_scale(input_model.meta.wcsinfo.cdelt1 * u.deg / u.pix),
            "y": u.pixel_scale(input_model.meta.wcsinfo.cdelt2 * u.deg / u.pix),
        }
        det2sky = shift_by_crpix | pix2sky | celestial_rotation
        det2sky.name = "linear_transform"
        detector_frame = cf.Frame2D(
            name="detector", axes_names=("x", "y"), unit=(u.pix, u.pix)
        )
        sky_frame = cf.CelestialFrame(
            reference_frame=getattr(
                coord, input_model.meta.coordinates.reference_frame
            )(),
            name="sky_frame",
            unit=(u.deg, u.deg),
        )
        pipeline = [(detector_frame, det2sky), (sky_frame, None)]

        wcs = WCS(pipeline)
        output_model.meta.wcs = wcs
        output_model.meta.cal_step.assign_wcs = "COMPLETE"
    return output_model