Exemple #1
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
Exemple #2
0
def fitswcs_transform_from_model(wcsinfo, wavetable=None):
    """
    Create a WCS object using from datamodel.meta.wcsinfo.
    Transforms assume 0-based coordinates.

    Parameters
    ----------
    wcsinfo : dict-like
        ``~jwst.meta.wcsinfo`` structure.

    Return
    ------
    transform : `~astropy.modeling.core.Model`
        WCS forward transform - from pixel to world coordinates.

    """
    spatial_axes, spectral_axes, unknown = gwutils.get_axes(wcsinfo)

    transform = gwutils.make_fitswcs_transform(wcsinfo)
    if spectral_axes:
        sp_axis = spectral_axes[0]
        if wavetable is None:
            # Subtract one from CRPIX which is 1-based.
            spectral_transform = astmodels.Shift(-(wcsinfo['CRPIX'][sp_axis] - 1)) | \
                astmodels.Scale(wcsinfo['CDELT'][sp_axis]) | \
                astmodels.Shift(wcsinfo['CRVAL'][sp_axis])
        else:
            # Wave dimension is an array that needs to be converted to a table
            waves = wavetable['wavelength'].flatten()
            spectral_transform = astmodels.Tabular1D(lookup_table=waves)

        transform = transform & spectral_transform

    return transform
Exemple #3
0
def fitswcs_transform_from_model(wcsinfo):
    """
    Create a WCS object using from datamodel.meta.wcsinfo.
    Transforms assume 0-based coordinates.

    Parameters
    ----------
    wcsinfo : dict-like
        ``~jwst.meta.wcsinfo`` structure.

    Return
    ------
    transform : `~astropy.modeling.core.Model`
        WCS forward transform - from pixel to world coordinates.

    """
    spatial_axes, spectral_axes, unknown = gwutils.get_axes(wcsinfo)
    #sp_axis = spectral_axes[0]

    transform = gwutils.make_fitswcs_transform(wcsinfo)
    #if wcsinfo['WCSAXES'] == 3:
    if spectral_axes:
        sp_axis = spectral_axes[0]
        # Subtract one from CRPIX which is 1-based.
        spectral_transform = astmodels.Shift(-(wcsinfo['CRPIX'][sp_axis] - 1)) | \
                           astmodels.Scale(wcsinfo['CDELT'][sp_axis]) | \
                           astmodels.Shift(wcsinfo['CRVAL'][sp_axis])
        transform = transform & spectral_transform

    return transform
Exemple #4
0
def fitswcs_transform_from_model(wcsinfo, wavetable=None):
    """
    Create a WCS object using from datamodel.meta.wcsinfo.
    Transforms assume 0-based coordinates.

    Parameters
    ----------
    wcsinfo : dict-like
        ``~jwst.meta.wcsinfo`` structure.

    Return
    ------
    transform : `~astropy.modeling.core.Model`
        WCS forward transform - from pixel to world coordinates.

    """
    spatial_axes, spectral_axes, unknown = gwutils.get_axes(wcsinfo)
    #sp_axis = spectral_axes[0]

    transform = gwutils.make_fitswcs_transform(wcsinfo)
    if spectral_axes:
        sp_axis = spectral_axes[0]
        if wavetable is None :
            # Subtract one from CRPIX which is 1-based.
            spectral_transform = astmodels.Shift(-(wcsinfo['CRPIX'][sp_axis] - 1)) | \
                astmodels.Scale(wcsinfo['CDELT'][sp_axis]) | \
                astmodels.Shift(wcsinfo['CRVAL'][sp_axis])
        else :
            # Wave dimension is an array that needs to be converted to a table
            waves = wavetable['wavelength'].flatten()
            spectral_transform = astmodels.Tabular1D(lookup_table=waves) 

        transform = transform & spectral_transform

    return transform
