Beispiel #1
0
    def from_tree(cls, node, ctx):
        import gwcs

        steps = [(x['frame'], x.get('transform')) for x in node['steps']]
        name = node['name']

        return gwcs.WCS(steps, name=name)
Beispiel #2
0
 def wcs(self):
     """
     A gWCS object representing all the coordinates.
     """
     model = self.model
     return gwcs.WCS(forward_transform=model,
                     input_frame=_generate_generic_frame(model.n_inputs, u.pix),
                     output_frame=self.frame)
Beispiel #3
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 #4
0
def hdu_to_imagemodel(in_hdu):
    """
    Workaround for initializing a `jwst.datamodels.ImageModel` from a 
    normal FITS ImageHDU that could contain HST header keywords and 
    unexpected WCS definition.
    
    TBD
    
    Parameters
    ----------
    in_hdu : `astropy.io.fits.ImageHDU`
    
    
    Returns
    -------
    img : `jwst.datamodels.ImageModel`
    
    
    """
    from astropy.io.fits import ImageHDU, HDUList
    from astropy.coordinates import ICRS

    from jwst.datamodels import util
    import gwcs

    hdu = ImageHDU(data=in_hdu.data, header=in_hdu.header)

    new_header = strip_telescope_header(hdu.header)

    hdu.header = new_header

    # Initialize data model
    img = util.open(HDUList([hdu]))

    # Initialize GWCS
    tform = gwcs.wcs.utils.make_fitswcs_transform(new_header)
    hwcs = gwcs.WCS(forward_transform=tform,
                    output_frame=ICRS())  #gwcs.CelestialFrame())
    sh = hdu.data.shape
    hwcs.bounding_box = ((-0.5, sh[0] - 0.5), (-0.5, sh[1] - 0.5))

    # Put gWCS in meta, where blot/drizzle expect to find it
    img.meta.wcs = hwcs

    return img
Beispiel #5
0
def gwcs_from_headers(headers):
    """
    Given a list of headers build a gwcs.

    Parameters
    ----------

    headers : `list`
        A list of headers. These are expected to have already been validated.
    """
    header = headers[0]

    pixel_frame = build_pixel_frame(header)

    builder = TransformBuilder(headers)
    world_frame = cf.CompositeFrame(builder.frames)

    return gwcs.WCS(forward_transform=builder.transform,
                    input_frame=pixel_frame,
                    output_frame=world_frame)
