Beispiel #1
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
Beispiel #2
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
Beispiel #3
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
Beispiel #4
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
Beispiel #5
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
Beispiel #6
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
Beispiel #7
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
Beispiel #8
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
Beispiel #9
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 #10
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
Beispiel #11
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
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
Beispiel #13
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
Beispiel #14
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
Beispiel #15
0
Datei: miri.py Projekt: nden/jwst
def lrs(input_model, reference_files):
    """
    Create the WCS pipeline for a MIRI fixed slit observation.

    reference_files = {"specwcs": 'MIRI_FM_MIRIMAGE_P750L_DISTORTION_04.02.00.fits'}
    """
    detector = cf.Frame2D(name='detector',
                          axes_order=(0, 1),
                          unit=(u.pix, u.pix))
    focal_spatial = cf.Frame2D(name='focal',
                               axes_order=(0, 1),
                               unit=(u.arcmin, u.arcmin))
    sky = cf.CelestialFrame(reference_frame=coord.ICRS())
    spec = cf.SpectralFrame(name='wavelength',
                            axes_order=(2, ),
                            unit=(u.micron, ),
                            axes_names=('lambda', ))
    focal = cf.CompositeFrame([focal_spatial, spec])

    ref = fits.open(reference_files['specwcs'])
    ldata = ref[1].data
    if input_model.meta.exposure.type.lower() == 'mir_lrs-fixedslit':
        zero_point = ref[1].header['imx'], ref[1].header['imy']
    elif input_model.meta.exposure.type.lower() == 'mir_lrs-slitless':
        #zero_point = ref[1].header['imysltl'], ref[1].header['imxsltl']
        #zero point in reference file is wrong
        # This should eb moved eventually to the reference file.
        zero_point = [35, 442]  #[35, 763] # account for subarray
    lrsdata = np.array([l for l in ldata])
    x0 = lrsdata[:, 3]
    x1 = lrsdata[:, 5]
    y0 = lrsdata[:, 4]
    domain = [{
        'lower': x0.min() + zero_point[0],
        'upper': x1.max() + zero_point[0]
    }, {
        'lower': (y0.min() + zero_point[1]),
        'upper': (y0.max() + zero_point[1])
    }]
    log.info("Setting domain to {0}".format(domain))
    lrs_wav_model = jwmodels.LRSWavelength(lrsdata, zero_point)
    ref.close()
    angle = np.arctan(0.00421924)
    spatial = models.Rotation2D(angle)
    det2focal = models.Mapping((0, 1, 0, 1)) | spatial & lrs_wav_model
    det2focal.meta['domain'] = domain
    pipeline = [(detector, det2focal), (focal, None)]
    #(sky, None)
    #]
    return pipeline
    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
Beispiel #17
0
def imaging(input_model, reference_files):
    """
    The NIRISS imaging pipeline includes 3 coordinate frames -
    detector, focal plane and sky

    reference_files={'distortion': 'jwst_niriss_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(reference_frame=coord.ICRS(), name='world')
    distortion = imaging_distortion(input_model, reference_files)
    tel2sky = pointing.v23tosky(input_model)
    pipeline = [(detector, distortion),
                (v2v3, tel2sky),
                (world, None)]
    return pipeline
Beispiel #18
0
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)
Beispiel #19
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]
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)
Beispiel #21
0
def create_fitswcs(inp, input_frame=None):
    if isinstance(inp, DataModel):
        wcsinfo = wcsinfo_from_model(inp)
        wavetable = None
        spatial_axes, spectral_axes, unknown = gwutils.get_axes(wcsinfo)
        if spectral_axes:
            sp_axis = spectral_axes[0]
            if wcsinfo['CTYPE'][sp_axis] == 'WAVE-TAB':
                wavetable = inp.wavetable
        transform = fitswcs_transform_from_model(wcsinfo, wavetable=wavetable)
        output_frame = frame_from_model(wcsinfo)
    else:
        raise TypeError(
            "Input is expected to be a DataModel instance or a FITS file.")

    if input_frame is None:
        wcsaxes = wcsinfo['WCSAXES']
        if wcsaxes == 2:
            input_frame = cf.Frame2D(name="detector")
        elif wcsaxes == 3:
            input_frame = cf.CoordinateFrame(
                name="detector",
                naxes=3,
                axes_order=(0, 1, 2),
                unit=(u.pix, u.pix, u.pix),
                axes_type=["SPATIAL", "SPATIAL", "SPECTRAL"],
                axes_names=('x', 'y', 'z'),
                axis_physical_types=None)
        else:
            raise TypeError(
                f"WCSAXES is expected to be 2 or 3, instead it is {wcsaxes}")
    pipeline = [(input_frame, transform), (output_frame, None)]

    wcsobj = wcs.WCS(pipeline)
    return wcsobj
Beispiel #22
0
def imaging(input_model, reference_files):
    """
    The MIRI imaging pipeline includes 3 coordinate frames - detector,
    focal plane and sky

    reference_files={'distortion': 'test.asdf', 'filter_offsets': 'filter_offsets.asdf'}
    """
    detector = cf.Frame2D(name='detector', axes_order=(0, 1), unit=(u.pix, u.pix))
    focal = cf.Frame2D(name='focal', axes_order=(0, 1), unit=(u.arcmin, u.arcmin))
    sky = cf.CelestialFrame(reference_frame=coord.ICRS())
    distortion = imaging_distortion(input_model, reference_files)
    fitswcs_transform = pointing.create_fitswcs_transform(input_model)
    pipeline = [(detector, distortion),
                (focal, fitswcs_transform),
                (sky, None)
                ]
    return pipeline
Beispiel #23
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
Beispiel #24
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),
                      unit=(u.arcsec, u.arcsec))
    world = cf.CelestialFrame(reference_frame=coord.ICRS(), name='world')

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

    # TODO: remove setting the bounding box when 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
    # Create the pipeline
    pipeline = [(detector, distortion), (v2v3, tel2sky), (world, None)]

    return pipeline
Beispiel #25
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
    subarray2full = subarray_transform(input_model)
    imdistortion = imaging_distortion(input_model, reference_files)
    distortion = subarray2full | imdistortion
    tel2sky = pointing.v23tosky(input_model)

    # TODO: remove setting the bounding box when 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.
        distortion.bounding_box = ((-0.5, shape[0] - 0.5), (3.5,
                                                            shape[1] - 4.5))

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

    return pipeline
Beispiel #26
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),
                      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
Beispiel #27
0
def imaging(input_model, reference_files):
    """
    The NIRCAM imaging pipeline includes 3 coordinate frames -
    detector, focal plane and sky

    reference_files={'distortion': 'test.asdf', 'filter_offsets': 'filter_offsets.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(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
Beispiel #28
0
Datei: fgs.py Projekt: rij/jwst
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))
    focal = cf.Frame2D(name='focal', axes_order=(0,1), unit=(u.arcmin, u.arcmin))
    sky = cf.CelestialFrame(name='icrs', reference_frame=coord.ICRS())
    fitswcs_transform = pointing.create_fitswcs_transform(input_model)
    if reference_files:
        distortion = imaging_distortion(input_model, reference_files)
    else:
        distortion = models.Identity(2)
    pipeline = [(detector, distortion),
                (focal, fitswcs_transform),
                (sky, None)
                ]

    return pipeline
Beispiel #29
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
Beispiel #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