Exemple #5
0
def frame_from_model(wcsinfo):
    """
    Initialize a coordinate frame based on values in model.meta.wcsinfo.

    Parameters
    ----------
    wcsinfo : `~stdatamodels.DataModel` or dict
        Either one of the JWST data models or a dict with model.meta.wcsinfo.

    Returns
    -------
    frame : `~coordinate_frames.CoordinateFrame`

    """
    if isinstance(wcsinfo, DataModel):
        wcsinfo = wcsinfo_from_model(wcsinfo)

    wcsaxes = wcsinfo['WCSAXES']
    celestial_axes, spectral_axes, other = gwutils.get_axes(wcsinfo)
    cunit = wcsinfo['CUNIT']
    frames = []
    if celestial_axes:
        ref_frame = coords.ICRS()
        celestial = cf.CelestialFrame(name='sky',
                                      axes_order=tuple(celestial_axes),
                                      reference_frame=ref_frame,
                                      unit=cunit[celestial_axes],
                                      axes_names=('RA', 'DEC'))
        frames.append(celestial)
    if spectral_axes:
        spec = cf.SpectralFrame(name='spectral',
                                axes_order=tuple(spectral_axes),
                                unit=cunit[spectral_axes],
                                axes_names=('wavelength', ))
        frames.append(spec)
    if other:
        # Make sure these are strings and not np.str_ objects.
        axes_names = tuple([str(name) for name in wcsinfo['CTYPE'][other]])
        name = "_".join(wcsinfo['CTYPE'][other])
        spatial = cf.Frame2D(name=name,
                             axes_order=tuple(other),
                             unit=cunit[other],
                             axes_names=axes_names)
        frames.append(spatial)
    if wcsaxes == 2:
        return frames[0]
    elif wcsaxes == 3:
        world = cf.CompositeFrame(frames, name='world')
        return world
    else:
        raise ValueError("WCSAXES can be 2 or 3, got {0}".format(wcsaxes))
Exemple #6
0
def fitswcs_transform_from_model(wcsinfo):
    """
    Create a fits wcs from a datamodel.meta.wcsinfo.
    """
    spatial_axes, spectral_axes = gwutils.get_axes(wcsinfo)

    transform = gwutils.make_fitswcs_transform(wcsinfo)
    if wcsinfo['WCSAXES'] == 3:
        spectral_transform = astmodels.Shift(-wcsinfo['CRPIX'][spectral_axes]) | \
                           astmodels.Scale(wcsinfo['CDELT'][spectral_axes]) | \
                           astmodels.Shift(wcsinfo['CRVAL'][spectral_axes])
        transform = transform & spectral_transform

    return transform
Exemple #7
0
def frame_from_model(wcsinfo):
    wcsaxes = wcsinfo['WCSAXES']
    spatial_axes, spectral_axes = gwutils.get_axes(wcsinfo)
    cunit = wcsinfo['CUNIT']
    ref_frame = coords.ICRS()
    sky = cf.CelestialFrame(name='sky', axes_order=tuple(spatial_axes), reference_frame=ref_frame,
                            unit=cunit[spatial_axes], axes_names=('RA', 'DEC'))
    if wcsaxes == 2:
        return sky
    elif wcsaxes == 3:
        spec = cf.SpectralFrame(name='spectral', axes_order=tuple(spectral_axes), unit=cunit[spectral_axes[0]],
                                axes_names=('wavelength',))
        world = cf.CompositeFrame([sky, spec], name='world')
        return world
    else:
        raise ValueError("WCSAXES can be 2 or 3, git {0}".format(wcsaxes))
Exemple #8
0
def frame_from_model(wcsinfo):
    """
    Initialize a coordinate frame based on values in model.meta.wcsinfo.

    Parameters
    ----------
    wcsinfo : `~jwst.datamodels.model_base.DataModel` or dict
        Either one of the JWST data moels or a dict with model.meta.wcsinfo.

    Returns
    -------
    frame : `~coordinate_frames.CoordinateFrame`

    """
    if isinstance(wcsinfo, DataModel):
        wcsinfo = wcsinfo_from_model(wcsinfo)

    wcsaxes = wcsinfo['WCSAXES']
    celestial_axes, spectral_axes, other = gwutils.get_axes(wcsinfo)
    cunit = wcsinfo['CUNIT']
    frames = []
    if celestial_axes:
        ref_frame = coords.ICRS()
        celestial = cf.CelestialFrame(name='sky', axes_order=tuple(celestial_axes),
                                    reference_frame=ref_frame, unit=cunit[celestial_axes],
                                    axes_names=('RA', 'DEC'))
        frames.append(celestial)
    if spectral_axes:
        spec = cf.SpectralFrame(name='spectral', axes_order=tuple(spectral_axes),
                                unit=cunit[spectral_axes],
                                axes_names=('wavelength',))
        frames.append(spec)
    if other:
        # Make sure these are strings and not np.str_ objects.
        axes_names = tuple([str(name) for name in wcsinfo['CTYPE'][other]])
        name = "_".join(wcsinfo['CTYPE'][other])
        spatial = cf.Frame2D(name=name, axes_order=tuple(other), unit=cunit[other],
                             axes_names=axes_names)
        frames.append(spatial)
    if wcsaxes == 2:
        return frames[0]
    elif wcsaxes == 3:
        world = cf.CompositeFrame(frames, name='world')
        return world
    else:
        raise ValueError("WCSAXES can be 2 or 3, got {0}".format(wcsaxes))