Beispiel #6
0
    def blot(self):
        """MAIN FUNCTION
        Resamples the input image onto the WCS associated with the given
        instrument/apertures
        """
        # Get detector names from the aperture list
        if isinstance(self.aperture, str):
            self.aperture = [self.aperture]

        self.detector = [element.split('_')[0] for element in self.aperture]

        # Make sure detector, ra, dec, and roll have same number
        # of elements
        if ((len(self.center_dec) != len(self.center_ra)) | \
                (len(self.center_dec) != len(self.pav3))):
            raise ValueError(('WARNING: center_ra, center_dec '
                              'and pav3 all must have the same number '
                              'of elements.'))

        if type(self.blotfile) == str:
            input_mod = datamodels.ImageModel(self.blotfile)
            outbase = self.blotfile

        elif type(self.blotfile) == datamodels.image.ImageModel:
            # Not a great solution at the moment. Save
            # imagemodel instance so that you have a fits
            # file from which the header can be retrieved
            input_mod = copy(self.blotfile)
            self.blotfile.save('temp.fits')
            self.blotfile = 'temp.fits'
            outbase = 'mosaic'

        else:
            raise ValueError('WARNING: unrecognized type for blotfile')

        # Create a GWCS object from the input file's header
        input_header = fits.getheader(self.blotfile, ext=1)
        transform = gwcs.utils.make_fitswcs_transform(input_header)
        input_mod.meta.wcs = gwcs.WCS(forward_transform=transform,
                                      output_frame='world')

        # Filter and pupil information
        filtername = input_mod.meta.instrument.filter
        try:
            pupil = input_mod.meta.instrument.pupil
        except:
            pupil = 'CLEAR'

        # Get position angle of input data
        input_pav3 = input_mod.meta.wcsinfo.roll_ref

        # Name of temporary file output for set_telescope_pointing
        # to work on
        shellname = 'temp_wcs_container.fits'

        blist = []
        for (aper, det, ra, dec, roll) in \
            zip(self.aperture, self.detector, self.center_ra, self.center_dec, self.pav3):
            # Get aperture-specific info
            self.siaf = get_instance(self.instrument)[aper]

            # Create datamodel with appropriate metadata
            bmodel = self.make_model(det, ra, dec, input_pav3, filtername,
                                     pupil)
            bmodel.save(shellname, overwrite=True)

            # Use set_telescope_pointing to compute local roll
            # angle and PC matrix
            stp.add_wcs(shellname, roll=roll)

            bmodel = datamodels.open(shellname)

            # Now we need to run assign_wcs step so that these
            # files get a gwcs object attached to them.
            if self.distortion_file is not None:
                bmodel = AssignWcsStep.call(
                    bmodel, override_distortion=self.distortion_file)
            else:
                bmodel = AssignWcsStep.call(bmodel)

            # Add to the list of data model instances to blot to
            blist.append(bmodel)

        # Place the model instances to blot to in a ModelContainer
        blot_list = container.ModelContainer(blist)

        # Blot the image to each of the WCSs in the blot_list
        pars = {'sinscl': 1.0, 'interp': 'poly5'}
        reffiles = {}
        blotter = outlier_detection.OutlierDetection(blot_list,
                                                     reffiles=reffiles,
                                                     **pars)
        blotter.input_models = blot_list
        self.blotted_datamodels = blotter.blot_median(input_mod)