Exemple #9
0
def frame_from_model(wcsinfo):
    wcsaxes = wcsinfo['WCSAXES']
    spatial_axes, spectral_axes = gwutils.get_axes(wcsinfo)
    cunit = wcsinfo['CUNIT']
    ref_frame = coords.ICRS()
    sky = cf.CelestialFrame(name='sky',
                            axes_order=tuple(spatial_axes),
                            reference_frame=ref_frame,
                            unit=cunit[spatial_axes],
                            axes_names=('RA', 'DEC'))
    if wcsaxes == 2:
        return sky
    elif wcsaxes == 3:
        spec = cf.SpectralFrame(name='spectral',
                                axes_order=tuple(spectral_axes),
                                unit=cunit[spectral_axes[0]],
                                axes_names=('wavelength', ))
        world = cf.CompositeFrame([sky, spec], name='world')
        return world
    else:
        raise ValueError("WCSAXES can be 2 or 3, got {0}".format(wcsaxes))
Exemple #10
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)
        sp_axis = spectral_axes[0]
        if wcsinfo['CTYPE'][sp_axis] == 'WAVE-TAB':
            wavetable = inp.wavetable
        transform = fitswcs_transform_from_model(wcsinfo, wavetable)
        output_frame = frame_from_model(wcsinfo)
    #elif isinstance(inp, str):
    #transform = create_fitswcs_transform(inp)
    #output_frame = frame_from_fits(inp)
    else:
        raise TypeError(
            "Input is expected to be a DataModel instance or a FITS file.")

    if input_frame is None:
        input_frame = "detector"
    pipeline = [(input_frame, transform), (output_frame, None)]

    wcsobj = wcs.WCS(pipeline)
    return wcsobj
Exemple #11
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)
        sp_axis = spectral_axes[0]
        if wcsinfo['CTYPE'][sp_axis] == 'WAVE-TAB':
            wavetable = inp.wavetable
        transform = fitswcs_transform_from_model(wcsinfo, wavetable)
        output_frame = frame_from_model(wcsinfo)
    #elif isinstance(inp, str):
        #transform = create_fitswcs_transform(inp)
        #output_frame = frame_from_fits(inp)
    else:
        raise TypeError("Input is expected to be a DataModel instance or a FITS file.")

    if input_frame is None:
        input_frame = "detector"
    pipeline = [(input_frame, transform),
               (output_frame, None)]

    wcsobj = wcs.WCS(pipeline)
    return wcsobj