Beispiel #7
0
    def set_correction(self,
                       matrix=[[1, 0], [0, 1]],
                       shift=[0, 0],
                       ref_tpwcs=None,
                       meta=None,
                       **kwargs):
        """
        Sets a tangent-plane correction of the GWCS object according to
        the provided liniar parameters. In addition, this function updates
        the ``meta`` attribute of the `JWSTgWCS` object with the values
        of keyword arguments except for the argument ``meta`` which is
        *merged* with the *attribute* ``meta``.

        Parameters
        ----------
        matrix: list, numpy.ndarray
            A ``2x2`` array or list of lists coefficients representing scale,
            rotation, and/or skew transformations.

        shift: list, numpy.ndarray
            A list of two coordinate shifts to be applied to coordinates
            *after* ``matrix`` transformations are applied.

        ref_tpwcs: TPWCS, None, optional
            A reference WCS of the type ``TPWCS`` that provides the tangent
            plane in which corrections (``matrix`` and ``shift``) were defined.
            When not provided (i.e., set to `None`), it is assumed that the
            transformations are being applied directly to *this* image WCS'
            tangent plane.

        meta: dict, None, optional
            Dictionary that will be merged to the object's ``meta`` fields.

        **kwargs: optional parameters
            Optional parameters for the WCS corrector. `JWSTgWCS` ignores these
            arguments (except for storing them in the ``meta`` attribute).

        """
        frms = self._wcs.available_frames

        if ref_tpwcs is None:
            matrix = np.array(matrix, dtype=np.double)
            shift = np.array(shift, dtype=np.double)
        else:
            # compute linear transformation from the tangent plane used for
            # alignment to the tangent plane of this wcs:
            r, t = _tp2tp(ref_tpwcs, self)
            matrix = np.linalg.multi_dot([r, matrix, inv(r)]).astype(np.double)
            shift = (np.dot(r, shift) - np.dot(matrix, t) + t).astype(
                np.double)

        # if original WCS did not have tangent-plane corrections, create
        # new correction and add it to the WCs pipeline:
        if self._tpcorr is None:
            self._tpcorr = JWSTgWCS._tpcorr_init(
                v2_ref=self._wcsinfo['v2_ref'] / 3600.0,
                v3_ref=self._wcsinfo['v3_ref'] / 3600.0,
                roll_ref=self._wcsinfo['roll_ref'])

            JWSTgWCS._tpcorr_combine_affines(self._tpcorr, matrix,
                                             _ARCSEC2RAD * np.asarray(shift))

            self._partial_tpcorr = JWSTgWCS._v2v3_to_tpcorr_from_full(
                self._tpcorr)

            idx_v2v3 = frms.index(self._v23name)
            pipeline = deepcopy(self._wcs.pipeline)
            pf, pt = pipeline[idx_v2v3]
            pipeline[idx_v2v3] = (pf, deepcopy(self._tpcorr))
            frm_v2v3corr = deepcopy(pf)
            frm_v2v3corr.name = 'v2v3corr'
            pipeline.insert(idx_v2v3 + 1, (frm_v2v3corr, pt))
            self._wcs = gwcs.WCS(pipeline, name=self._owcs.name)
            self._v23name = 'v2v3corr'

        else:
            # combine old and new corrections into a single one and replace
            # old transformation with the combined correction transformation:
            JWSTgWCS._tpcorr_combine_affines(self._tpcorr, matrix,
                                             _ARCSEC2RAD * np.asarray(shift))

            self._partial_tpcorr = JWSTgWCS._v2v3_to_tpcorr_from_full(
                self._tpcorr)

            idx_v2v3 = frms.index(self._v23name)
            pipeline = deepcopy(self._wcs.pipeline)
            pipeline[idx_v2v3 - 1] = (pipeline[idx_v2v3 - 1].frame,
                                      deepcopy(self._tpcorr))
            self._wcs = gwcs.WCS(pipeline, name=self._owcs.name)

        # reset definitions of the transformations from detector/world
        # coordinates to the tangent plane:
        self._update_transformations()

        # save linear transformation info to the meta attribute:
        super().set_correction(matrix=matrix, shift=shift, meta=meta, **kwargs)
Beispiel #8
0
    def blot(self):

        # Make sure detector, ra, dec, and roll have same number
        # of elements
        if ((len(self.detector) != len(self.center_ra)) | \
                (len(self.detector) != len(self.center_dec)) | \
                (len(self.detector) != len(self.pav3))):
            print('WARNING: detector, center_ra, center_dec')
            print('and pav3 all must have the same number')
            print('of elements.')
            sys.exit()

        if type(self.blotfile) == str:
            input_mod = datamodels.ImageModel(self.blotfile)
            outbase = self.blotfile

            # Create a GWCS object from the input file's header
            #input_header = fits.getheader(self.blotfile)
            #transform = gwcs.utils.make_fitswcs_transform(header)
            #input_mod.meta.wcs = gwcs.WCS(transform)

        elif type(self.blotfile) == datamodels.image.ImageModel:
            # Not a great solution at the moment. Save
            # imagemodel instance so that you have a fits
            # file from which the header can be retrieved
            input_mod = copy(self.blotfile)
            self.blotfile.save('temp.fits')
            self.blotfile = 'temp.fits'
            outbase = 'mosaic'

        else:
            print('WARNING: unrecognized type for blotfile')
            sys.exit()

        # Create a GWCS object from the input file's header
        input_header = fits.getheader(self.blotfile, ext=1)
        transform = gwcs.utils.make_fitswcs_transform(input_header)
        input_mod.meta.wcs = gwcs.WCS(forward_transform=transform,
                                      output_frame='world')
        # Filter and pupil information
        filter = input_mod.meta.instrument.filter
        try:
            pupil = input_mod.meta.instrument.pupil
        except:
            pupil = 'CLEAR'

        # get position angle of input data
        input_pav3 = input_mod.meta.wcsinfo.roll_ref

        # parity is always -1 for nircam
        parity = -1

        # Name of temporary file output for set_telescope_pointing
        # to work on
        shellname = 'temp_wcs_container.fits'

        blist = []
        for (det,ra,dec,roll) in \
            zip(self.detector,self.center_ra,\
                self.center_dec,self.pav3):
            # get detector-specific info
            v2ref, v3ref, v3ang = self.get_siaf_info(det)

            # create datamodel with appropriate metadata
            bmodel = self.make_model(det, ra, dec, v2ref, v3ref, v3ang, parity,
                                     input_pav3, filter, pupil)
            #shellname = 'wcs_model_to_blot_to_{}_{}_{}_{}.fits'.format(det,ra,dec,roll)
            bmodel.save(shellname, overwrite=True)

            #tmpname = 'wcs_model_to_blot_to_BASEMODEL_{}_{}_{}_{}.fits'.format(det,ra,dec,roll)
            #bmodel.save(tmpname,overwrite=True)

            # use set_telescope_pointing to compute local roll
            # angle and PC matrix
            stp.add_wcs(shellname, roll=roll)

            bmodel = datamodels.open(shellname)

            # Now we need to run assign_wcs step so that these
            # files get a gwcs object attached to them.
            dist_reffile = [s for s in self.distfiles if det in s][0]
            bmodel = AssignWcsStep.call(bmodel,
                                        override_distortion=dist_reffile)

            #tmpname = 'wcs_model_to_blot_to_ASSIGNWCS_{}_{}_{}_{}.fits'.format(det,ra,dec,roll)
            #bmodel.save(tmpname,overwrite=True)

            # Add to the list of data model instances to blot to
            blist.append(bmodel)

        #place the model instances to blot to in a ModelContainer
        blot_list = container.ModelContainer(blist)

        #blot the image to each of the WCSs in the blot_list
        pars = {'sinscl': 1.0, 'interp': 'poly5'}
        reffiles = {}
        mm = outlier_detection.OutlierDetection(blot_list,
                                                reffiles=reffiles,
                                                **pars)
        blotted_datamodels = outlier_detection.blot_median(
            input_mod, blot_list, **mm.outlierpars)

        for (bltted,det,ra,dec,roll) in \
            zip(blotted_datamodels,self.detector,self.center_ra,\
                self.center_dec,self.pav3):
            if self.outfile is None:
                self.outfile = 'blotted_from_{}_to_{}_{}_{}_{}.fits'.format(
                    outbase, det, ra, dec, roll)
            bltted.save(self.outfile)