Exemple #12
0
def wcs_from_footprints(dmodels,
                        refmodel=None,
                        transform=None,
                        bounding_box=None,
                        domain=None):
    """
    Create a WCS from a list of input data models.

    A fiducial point in the output coordinate frame is created from  the
    footprints of all WCS objects. For a spatial frame this is the center
    of the union of the footprints. For a spectral frame the fiducial is in
    the beginning of the footprint range.
    If ``refmodel`` is None, the first WCS object in the list is considered
    a reference. The output coordinate frame and projection (for celestial frames)
    is taken from ``refmodel``.
    If ``transform`` is not suplied, a compound transform is created using
    CDELTs and PC.
    If ``bounding_box`` is not supplied, the bounding_box of the new WCS is computed
    from bounding_box of all input WCSs.

    Parameters
    ----------
    dmodels : list of `~jwst.datamodels.DataModel`
        A list of data models.
    refmodel : `~jwst.datamodels.DataModel`, optional
        This model's WCS is used as a reference.
        WCS. The output coordinate frame, the projection and a
        scaling and rotation transform is created from it. If not supplied
        the first model in the list is used as ``refmodel``.
    transform : `~astropy.modeling.core.Model`, optional
        A transform, passed to :meth:`~gwcs.wcstools.wcs_from_fiducial`
        If not supplied Scaling | Rotation is computed from ``refmodel``.
    bounding_box : tuple, optional
        Bounding_box of the new WCS.
        If not supplied it is computed from the bounding_box of all inputs.
    """
    if domain is not None:
        warnings.warning(
            "'domain' was deprecated in 0.8 and will be removed from next"
            "version. Use 'bounding_box' instead.")
        bb = _domain_to_bounding_box(domain)
    else:
        bb = bounding_box
    wcslist = [im.meta.wcs for im in dmodels]
    if not isiterable(wcslist):
        raise ValueError(
            "Expected 'wcslist' to be an iterable of WCS objects.")
    if not all([isinstance(w, WCS) for w in wcslist]):
        raise TypeError(
            "All items in wcslist are to be instances of gwcs.WCS.")
    if refmodel is None:
        refmodel = dmodels[0]
    else:
        if not isinstance(refmodel, DataModel):
            raise TypeError(
                "Expected refmodel to be an instance of DataModel.")

    fiducial = compute_fiducial(wcslist, bb)

    prj = astmodels.Pix2Sky_TAN()

    if transform is None:
        transform = []
        wcsinfo = pointing.wcsinfo_from_model(refmodel)
        sky_axes, spec, other = gwutils.get_axes(wcsinfo)
        rotation = astmodels.AffineTransformation2D(wcsinfo['PC'])
        transform.append(rotation)
        if sky_axes:
            cdelt1, cdelt2 = wcsinfo['CDELT'][sky_axes]
            scale = np.sqrt(np.abs(cdelt1 * cdelt2))
            scales = astmodels.Scale(scale) & astmodels.Scale(scale)
            transform.append(scales)

        if transform:
            transform = functools.reduce(lambda x, y: x | y, transform)

    out_frame = refmodel.meta.wcs.output_frame
    wnew = wcs_from_fiducial(fiducial,
                             coordinate_frame=out_frame,
                             projection=prj,
                             transform=transform)

    footprints = [w.footprint().T for w in wcslist]
    domain_bounds = np.hstack(
        [wnew.backward_transform(*f) for f in footprints])
    for axs in domain_bounds:
        axs -= axs.min()
    bounding_box = []
    for axis in out_frame.axes_order:
        axis_min, axis_max = domain_bounds[axis].min(
        ), domain_bounds[axis].max()
        bounding_box.append((axis_min, axis_max))
    bounding_box = tuple(bounding_box)
    ax1, ax2 = np.array(bounding_box)[sky_axes]
    offset1 = (ax1[1] - ax1[0]) / 2
    offset2 = (ax2[1] - ax2[0]) / 2
    offsets = astmodels.Shift(-offset1) & astmodels.Shift(-offset2)

    wnew.insert_transform('detector', offsets, after=True)
    wnew.bounding_box = bounding_box
    return wnew
Exemple #13
0
def wcs_from_footprints(dmodels, refmodel=None, transform=None, bounding_box=None,
                        pscale_ratio=None):
    """
    Create a WCS from a list of input data models.

    A fiducial point in the output coordinate frame is created from  the
    footprints of all WCS objects. For a spatial frame this is the center
    of the union of the footprints. For a spectral frame the fiducial is in
    the beginning of the footprint range.
    If ``refmodel`` is None, the first WCS object in the list is considered
    a reference. The output coordinate frame and projection (for celestial frames)
    is taken from ``refmodel``.
    If ``transform`` is not suplied, a compound transform is created using
    CDELTs and PC.
    If ``bounding_box`` is not supplied, the bounding_box of the new WCS is computed
    from bounding_box of all input WCSs.

    Parameters
    ----------
    dmodels : list of `~jwst.datamodels.DataModel`
        A list of data models.
    refmodel : `~jwst.datamodels.DataModel`, optional
        This model's WCS is used as a reference.
        WCS. The output coordinate frame, the projection and a
        scaling and rotation transform is created from it. If not supplied
        the first model in the list is used as ``refmodel``.
    transform : `~astropy.modeling.core.Model`, optional
        A transform, passed to :meth:`~gwcs.wcstools.wcs_from_fiducial`
        If not supplied Scaling | Rotation is computed from ``refmodel``.
    bounding_box : tuple, optional
        Bounding_box of the new WCS.
        If not supplied it is computed from the bounding_box of all inputs.
    pscale_ratio : float, optional
        Ratio of input to output pixel scale.
    """
    bb = bounding_box
    wcslist = [im.meta.wcs for im in dmodels]

    if not isiterable(wcslist):
        raise ValueError("Expected 'wcslist' to be an iterable of WCS objects.")

    if not all([isinstance(w, WCS) for w in wcslist]):
        raise TypeError("All items in wcslist are to be instances of gwcs.WCS.")

    if refmodel is None:
        refmodel = dmodels[0]
    else:
        if not isinstance(refmodel, DataModel):
            raise TypeError("Expected refmodel to be an instance of DataModel.")

    fiducial = compute_fiducial(wcslist, bb)
    ref_fiducial = compute_fiducial([refmodel.meta.wcs])

    prj = astmodels.Pix2Sky_TAN()

    if transform is None:
        transform = []
        wcsinfo = pointing.wcsinfo_from_model(refmodel)
        sky_axes, spec, other = gwutils.get_axes(wcsinfo)

        # Need to put the rotation matrix (List[float, float, float, float])
        # returned from calc_rotation_matrix into the correct shape for
        # constructing the transformation
        roll_ref = np.deg2rad(refmodel.meta.wcsinfo.roll_ref)
        v3yangle = np.deg2rad(refmodel.meta.wcsinfo.v3yangle)
        vparity = refmodel.meta.wcsinfo.vparity
        pc = np.reshape(
            calc_rotation_matrix(roll_ref, v3yangle, vparity=vparity),
            (2, 2)
        )

        rotation = astmodels.AffineTransformation2D(pc)
        transform.append(rotation)

        if sky_axes:
            scale = compute_scale(refmodel.meta.wcs, ref_fiducial,
                                  pscale_ratio=pscale_ratio)
            transform.append(astmodels.Scale(scale) & astmodels.Scale(scale))

        if transform:
            transform = functools.reduce(lambda x, y: x | y, transform)

    out_frame = refmodel.meta.wcs.output_frame
    input_frame = dmodels[0].meta.wcs.input_frame
    wnew = wcs_from_fiducial(fiducial, coordinate_frame=out_frame, projection=prj,
                             transform=transform, input_frame=input_frame)

    footprints = [w.footprint().T for w in wcslist]
    domain_bounds = np.hstack([wnew.backward_transform(*f) for f in footprints])

    for axs in domain_bounds:
        axs -= (axs.min() + .5)

    output_bounding_box = []
    for axis in out_frame.axes_order:
        axis_min, axis_max = domain_bounds[axis].min(), domain_bounds[axis].max()
        output_bounding_box.append((axis_min, axis_max))

    output_bounding_box = tuple(output_bounding_box)
    ax1, ax2 = np.array(output_bounding_box)[sky_axes]
    offset1 = (ax1[1] - ax1[0]) / 2
    offset2 = (ax2[1] - ax2[0]) / 2
    offsets = astmodels.Shift(-offset1) & astmodels.Shift(-offset2)

    wnew.insert_transform('detector', offsets, after=True)
    wnew.bounding_box = output_bounding_box

    return wnew