Beispiel #9
0
    def set_correction(self, matrix=[[1, 0], [0, 1]], shift=[0, 0], meta=None,
                       **kwargs):
        """
        Sets a tangent-plane correction of the GWCS object according to
        the provided liniar parameters. In addition, this function updates
        the ``meta`` attribute of the `JWSTgWCS` object with the values
        of keyword arguments except for the argument ``meta`` which is
        *merged* with the *attribute* ``meta``.

        Parameters
        ----------
        matrix : list, numpy.ndarray
            A ``2x2`` array or list of lists coefficients representing scale,
            rotation, and/or skew transformations.

        shift : list, numpy.ndarray
            A list of two coordinate shifts to be applied to coordinates
            *before* ``matrix`` transformations are applied.

        meta : dict, None, optional
            Dictionary that will be merged to the object's ``meta`` fields.

        **kwargs : optional parameters
            Optional parameters for the WCS corrector. `JWSTgWCS` ignores these
            arguments (except for storing them in the ``meta`` attribute).

        """
        frms = self._wcs.available_frames

        # if original WCS did not have tangent-plane corrections, create
        # new correction and add it to the WCs pipeline:
        if self._tpcorr is None:
            self._tpcorr = TPCorr(
                v2ref=self._wcsinfo['v2_ref'] / 3600.0,
                v3ref=self._wcsinfo['v3_ref'] / 3600.0,
                roll=self._wcsinfo['roll_ref'],
                matrix=matrix,
                shift=shift,
                name='tangent-plane linear correction'
            )
            idx_v2v3 = frms.index(self._v23name)
            pipeline = deepcopy(self._wcs.pipeline)
            pf, pt = pipeline[idx_v2v3]
            pipeline[idx_v2v3] = (pf, deepcopy(self._tpcorr))
            frm_v2v3corr = deepcopy(pf)
            frm_v2v3corr.name = 'v2v3corr'
            pipeline.insert(idx_v2v3 + 1, (frm_v2v3corr, pt))
            self._wcs = gwcs.WCS(pipeline, name=self._owcs.name)
            self._v23name = 'v2v3corr'

        else:
            # combine old and new corrections into a single one and replace
            # old transformation with the combined correction transformation:
            tpcorr2 = self._tpcorr.__class__(
                v2ref=self._tpcorr.v2ref, v3ref=self._tpcorr.v3ref,
                roll=self._tpcorr.roll, matrix=matrix, shift=shift,
                name='tangent-plane linear correction'
            )

            self._tpcorr = tpcorr2.combine(tpcorr2, self._tpcorr)

            idx_v2v3 = frms.index(self._v23name)
            pipeline = deepcopy(self._wcs.pipeline)
            pipeline[idx_v2v3 - 1] = (pipeline[idx_v2v3 - 1][0],
                                      deepcopy(self._tpcorr))
            self._wcs = gwcs.WCS(pipeline, name=self._owcs.name)

        # reset definitions of the transformations from detector/world
        # coordinates to the tangent plane:
        self._update_transformations()

        # save linear transformation info to the meta attribute:
        self._meta['matrix'] = matrix
        self._meta['shift'] = shift
        if meta is not None:
            self._meta.update(meta)
Beispiel #10
0
def _make_gwcs_wcs(fits_hdr):
    hdr = fits.Header.fromfile(get_pkg_data_filename(fits_hdr))
    fw = fitswcs.WCS(hdr)

    a_order = hdr['A_ORDER']
    a_coeff = {}
    for i in range(a_order + 1):
        for j in range(a_order + 1 - i):
            key = 'A_{:d}_{:d}'.format(i, j)
            if key in hdr:
                a_coeff[key] = hdr[key]

    b_order = hdr['B_ORDER']
    b_coeff = {}
    for i in range(b_order + 1):
        for j in range(b_order + 1 - i):
            key = 'B_{:d}_{:d}'.format(i, j)
            if key in hdr:
                b_coeff[key] = hdr[key]

    cx = {"c" + k[2:]: v for k, v in a_coeff.items()}
    cy = {"c" + k[2:]: v for k, v in b_coeff.items()}
    sip_distortion = ((Shift(-fw.wcs.crpix[0]) & Shift(-fw.wcs.crpix[1]))
                      | Mapping((0, 1, 0, 1))
                      | (polynomial.Polynomial2D(a_order, **cx, c1_0=1)
                         & polynomial.Polynomial2D(b_order, **cy, c0_1=1))
                      | (Shift(fw.wcs.crpix[0]) & Shift(fw.wcs.crpix[1])))

    y, x = np.indices(fw.array_shape)

    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)

    sip_distortion |= (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, sip_distortion), (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))

    # sanity check:
    for _ in range(100):
        x = np.random.randint(1, fw.pixel_shape[0])
        y = np.random.randint(1, fw.pixel_shape[1])
        assert np.allclose(gw(x, y),
                           fw.all_pix2world(x, y, 1),
                           rtol=0,
                           atol=1e-11)

    return gw
Beispiel #11
0
 def wcs(self):
     return gwcs.WCS(forward_transform=self.model,
                     input_frame=self._generate_generic_frame(
                         self.model.n_inputs, u.pix),
                     output_frame=self.frame)