Exemple #14
0
def wcs_from_footprints(dmodels, refmodel=None, transform=None, domain=None):
    """
    Create a WCS from a list of input data models.

    A fiducial point in the output coordinate frame is created from  the
    footprints of all WCS objects. For a spatial frame this is the center
    of the union of the footprints. For a spectral frame the fiducial is in
    the beginning of the footprint range.
    If ``refmodel`` is None, the first WCS object in the list is considered
    a reference. The output coordinate frame and projection (for celestial frames)
    is taken from ``refmodel``.
    If ``transform`` is not suplied, a compound transform is created using
    CDELTs and PC.
    If ``domain`` is not supplied, the domain of the new WCS is computed
    from the domains of all input WCSs.

    Parameters
    ----------
    dmodels : list of `~jwst.datamodels.DataModel`
        A list of data models.
    refmodel : `~jwst.datamodels.DataModel`, optional
        This model's WCS is used as a reference.
        WCS. The output coordinate frame, the projection and a
        scaling and rotation transform is created from it. If not supplied
        the first model in the list is used as ``refmodel``.
    transform : `~astropy.modeling.core.Model`, optional
        A transform, passed to :class_method:`~gwcs.WCS.wcs_from_fiducial`
        If not supplied Scaling | Rotation is computed from ``refmodel``.
    domain : list of dicts, optional
        Domain of the new WCS.
        If not supplied it is computed from the domain of all inputs.
    """
    wcslist = [im.meta.wcs for im in dmodels]
    if not isiterable(wcslist):
        raise ValueError(
            "Expected 'wcslist' to be an iterable of WCS objects.")
    if not all([isinstance(w, WCS) for w in wcslist]):
        raise TypeError(
            "All items in wcslist are to be instances of gwcs.WCS.")
    if refmodel is None:
        refmodel = dmodels[0]
    else:
        if not isinstance(refmodel, DataModel):
            raise TypeError(
                "Expected refmodel to be an instance of DataModel.")

    fiducial = compute_fiducial(wcslist, domain)

    prj = astmodels.Pix2Sky_TAN()

    if transform is None:
        transform = []
        wcsinfo = pointing.wcsinfo_from_model(refmodel)
        sky_axes, _ = gwutils.get_axes(wcsinfo)
        rotation = astmodels.AffineTransformation2D(np.array(wcsinfo['PC']))
        transform.append(rotation)
        if sky_axes:
            scale = wcsinfo['CDELT'][sky_axes].mean()
            scales = astmodels.Scale(scale) & astmodels.Scale(scale)
            transform.append(scales)

        if transform:
            transform = functools.reduce(lambda x, y: x | y, transform)

    out_frame = refmodel.meta.wcs.output_frame
    wnew = wcs_from_fiducial(fiducial,
                             coordinate_frame=out_frame,
                             projection=prj,
                             transform=transform)

    footprints = [w.footprint() for w in wcslist]
    domain_bounds = np.hstack(
        [wnew.backward_transform(*f) for f in footprints])
    for axs in domain_bounds:
        axs -= axs.min()
    domain = []
    for axis in out_frame.axes_order:
        axis_min, axis_max = domain_bounds[axis].min(
        ), domain_bounds[axis].max()
        domain.append({
            'lower': axis_min,
            'upper': axis_max,
            'includes_lower': True,
            'includes_upper': True
        })
    #ax1, ax2 = domain[sky_axes] # change when domain is a bounding_box
    ax1, ax2 = domain
    offset1 = (ax1['upper'] - ax1['lower']) / 2
    offset2 = (ax2['upper'] - ax2['lower']) / 2
    offsets = astmodels.Shift(-offset1) & astmodels.Shift(-offset2)

    wnew.insert_transform('detector', offsets, after=True)
    wnew.domain = domain
    return wnew
Exemple #15
0
def wcs_from_footprints(dmodels, refmodel=None, transform=None, bounding_box=None, domain=None):
    """
    Create a WCS from a list of input data models.

    A fiducial point in the output coordinate frame is created from  the
    footprints of all WCS objects. For a spatial frame this is the center
    of the union of the footprints. For a spectral frame the fiducial is in
    the beginning of the footprint range.
    If ``refmodel`` is None, the first WCS object in the list is considered
    a reference. The output coordinate frame and projection (for celestial frames)
    is taken from ``refmodel``.
    If ``transform`` is not suplied, a compound transform is created using
    CDELTs and PC.
    If ``bounding_box`` is not supplied, the bounding_box of the new WCS is computed
    from bounding_box of all input WCSs.

    Parameters
    ----------
    dmodels : list of `~jwst.datamodels.DataModel`
        A list of data models.
    refmodel : `~jwst.datamodels.DataModel`, optional
        This model's WCS is used as a reference.
        WCS. The output coordinate frame, the projection and a
        scaling and rotation transform is created from it. If not supplied
        the first model in the list is used as ``refmodel``.
    transform : `~astropy.modeling.core.Model`, optional
        A transform, passed to :meth:`~gwcs.wcstools.wcs_from_fiducial`
        If not supplied Scaling | Rotation is computed from ``refmodel``.
    bounding_box : tuple, optional
        Bounding_box of the new WCS.
        If not supplied it is computed from the bounding_box of all inputs.
    """
    if domain is not None:
        warnings.warning("'domain' was deprecated in 0.8 and will be removed from next"
                         "version. Use 'bounding_box' instead.")
        bb = _domain_to_bounding_box(domain)
    else:
        bb = bounding_box
    wcslist = [im.meta.wcs for im in dmodels]
    if not isiterable(wcslist):
        raise ValueError("Expected 'wcslist' to be an iterable of WCS objects.")
    if not all([isinstance(w, WCS) for w in wcslist]):
        raise TypeError("All items in wcslist are to be instances of gwcs.WCS.")
    if refmodel is None:
        refmodel = dmodels[0]
    else:
        if not isinstance(refmodel, DataModel):
            raise TypeError("Expected refmodel to be an instance of DataModel.")

    fiducial = compute_fiducial(wcslist, bb)

    prj = astmodels.Pix2Sky_TAN()

    if transform is None:
        transform = []
        wcsinfo = pointing.wcsinfo_from_model(refmodel)
        sky_axes, spec, other = gwutils.get_axes(wcsinfo)
        rotation = astmodels.AffineTransformation2D(wcsinfo['PC'])
        transform.append(rotation)
        if sky_axes:
            cdelt1, cdelt2 = wcsinfo['CDELT'][sky_axes]
            scale = np.sqrt(np.abs(cdelt1 * cdelt2))
            scales = astmodels.Scale(scale) & astmodels.Scale(scale)
            transform.append(scales)

        if transform:
            transform = functools.reduce(lambda x, y: x | y, transform)

    out_frame = refmodel.meta.wcs.output_frame
    wnew = wcs_from_fiducial(fiducial, coordinate_frame=out_frame,
                             projection=prj, transform=transform)

    footprints = [w.footprint().T for w in wcslist]
    domain_bounds = np.hstack([wnew.backward_transform(*f) for f in footprints])
    for axs in domain_bounds:
        axs -= axs.min()
    bounding_box = []
    for axis in out_frame.axes_order:
        axis_min, axis_max = domain_bounds[axis].min(), domain_bounds[axis].max()
        bounding_box.append((axis_min, axis_max))
    bounding_box = tuple(bounding_box)
    ax1, ax2 = np.array(bounding_box)[sky_axes]
    offset1 = (ax1[1] - ax1[0]) / 2
    offset2 = (ax2[1] - ax2[0]) / 2
    offsets = astmodels.Shift(-offset1) & astmodels.Shift(-offset2)

    wnew.insert_transform('detector', offsets, after=True)
    wnew.bounding_box = bounding_box
    return wnew
Exemple #16
0
def wcs_from_footprints(dmodels,
                        refmodel=None,
                        transform=None,
                        bounding_box=None,
                        pscale_ratio=None,
                        pscale=None,
                        rotation=None,
                        shape=None,
                        crpix=None,
                        crval=None):
    """
    Create a WCS from a list of input data models.

    A fiducial point in the output coordinate frame is created from  the
    footprints of all WCS objects. For a spatial frame this is the center
    of the union of the footprints. For a spectral frame the fiducial is in
    the beginning of the footprint range.
    If ``refmodel`` is None, the first WCS object in the list is considered
    a reference. The output coordinate frame and projection (for celestial frames)
    is taken from ``refmodel``.
    If ``transform`` is not supplied, a compound transform is created using
    CDELTs and PC.
    If ``bounding_box`` is not supplied, the bounding_box of the new WCS is computed
    from bounding_box of all input WCSs.

    Parameters
    ----------
    dmodels : list of `~jwst.datamodels.DataModel`
        A list of data models.
    refmodel : `~jwst.datamodels.DataModel`, optional
        This model's WCS is used as a reference.
        WCS. The output coordinate frame, the projection and a
        scaling and rotation transform is created from it. If not supplied
        the first model in the list is used as ``refmodel``.
    transform : `~astropy.modeling.core.Model`, optional
        A transform, passed to :meth:`~gwcs.wcstools.wcs_from_fiducial`
        If not supplied Scaling | Rotation is computed from ``refmodel``.
    bounding_box : tuple, optional
        Bounding_box of the new WCS.
        If not supplied it is computed from the bounding_box of all inputs.
    pscale_ratio : float, None, optional
        Ratio of input to output pixel scale. Ignored when either
        ``transform`` or ``pscale`` are provided.
    pscale : float, None, optional
        Absolute pixel scale in degrees. When provided, overrides
        ``pscale_ratio``. Ignored when ``transform`` is provided.
    rotation : float, None, optional
        Position angle of output image’s Y-axis relative to North.
        A value of 0.0 would orient the final output image to be North up.
        The default of `None` specifies that the images will not be rotated,
        but will instead be resampled in the default orientation for the camera
        with the x and y axes of the resampled image corresponding
        approximately to the detector axes. Ignored when ``transform`` is
        provided.
    shape : tuple of int, None, optional
        Shape of the image (data array) using ``numpy.ndarray`` convention
        (``ny`` first and ``nx`` second). This value will be assigned to
        ``pixel_shape`` and ``array_shape`` properties of the returned
        WCS object.
    crpix : tuple of float, None, optional
        Position of the reference pixel in the image array.  If ``crpix`` is not
        specified, it will be set to the center of the bounding box of the
        returned WCS object.
    crval : tuple of float, None, optional
        Right ascension and declination of the reference pixel. Automatically
        computed if not provided.

    """
    bb = bounding_box
    wcslist = [im.meta.wcs for im in dmodels]

    if not isiterable(wcslist):
        raise ValueError(
            "Expected 'wcslist' to be an iterable of WCS objects.")

    if not all([isinstance(w, WCS) for w in wcslist]):
        raise TypeError(
            "All items in wcslist are to be instances of gwcs.WCS.")

    if refmodel is None:
        refmodel = dmodels[0]
    else:
        if not isinstance(refmodel, DataModel):
            raise TypeError(
                "Expected refmodel to be an instance of DataModel.")

    fiducial = compute_fiducial(wcslist, bb)
    if crval is not None:
        # overwrite spatial axes with user-provided CRVAL:
        i = 0
        for k, axt in enumerate(wcslist[0].output_frame.axes_type):
            if axt == 'SPATIAL':
                fiducial[k] = crval[i]
                i += 1

    ref_fiducial = np.array(
        [refmodel.meta.wcsinfo.ra_ref, refmodel.meta.wcsinfo.dec_ref])

    prj = astmodels.Pix2Sky_TAN()

    if transform is None:
        transform = []
        wcsinfo = pointing.wcsinfo_from_model(refmodel)
        sky_axes, spec, other = gwutils.get_axes(wcsinfo)

        # Need to put the rotation matrix (List[float, float, float, float])
        # returned from calc_rotation_matrix into the correct shape for
        # constructing the transformation
        v3yangle = np.deg2rad(refmodel.meta.wcsinfo.v3yangle)
        vparity = refmodel.meta.wcsinfo.vparity
        if rotation is None:
            roll_ref = np.deg2rad(refmodel.meta.wcsinfo.roll_ref)
        else:
            roll_ref = np.deg2rad(rotation) + (vparity * v3yangle)

        pc = np.reshape(
            calc_rotation_matrix(roll_ref, v3yangle, vparity=vparity), (2, 2))

        rotation = astmodels.AffineTransformation2D(pc,
                                                    name='pc_rotation_matrix')
        transform.append(rotation)

        if sky_axes:
            if not pscale:
                pscale = compute_scale(refmodel.meta.wcs,
                                       ref_fiducial,
                                       pscale_ratio=pscale_ratio)
            transform.append(
                astmodels.Scale(pscale, name='cdelt1')
                & astmodels.Scale(pscale, name='cdelt2'))

        if transform:
            transform = functools.reduce(lambda x, y: x | y, transform)

    out_frame = refmodel.meta.wcs.output_frame
    input_frame = refmodel.meta.wcs.input_frame
    wnew = wcs_from_fiducial(fiducial,
                             coordinate_frame=out_frame,
                             projection=prj,
                             transform=transform,
                             input_frame=input_frame)

    footprints = [w.footprint().T for w in wcslist]
    domain_bounds = np.hstack(
        [wnew.backward_transform(*f) for f in footprints])
    axis_min_values = np.min(domain_bounds, axis=1)
    domain_bounds = (domain_bounds.T - axis_min_values).T

    output_bounding_box = []
    for axis in out_frame.axes_order:
        axis_min, axis_max = domain_bounds[axis].min(
        ), domain_bounds[axis].max()
        output_bounding_box.append((axis_min, axis_max))

    output_bounding_box = tuple(output_bounding_box)
    if crpix is None:
        offset1, offset2 = wnew.backward_transform(*fiducial)
        offset1 -= axis_min_values[0]
        offset2 -= axis_min_values[1]
    else:
        offset1, offset2 = crpix
    offsets = astmodels.Shift(-offset1, name='crpix1') & astmodels.Shift(
        -offset2, name='crpix2')

    wnew.insert_transform('detector', offsets, after=True)
    wnew.bounding_box = output_bounding_box

    if shape is None:
        shape = [
            int(axs[1] - axs[0] + 0.5) for axs in output_bounding_box[::-1]
        ]

    wnew.pixel_shape = shape[::-1]
    wnew.array_shape = shape

    return wnew