def test_nirspec_nrs1_wcs(self):
        """

        Regression test of creating a WCS object and doing pixel to sky transformation.

        """
        input_file = self.get_data(*self.test_dir,
                                  'jw00023001001_01101_00001_NRS1_ramp_fit.fits')
        ref_file = self.get_data(*self.ref_loc,
                                 'jw00023001001_01101_00001_NRS1_ramp_fit_assign_wcs.fits')

        result = AssignWcsStep.call(input_file, save_results=True, suffix='assign_wcs')
        result.close()

        im = ImageModel(result.meta.filename)
        imref = ImageModel(ref_file)

        for slit in ['S200A1', 'S200A2', 'S400A1', 'S1600A1']:
            w = nirspec.nrs_wcs_set_input(im, slit)
            grid = grid_from_bounding_box(w.bounding_box)
            ra, dec, lam = w(*grid)
            wref = nirspec.nrs_wcs_set_input(imref, slit)
            raref, decref, lamref = wref(*grid)

            assert_allclose(ra, raref, equal_nan=True)
            assert_allclose(dec, decref, equal_nan=True)
            assert_allclose(lam, lamref, equal_nan=True)
Example #2
0
def test_nirspec_ifu_wcs(envopt, _jail, test_id, input_file, truth_file):
    """
    Regression test of creating a WCS object and doing pixel to sky transformation.
    """
    del test_id

    input_file = get_bigdata('jwst-pipeline', envopt,
                             'nirspec', 'test_wcs', 'nrs1-ifu', input_file)
    truth_file = get_bigdata('jwst-pipeline', envopt,
                             'nirspec', 'test_wcs', 'nrs1-ifu', 'truth', truth_file)

    result = AssignWcsStep.call(input_file, save_results=True, suffix='assign_wcs')
    result.close()

    im = ImageModel(result.meta.filename)
    imref = ImageModel(truth_file)
    w = nirspec.nrs_wcs_set_input(im, 0)
    grid = grid_from_bounding_box(w.bounding_box)
    ra, dec, lam = w(*grid)
    wref = nirspec.nrs_wcs_set_input(imref, 0)
    raref, decref, lamref = wref(*grid)

    # equal_nan is used here as many of the entries are nan.
    # The domain is defined but it is only a few entries in there that are valid
    # as it is a curved narrow slit.
    assert_allclose(ra, raref, equal_nan=True)
    assert_allclose(dec, decref, equal_nan=True)
    assert_allclose(lam, lamref, equal_nan=True)
Example #3
0
    def __init__(self, median_model, input_models):

        #Pull out the needed information from the Median IFUCube
        self.median_skycube = median_model
        self.instrument = median_model.meta.instrument.name
        self.detector = median_model.meta.instrument.detector
        #information on how the IFUCube was constructed
        self.weight_power = median_model.meta.weight_power
        self.weighting = median_model.meta.weighting  # if AREA ABORT
        self.rois = median_model.meta.roi_spatial
        self.roiw = median_model.meta.roi_wave

        #basic information about the type of data
        self.grating = None
        self.filter = None
        self.subchannel = None
        self.channel = None

        if (self.instrument == 'MIRI'):
            self.channel = median_model.meta.instrument.channel
            self.subchannel = median_model.meta.instrument.band
        elif (self.instrument == 'NIRSPEC'):
            self.grating = median_model.meta.instrument.grating
            self.filter = median_model.meta.instrument.filter

        # find the ra,dec,lambda of each element of the IFUCube
        self.naxis1 = self.median_skycube.data.shape[2]
        self.naxis2 = self.median_skycube.data.shape[1]
        self.naxis3 = self.median_skycube.data.shape[0]
        self.cdelt1 = median_model.meta.wcsinfo.cdelt1 * 3600.0
        self.cdelt2 = median_model.meta.wcsinfo.cdelt2 * 3600.0
        self.cdelt3 = median_model.meta.wcsinfo.cdelt3 * 3600.0

        xcube, ycube, zcube = wcstools.grid_from_bounding_box(
            self.median_skycube.meta.wcs.bounding_box, step=(1, 1, 1))

        cube_pos1, cube_pos2, cube_pos3 = self.median_skycube.meta.wcs(
            xcube, ycube, zcube)
        num = self.naxis1 * self.naxis2 * self.naxis3
        flux = self.median_skycube.data
        self.cube_ra = cube_pos1
        self.cube_dec = cube_pos2
        self.cube_wave = cube_pos3
        self.cube_flux = flux

        self.lam_centers = self.cube_wave[:, 0, 0]

        #        self.cube_ra = np.reshape(cube_pos1,num)
        #        self.cube_dec = np.reshape(cube_pos2,num)
        #        self.cube_wave = np.reshape(cube_pos3,num)
        #        self.cube_flux = np.reshape(flux,num)
        #        print('size of input cube',cube_pos1.shape,cube_pos2.shape,cube_pos3.shape)
        # initialize blotted images to be original input images

        self.input_models = input_models
Example #4
0
    def test_miri_ifu_wcs(self):
        """
        Regression test of creating a WCS object and doing pixel to sky transformation.
        """
        input_file = self.get_data(
            self.test_dir,
            'jw00024001001_01101_00001_MIRIFUSHORT_uncal_MiriSloperPipeline.fits'
        )
        result = AssignWcsStep.call(input_file, save_results=True)

        # Get the region file
        region = RegionsModel(crds_client.get_reference_file(
            result, 'regions'))
        # Choose the same plane as in the miri.py file (hardcoded for now).
        regions = region.regions[7, :, :]

        # inputs
        x, y = grid_from_bounding_box(result.meta.wcs.bounding_box)

        # Get indices where pixels == 0. These should be NaNs in the output.
        ind_zeros = regions == 0

        cwd = os.path.abspath('.')
        os.makedirs('truth', exist_ok=True)
        os.chdir('truth')
        truth_file = self.get_data(
            *self.ref_loc,
            'jw00024001001_01101_00001_MIRIFUSHORT_assign_wcs.fits')
        os.chdir(cwd)
        truth = ImageModel(truth_file)

        ra, dec, lam = result.meta.wcs(x, y)
        raref, decref, lamref = truth.meta.wcs(x, y)
        assert_allclose(ra, raref, equal_nan=True)
        assert_allclose(dec, decref, equal_nan=True)
        assert_allclose(lam, lamref, equal_nan=True)

        # Test that we got NaNs at ind_zero
        assert (np.isnan(ra).nonzero()[0] == ind_zeros.nonzero()[0]).all()
        assert (np.isnan(ra).nonzero()[1] == ind_zeros.nonzero()[1]).all()

        # Test the inverse transform
        x1, y1 = result.meta.wcs.backward_transform(ra, dec, lam)
        assert (np.isnan(x1).nonzero()[0] == ind_zeros.nonzero()[0]).all()
        assert (np.isnan(x1).nonzero()[1] == ind_zeros.nonzero()[1]).all()

        # Also run a smoke test with values outside the region.
        dec[100][200] = -80
        ra[100][200] = 7
        lam[100][200] = 15

        x2, y2 = result.meta.wcs.backward_transform(ra, dec, lam)
        assert np.isnan(x2[100][200])
        assert np.isnan(x2[100][200])
Example #5
0
def test_nirspec_wcs_roundtrip(nirspec_rate):
    im = AssignWcsStep.call(nirspec_rate)
    im = Extract2dStep.call(im)
    im = ResampleSpecStep.call(im)

    for slit in im.slits:
        x, y = grid_from_bounding_box(slit.meta.wcs.bounding_box)
        ra, dec, lam = slit.meta.wcs(x, y)
        xp, yp = slit.meta.wcs.invert(ra, dec, lam)

        assert_allclose(x, xp, atol=1e-8)
        assert_allclose(y, yp, atol=1e-8)
Example #6
0
    def test_miri_lrs_masterbg_user(self):
        """
        Regression test of masterbackgound subtraction with lrs, with user provided 1-D background
        """

        # input file has the background added
        input_file = self.get_data(*self.test_dir, 'miri_lrs_sci+bkg_cal.fits')
        # user provided 1-D background
        user_background = self.get_data(*self.test_dir,
                                        'miri_lrs_bkg_x1d.fits')

        result = MasterBackgroundStep.call(input_file,
                                           user_background=user_background,
                                           save_results=True)

        # Compare result (background subtracted image) to science image with no
        # background. Subtract these images, smooth the subtracted image and
        # the mean should be close to zero.
        input_sci_cal_file = self.get_data(*self.test_dir,
                                           'miri_lrs_sci_cal.fits')
        input_sci = datamodels.open(input_sci_cal_file)

        # find the LRS region
        bb = result.meta.wcs.bounding_box
        x, y = grid_from_bounding_box(bb)
        result_lrs_region = result.data[y.astype(int), x.astype(int)]
        sci_lrs_region = input_sci.data[y.astype(int), x.astype(int)]

        # do a 5 sigma clip on the science image
        sci_mean = np.nanmean(sci_lrs_region)
        sci_std = np.nanstd(sci_lrs_region)
        upper = sci_mean + sci_std * 5.0
        lower = sci_mean - sci_std * 5.0
        mask_clean = np.logical_and(sci_lrs_region < upper,
                                    sci_lrs_region > lower)

        sub = result_lrs_region - sci_lrs_region
        mean_sub = np.absolute(np.mean(sub[mask_clean]))

        atol = 0.1
        rtol = 0.001
        assert_allclose(mean_sub, 0, atol=atol, rtol=rtol)

        # Test 3 Compare background subtracted science data (results)
        #  to a truth file.
        truth_file = self.get_data(
            *self.ref_loc, 'miri_lrs_sci+bkg_masterbackgroundstep.fits')

        result_file = result.meta.filename
        outputs = [(result_file, truth_file)]
        self.compare_outputs(outputs)
        result.close()
        input_sci.close()
Example #7
0
def spec_footprint(in_wcs, bounding_box=None, mask=None):
    """
    Returns wcs footprint grid coordinates where NaNs are masked.

    Build-7 workaround.
    """
    x, y = wcstools.grid_from_bounding_box(in_wcs.bounding_box,
                                           step=(1, 1),
                                           center=True)
    ra, dec, lam = in_wcs(x, y)
    m = np.isnan(lam)
    return ma.array([ra, dec, lam], mask=[m, m, m])
Example #8
0
def calc_gwcs_pixmap(in_wcs, out_wcs, shape=None):
    """ Return a pixel grid map from input frame to output frame.
    """
    if shape:
        bb = wcs_bbox_from_shape(shape)
        log.debug("Bounding box from data shape: {}".format(bb))
    else:
        bb = in_wcs.bounding_box
        log.debug("Bounding box from WCS: {}".format(in_wcs.bounding_box))

    grid = wcstools.grid_from_bounding_box(bb, step=(1, 1))
    pixmap = np.dstack(reproject(in_wcs, out_wcs)(grid[0], grid[1]))
    return pixmap
Example #9
0
def calc_gwcs_pixmap(in_wcs, out_wcs, shape=None):
    """ Return a pixel grid map from input frame to output frame.
    """
    if shape:
        bb = bounding_box_from_shape(shape)
        log.debug("Bounding box from data shape: {}".format(bb))
    else:
        bb = in_wcs.bounding_box
        log.debug("Bounding box from WCS: {}".format(in_wcs.bounding_box))

    grid = wcstools.grid_from_bounding_box(bb, step=(1, 1))
    pixmap = np.dstack(reproject(in_wcs, out_wcs)(grid[0], grid[1]))
    return pixmap
Example #10
0
def bkg_for_ifu_image(input, tab_wavelength, tab_background):
    """Create a 2-D background for an IFUImageModel

    Parameters
    ----------
    input : `~jwst.datamodels.IFUImageModel`
        The input science data.

    tab_wavelength : 1-D ndarray
        The wavelength column read from the 1-D background table.

    tab_background : 1-D ndarray
        The flux column read from the 1-D background table, divided by
        the npixels column.

    Returns
    -------
    background : `~jwst.datamodels.IFUImageModel`
        A copy of `input` but with the data replaced by the background,
        "expanded" from 1-D to 2-D.
    """

    background = input.copy()
    background.data[:, :] = 0.

    if input.meta.instrument.name.upper() == "NIRSPEC":
        list_of_wcs = nirspec.nrs_ifu_wcs(input)
        for ifu_wcs in list_of_wcs:
            x, y = grid_from_bounding_box(ifu_wcs.bounding_box)
            wl_array = ifu_wcs(x, y)[2]

            wl_array[np.isnan(wl_array)] = -1.
            bkg_flux = np.interp(wl_array, tab_wavelength, tab_background,
                                 left=0., right=0.)
            background.data[y.astype(int), x.astype(int)] = bkg_flux.copy()

    elif input.meta.instrument.name.upper() == "MIRI":
        shape = input.data.shape
        grid = np.indices(shape, dtype=np.float64)
        wl_array = ifu_wcs(grid[1], grid[0])[2]

        wl_array[np.isnan(wl_array)] = -1.
        bkg_flux = np.interp(wl_array, tab_wavelength, tab_background,
                             left=0., right=0.)
        background.data[:, :] = bkg_flux.copy()

    else:
        raise RuntimeError("Exposure type {} is not supported."
                           .format(input.meta.exposure.type))

    return background
Example #11
0
    def test_miri_lrs_masterbg_user(self):
        """
        Regression test of masterbackgound subtraction with lrs, with user provided 1-D background
        """

        # input file has the background added
        input_file = self.get_data(*self.test_dir, 'miri_lrs_sci+bkg_cal.fits')
        # user provided 1-D background
        user_background = self.get_data(*self.test_dir, 'miri_lrs_bkg_x1d.fits')

        result = MasterBackgroundStep.call(input_file,
                                           user_background=user_background,
                                           save_results=True)

        # Compare result (background subtracted image) to science image with no
        # background. Subtract these images, smooth the subtracted image and
        # the mean should be close to zero.
        input_sci_cal_file = self.get_data(*self.test_dir,
                                            'miri_lrs_sci_cal.fits')
        input_sci = datamodels.open(input_sci_cal_file)

        # find the LRS region
        bb = result.meta.wcs.bounding_box
        x, y = grid_from_bounding_box(bb)
        result_lrs_region = result.data[y.astype(int), x.astype(int)]
        sci_lrs_region = input_sci.data[y.astype(int), x.astype(int)]

        # do a 5 sigma clip on the science image
        sci_mean = np.nanmean(sci_lrs_region)
        sci_std = np.nanstd(sci_lrs_region)
        upper = sci_mean + sci_std*5.0
        lower = sci_mean - sci_std*5.0
        mask_clean = np.logical_and(sci_lrs_region < upper, sci_lrs_region > lower)

        sub = result_lrs_region - sci_lrs_region
        mean_sub = np.absolute(np.mean(sub[mask_clean]))

        atol = 0.1
        rtol = 0.001
        assert_allclose(mean_sub, 0, atol=atol, rtol=rtol)

        # Test 3 Compare background subtracted science data (results)
        #  to a truth file.
        truth_file = self.get_data(*self.ref_loc,
                                  'miri_lrs_sci+bkg_masterbackgroundstep.fits')

        result_file = result.meta.filename
        outputs = [(result_file, truth_file)]
        self.compare_outputs(outputs)
        result.close()
        input_sci.close()
Example #12
0
def update_s_region_spectral(model):
    swcs = model.meta.wcs

    bbox = swcs.bounding_box
    if bbox is None:
        bbox = bounding_box_from_shape(model.data.shape)

    x, y = grid_from_bounding_box(bbox)
    ra, dec, lam = swcs(x, y)
    footprint = np.array([[np.nanmin(ra), np.nanmin(dec)],
                 [np.nanmax(ra), np.nanmin(dec)],
                 [np.nanmax(ra), np.nanmax(dec)],
                 [np.nanmin(ra), np.nanmax(dec)]])
    update_s_region_keyword(model, footprint)
Example #13
0
def update_s_region_spectral(model):
    swcs = model.meta.wcs

    bbox = swcs.bounding_box
    if bbox is None:
        bbox = wcs_bbox_from_shape(model.data.shape)

    x, y = grid_from_bounding_box(bbox)
    ra, dec, lam = swcs(x, y)
    footprint = np.array([[np.nanmin(ra), np.nanmin(dec)],
                          [np.nanmax(ra), np.nanmin(dec)],
                          [np.nanmax(ra), np.nanmax(dec)],
                          [np.nanmin(ra), np.nanmax(dec)]])
    update_s_region_keyword(model, footprint)
Example #14
0
    def _max_virtual_slit_extent(self, wcs_list, target_ra, target_dec):
        """
        Compute min & max slit coordinates for all nods in the "virtual"
        slit frame.

        NOTE: this code, potentially, might have troubles dealing
              with large dithers such that ``target_ra`` and ``target_dec``
              may not be converted to slit frame (i.e., result in ``NaN``).

              A more sophisticated algorithm may be needed to "stitch" large
              dithers. But then distortions may come into play.
        """
        y_slit_min = np.inf
        y_slit_max = -np.inf

        t0 = 0

        for wcs in wcs_list:
            d2s = wcs.get_transform('detector', 'slit_frame')
            w2s = wcs.get_transform('world', 'slit_frame')

            x, y = wcstools.grid_from_bounding_box(wcs.bounding_box)
            ra, dec, lam = wcs(x, y)

            good = np.logical_and(np.isfinite(ra), np.isfinite(dec))
            x = x[good]
            y = y[good]
            lm = lam[good]

            _, yslit, _ = d2s(x, y)

            # position of the target in the slit relative to its position
            # for the refence image:
            ts = w2s(target_ra, target_dec, np.mean(lm))[1] - t0

            if wcs is wcs_list[0]:
                t0 = ts
                ts = 0

            y_slit_min_i = np.min(yslit) - ts
            y_slit_max_i = np.max(yslit) - ts

            if y_slit_min_i < y_slit_min:
                y_slit_min = y_slit_min_i

            if y_slit_max_i > y_slit_max:
                y_slit_max = y_slit_max_i

        return y_slit_min, y_slit_max
Example #15
0
def test_NIRCAMForwardRowGrismDispersion():
    xmodels = [
        Polynomial1D(1, c0=0.59115385, c1=0.00038615),
        Polynomial1D(1, c0=-0.16596154, c1=0.00019308)
    ]
    ymodels = [Polynomial1D(1, c0=0., c1=0.), Polynomial1D(1, c0=0., c1=0.)]
    lmodels = [
        Polynomial1D(1, c0=2.4, c1=2.6),
        Polynomial1D(1, c0=2.4, c1=2.6)
    ]
    model = transforms.NIRCAMForwardRowGrismDispersion([1, 2], lmodels,
                                                       xmodels, ymodels)

    x0 = 913.7
    y0 = 15.5
    order = 1

    slit = create_slit(model, x0, y0, order)

    expected = np.array([[
        3.03973415, 3.04073814, 3.04174213, 3.04274612, 3.04375011, 3.0447541
    ], [3.03973415, 3.04073814, 3.04174213, 3.04274612, 3.04375011, 3.0447541],
                         [
                             3.03973415, 3.04073814, 3.04174213, 3.04274612,
                             3.04375011, 3.0447541
                         ],
                         [
                             3.03973415, 3.04073814, 3.04174213, 3.04274612,
                             3.04375011, 3.0447541
                         ],
                         [
                             3.03973415, 3.04073814, 3.04174213, 3.04274612,
                             3.04375011, 3.0447541
                         ],
                         [
                             3.03973415, 3.04073814, 3.04174213, 3.04274612,
                             3.04375011, 3.0447541
                         ]])

    # refactored call
    x, y = grid_from_bounding_box(slit.meta.wcs.bounding_box)
    wavelength = compute_wavelength_array(
        slit
    )  # x, y, np.zeros(x.shape)  +x0, np.zeros(y.shape)+y0, np.zeros(x.shape)+order)
    assert_allclose(wavelength, expected)

    with pytest.raises(ValueError):
        slit = create_slit(model, x0, y0, 3)
        compute_wavelength_array(slit)
Example #16
0
    def test_miri_ifu_wcs(self):
        """
        Regression test of creating a WCS object and doing pixel to sky transformation.
        """
        input_file = self.get_data(self.test_dir,
                                   'jw00024001001_01101_00001_MIRIFUSHORT_uncal_MiriSloperPipeline.fits')
        result = AssignWcsStep.call(input_file, save_results=True)

        # Get the region file
        region = RegionsModel(crds_client.get_reference_file(result, 'regions'))

        # inputs
        x, y = grid_from_bounding_box(result.meta.wcs.bounding_box)

        # Get indices where pixels == 0. These should be NaNs in the output.
        ind_zeros = region.regions == 0

        cwd = os.path.abspath('.')
        os.makedirs('truth', exist_ok=True)
        os.chdir('truth')
        truth_file = self.get_data(*self.ref_loc,
                                 'jw00024001001_01101_00001_MIRIFUSHORT_assign_wcs.fits')
        os.chdir(cwd)
        truth = ImageModel(truth_file)

        ra, dec, lam = result.meta.wcs(x, y)
        raref, decref, lamref = truth.meta.wcs(x, y)
        assert_allclose(ra, raref, equal_nan=True)
        assert_allclose(dec, decref, equal_nan=True)
        assert_allclose(lam, lamref, equal_nan=True)

        # Test that we got NaNs at ind_zero
        assert(np.isnan(ra).nonzero()[0] == ind_zeros.nonzero()[0]).all()
        assert(np.isnan(ra).nonzero()[1] == ind_zeros.nonzero()[1]).all()

        # Test the inverse transform
        x1, y1 = result.meta.wcs.backward_transform(ra, dec, lam)
        assert(np.isnan(x1).nonzero()[0] == ind_zeros.nonzero()[0]).all()
        assert (np.isnan(x1).nonzero()[1] == ind_zeros.nonzero()[1]).all()

        # Also run a smoke test with values outside the region.
        dec[100][200] = -80
        ra[100][200] = 7
        lam[100][200] = 15

        x2, y2 = result.meta.wcs.backward_transform(ra, dec, lam)
        assert np.isnan(x2[100][200])
        assert np.isnan(x2[100][200])
def test_tweakreg_with_gaia(run_image3pipeline, rtdata_module, root):
    """ Test that WCS object works as expected """
    rtdata = rtdata_module
    rtdata.input = root + "_nrca5_cal.fits"
    output_crf = root + "_nrca5_a3001_crf.fits"
    rtdata.output = output_crf
    rtdata.get_truth("truth/test_nircam_align_to_gaia/" + output_crf)

    with datamodels.open(rtdata.output) as model, datamodels.open(rtdata.truth) as model_truth:
        grid = grid_from_bounding_box(model.meta.wcs.bounding_box)

        ra, dec = model.meta.wcs(*grid)
        ra_truth, dec_truth = model_truth.meta.wcs(*grid)

        assert_allclose(ra, ra_truth)
        assert_allclose(dec, dec_truth)
Example #18
0
def test_nircam_image_stage2_wcs(run_image2pipeline, rtdata_module):
    """Test that WCS object works as expected"""
    rtdata = rtdata_module
    rtdata.input = "jw42424001001_01101_00001_nrca5_uncal.fits"
    output = "jw42424001001_01101_00001_nrca5_assign_wcs.fits"
    rtdata.output = output
    rtdata.get_truth(f"truth/test_nircam_image_stages/{output}")

    with datamodels.open(rtdata.output) as model, datamodels.open(rtdata.truth) as model_truth:
        grid = grid_from_bounding_box(model.meta.wcs.bounding_box)

        ra, dec = model.meta.wcs(*grid)
        ra_truth, dec_truth = model_truth.meta.wcs(*grid)

        assert_allclose(ra, ra_truth)
        assert_allclose(dec, dec_truth)
Example #19
0
def ifu_world_coord(wcs_ifu_grating):
    """ Return RA, DEC, LAM for all slices in the NRS IFU."""
    ra_all = []
    dec_all = []
    lam_all = []
    im, refs = wcs_ifu_grating(grating="G140H", filter="F100LP")
    for sl in range(30):
        slice_wcs = nirspec.nrs_wcs_set_input(im, sl)
        x, y = wcstools.grid_from_bounding_box(slice_wcs.bounding_box)
        r, d, lam = slice_wcs(x, y)
        ra_all.append(r)
        dec_all.append(d)
        lam_all.append(lam)
    ra_all = np.concatenate([r.flatten() for r in ra_all])
    dec_all = np.concatenate([r.flatten() for r in dec_all])
    lam_all = np.concatenate([r.flatten() for r in lam_all])
    return ra_all, dec_all, lam_all
    def test_miri_fixed_slit_wcs(self):
        """
        Regression test of creating a WCS object and doing pixel to sky transformation.
        """
        input_file = self.get_data(self.test_dir,
                                   'jw00035001001_01101_00001_mirimage_rate.fits')
        result = AssignWcsStep.call(input_file, save_results=True)

        truth_file = self.get_data(os.path.join(*self.ref_loc),
                                 'jw00035001001_01101_00001_mirimage_assign_wcs.fits')
        truth = ImageModel(truth_file)
        x, y = grid_from_bounding_box(result.meta.wcs.bounding_box)
        ra, dec, lam = result.meta.wcs(x, y)
        raref, decref, lamref = truth.meta.wcs(x, y)
        assert_allclose(ra, raref)
        assert_allclose(dec, decref)
        assert_allclose(lam, lamref)
Example #21
0
    def test_miri_fixed_slit_wcs(self):
        """
        Regression test of creating a WCS object and doing pixel to sky transformation.
        """
        input_file = self.get_data(self.test_dir,
                                   'jw00035001001_01101_00001_mirimage_rate.fits')
        result = AssignWcsStep.call(input_file, save_results=True)

        truth_file = self.get_data(os.path.join(*self.ref_loc),
                                 'jw00035001001_01101_00001_mirimage_assign_wcs.fits')
        truth = ImageModel(truth_file)
        x, y = grid_from_bounding_box(result.meta.wcs.bounding_box)
        ra, dec, lam = result.meta.wcs(x, y)
        raref, decref, lamref = truth.meta.wcs(x, y)
        assert_allclose(ra, raref)
        assert_allclose(dec, decref)
        assert_allclose(lam, lamref)
Example #22
0
def test_in_slice(slice, wcs_ifu_grating, ifu_world_coord):
    """ Test that the number of valid outputs from a slice forward transform
    equals the valid pixels within the slice from the slice backward transform.
    """
    ra_all, dec_all, lam_all = ifu_world_coord
    im, refs = wcs_ifu_grating("G140H", "F100LP")
    slice_wcs = nirspec.nrs_wcs_set_input(im, slice)
    slicer2world = slice_wcs.get_transform('slicer', 'world')
    detector2slicer = slice_wcs.get_transform('detector', 'slicer')
    x, y = wcstools.grid_from_bounding_box(slice_wcs.bounding_box)
    onslice_ind = in_ifu_slice(slice_wcs, ra_all, dec_all, lam_all)
    slx, sly, sllam = slicer2world.inverse(ra_all, dec_all, lam_all)
    xinv, yinv = detector2slicer.inverse(slx[onslice_ind], sly[onslice_ind],
                                         sllam[onslice_ind])

    r, d, _ = slice_wcs(x, y)
    assert r[~np.isnan(r)].size == xinv.size
Example #23
0
def compute_wavelength_array(slit):
    """
    Compute the wavelength array for a slit with gwcs object

    Parameters
    ----------
    slit : `~jwst.datamodels.SlitModel`
        JWST slit datamodel containing a meta.wcs GWCS object

    Returns
    -------
    wavelength : numpy.array
        The wavelength array
    """
    transform = slit.meta.wcs.forward_transform
    x, y = grid_from_bounding_box(slit.meta.wcs.bounding_box)
    wavelength = transform(x, y)[2]
    return wavelength
Example #24
0
def test_miri_lrs_slitless_wcs(run_tso_spec2_pipeline, fitsdiff_default_kwargs,
                               rtdata_module):
    """Compare the assign_wcs output of a MIRI LRS slitless calwebb_tso3 pipeline."""
    rtdata = rtdata_module
    output = f"{DATASET_ID}_assign_wcs.fits"
    # get input assign_wcs and truth file
    rtdata.output = output
    rtdata.get_truth("truth/test_miri_lrs_slitless_tso_spec2/" + output)

    # Compare the output and truth file
    with datamodels.open(rtdata.output) as im, datamodels.open(
            rtdata.truth) as im_truth:
        x, y = grid_from_bounding_box(im.meta.wcs.bounding_box)
        ra, dec, lam = im.meta.wcs(x, y)
        ratruth, dectruth, lamtruth = im_truth.meta.wcs(x, y)
        assert_allclose(ra, ratruth)
        assert_allclose(dec, dectruth)
        assert_allclose(lam, lamtruth)
Example #25
0
def test_build_interpolated_output_wcs(miri_rate_pair):
    im1, im2 = miri_rate_pair

    driz = ResampleSpecData(ModelContainer([im1, im2]))
    output_wcs = driz.build_interpolated_output_wcs()

    # Make sure that all RA, Dec values in the input image have a location in
    # the output frame
    grid = grid_from_bounding_box(im2.meta.wcs.bounding_box)
    ra, dec, lam = im2.meta.wcs(*grid)
    x, y = output_wcs.invert(ra, dec, lam)

    # This currently fails, as we see a slight offset
    # assert (x > 0).all()

    # Make sure the output slit size is larger than the input slit size
    # for this nodded data
    assert driz.data_size[1] > ra.shape[1]
Example #26
0
def test_miri_lrs_slitless_wcs(run_tso_spec2_pipeline, fitsdiff_default_kwargs,
                               rtdata_module):

    rtdata = rtdata_module
    output = f"{DATASET_ID}_assign_wcs.fits"
    # get input assign_wcs and truth file
    rtdata.output = output
    rtdata.get_truth("truth/test_miri_lrs_slitless_tso_spec2/" + output)

    # Open the output and truth file
    im = datamodels.open(rtdata.output)
    im_truth = datamodels.open(rtdata.truth)

    x, y = grid_from_bounding_box(im.meta.wcs.bounding_box)
    ra, dec, lam = im.meta.wcs(x, y)
    ratruth, dectruth, lamtruth = im_truth.meta.wcs(x, y)
    assert_allclose(ra, ratruth)
    assert_allclose(dec, dectruth)
    assert_allclose(lam, lamtruth)
Example #27
0
def test_wavecorr():
    hdul = create_nirspec_mos_file()
    msa_meta = os.path.join(
        jwst.__path__[0],
        *['assign_wcs', 'tests', 'data', 'msa_configuration.fits'])
    hdul[0].header['MSAMETFL'] = msa_meta
    hdul[0].header['MSAMETID'] = 12
    im = datamodels.ImageModel(hdul)
    im_wcs = AssignWcsStep.call(im)
    im_ex2d = Extract2dStep.call(im_wcs)
    im_ex2d.slits[0].meta.wcs.bounding_box = ((-.5, 1432.5), (-.5, 37.5))
    im_src = SourceTypeStep.call(im_ex2d)
    im_wave = WavecorrStep.call(im_src)

    # test dispersion is of the correct order
    # there's one slit only
    slit = im_src.slits[0]
    x, y = wcstools.grid_from_bounding_box(slit.meta.wcs.bounding_box)
    dispersion = wavecorr.compute_dispersion(slit.meta.wcs, x, y)
    assert_allclose(dispersion[~np.isnan(dispersion)], 1e-9, atol=1e-10)

    # the difference in wavelength should be of the order of e-10 in um
    assert_allclose(im_src.slits[0].wavelength - im_wave.slits[0].wavelength,
                    1e-10)

    # test on both sides of the shutter
    source_xpos1 = -.2
    source_xpos2 = .2

    ra, dec, lam = slit.meta.wcs(x, y)
    ref_name = im_wave.meta.ref_file.wavecorr.name
    freference = datamodels.WaveCorrModel(
        WavecorrStep.reference_uri_to_cache_path(ref_name,
                                                 im.crds_observatory))
    zero_point1 = wavecorr.compute_zero_point_correction(
        lam, freference, source_xpos1, 'MOS', dispersion)
    zero_point2 = wavecorr.compute_zero_point_correction(
        lam, freference, source_xpos2, 'MOS', dispersion)
    diff_correction = np.abs(zero_point1[1] - zero_point2[1])
    assert_allclose(diff_correction[diff_correction.nonzero()].mean(),
                    0.02,
                    atol=0.01)
Example #28
0
def compute_dispersion(wcs):
    """
    Compute the pixel dispersion.

    Parameters
    ----------
    wcs : `~gwcs.wcs.WCS`
        The WCS object for this slit.

    Returns
    -------
    dispersion : ndarray
        The pixel dispersion [in m].

    """
    xpix, ypix = wcstools.grid_from_bounding_box(wcs.bounding_box, step=(1, 1))
    xleft = xpix - 0.5
    xright = xpix + 0.5
    _, _, lamright = wcs(xright, ypix)
    _, _, lamleft = wcs(xleft, ypix)
    return (lamright - lamleft) * 10**-6
Example #29
0
def test_miri_image_wcs(run_image2, rtdata_module, fitsdiff_default_kwargs):
    rtdata = rtdata_module

    # get input assign_wcs and truth file
    output = "det_image_1_MIRIMAGE_F770Wexp1_5stars_assign_wcs.fits"
    rtdata.output = output
    rtdata.get_truth("truth/test_miri_image_stages/" + output)

    # Open the output and truth file
    with datamodels.open(rtdata.output) as im, datamodels.open(rtdata.truth) as im_truth:
        x, y = grid_from_bounding_box(im.meta.wcs.bounding_box)
        ra, dec = im.meta.wcs(x, y)
        ratruth, dectruth = im_truth.meta.wcs(x, y)
        assert_allclose(ra, ratruth)
        assert_allclose(dec, dectruth)

        # Test the inverse transform
        xtest, ytest = im.meta.wcs.backward_transform(ra, dec)
        xtruth, ytruth = im_truth.meta.wcs.backward_transform (ratruth, dectruth)
        assert_allclose(xtest, xtruth)
        assert_allclose(ytest, ytruth)
Example #30
0
def compute_footprint_spectral(model):
    """
    Determine spatial footprint for spectral observations using the instrument model.

    Parameters
    ----------
    output_model : `~jwst.datamodels.IFUImageModel`
        The output of assign_wcs.
    """
    swcs = model.meta.wcs
    bbox = swcs.bounding_box
    if bbox is None:
        bbox = wcs_bbox_from_shape(model.data.shape)

    x, y = grid_from_bounding_box(bbox)
    ra, dec, lam = swcs(x, y)
    footprint = np.array([[np.nanmin(ra), np.nanmin(dec)],
                          [np.nanmax(ra), np.nanmin(dec)],
                          [np.nanmax(ra), np.nanmax(dec)],
                          [np.nanmin(ra), np.nanmax(dec)]])
    return footprint
def test_miri_mrs_wcs(run_spec2, fitsdiff_default_kwargs):
    rtdata, asn_path = run_spec2
    # get input assign_wcs and truth file
    output = "ifushort_ch12_assign_wcs.fits"
    rtdata.output = output
    rtdata.get_truth(f"truth/test_miri_mrs/{output}")

    # Open the output and truth file
    with datamodels.open(rtdata.output) as im, datamodels.open(rtdata.truth) as im_truth:
        x, y = grid_from_bounding_box(im.meta.wcs.bounding_box)
        ra, dec, lam = im.meta.wcs(x, y)
        ratruth, dectruth, lamtruth = im_truth.meta.wcs(x, y)
        assert_allclose(ra, ratruth)
        assert_allclose(dec, dectruth)
        assert_allclose(lam, lamtruth)

        # Test the inverse transform
        xtest, ytest = im.meta.wcs.backward_transform(ra, dec, lam)
        xtruth, ytruth = im_truth.meta.wcs.backward_transform(ratruth, dectruth, lamtruth)
        assert_allclose(xtest, xtruth)
        assert_allclose(ytest, ytruth)
Example #32
0
def compute_dispersion(wcs):
    """
    Compute the pixel dispersion.

    Parameters
    ----------
    wcs : `~gwcs.wcs.WCS`
        The WCS object for this slit.

    Returns
    -------
    dispersion : ndarray
        The pixel dispersion [in m].

    """
    xpix, ypix = wcstools.grid_from_bounding_box(wcs.bounding_box, step=(1, 1))
    xleft = xpix - 0.5
    xright = xpix + 0.5
    _, _, lamright = wcs(xright, ypix)
    _, _, lamleft = wcs(xleft, ypix)
    return (lamright - lamleft) * 10 ** -6
Example #33
0
def test_wcs(tmpdir, distortion, step):
    file_name = str(tmpdir / 'distortion.asdf')
    dist = rdm.DistortionRefModel(distortion)
    dist.save(file_name)

    l2im = create_image()
    l2_wcs = step(l2im, file_name)

    assert l2_wcs.meta.wcs is not None
    assert l2_wcs.meta.cal_step.assign_wcs == 'COMPLETE'

    x, y = grid_from_bounding_box(l2_wcs.meta.wcs.bounding_box)

    ra, dec = l2_wcs.meta.wcs(x, y)
    assert_allclose(ra, l2im.meta.wcsinfo.ra_ref, atol=2.3)
    assert_allclose(dec, l2im.meta.wcsinfo.dec_ref, atol=1.3)

    # verify inputs outside the bounding box return NaNs
    ra, dec = l2_wcs.meta.wcs(-5, 3)
    assert np.isnan(ra)
    assert np.isnan(dec)
Example #34
0
    def test_miri_image_wcs(self):
        """
        Regression test of creating a WCS object and doing pixel to sky transformation.
        """

        input_file = self.get_data(self.test_dir,
                                    "jw00001001001_01101_00001_MIRIMAGE_ramp_fit.fits")
        result = AssignWcsStep.call(input_file, save_results=True)

        cwd = os.path.abspath('.')
        os.makedirs('truth', exist_ok=True)
        os.chdir('truth')
        truth_file = self.get_data(*self.ref_loc,
                                 "jw00001001001_01101_00001_MIRIMAGE_assign_wcs.fits")
        os.chdir(cwd)
        truth = ImageModel(truth_file)

        x, y = grid_from_bounding_box(result.meta.wcs.bounding_box)
        ra, dec = result.meta.wcs(x, y)
        raref, decref = truth.meta.wcs(x, y)
        assert_allclose(ra, raref)
        assert_allclose(dec, decref)
Example #35
0
def test_miri_lrs_slit_wcs(run_pipeline, fitsdiff_default_kwargs):
    rtdata = run_pipeline

    # get input assign_wcs and truth file
    output = "jw00623032001_03102_00001_mirimage_assign_wcs.fits"
    rtdata.output = output
    rtdata.get_truth("truth/test_miri_lrs_slit_spec2/" + output)

    # Compare the output and truth file
    with datamodels.open(output) as im, datamodels.open(rtdata.truth) as im_truth:
        x, y = grid_from_bounding_box(im.meta.wcs.bounding_box)
        ra, dec, lam = im.meta.wcs(x, y)
        ratruth, dectruth, lamtruth = im_truth.meta.wcs(x, y)
        assert_allclose(ra, ratruth)
        assert_allclose(dec, dectruth)
        assert_allclose(lam, lamtruth)

        # Test the inverse transform
        xtest, ytest = im.meta.wcs.backward_transform(ra, dec, lam)
        xtruth, ytruth = im_truth.meta.wcs.backward_transform(ratruth, dectruth, lamtruth)
        assert_allclose(xtest, xtruth)
        assert_allclose(ytest, ytruth)
Example #36
0
    def test_miri_slitless_wcs(self):
        """
        Regression test of creating a WCS object and doing pixel to sky transformation.
        """
        input_file = self.get_data(self.test_dir,
                                   "jw80600012001_02101_00003_mirimage_rateints.fits")
        result = AssignWcsStep.call(input_file, save_results=True)

        cwd = os.path.abspath('.')
        os.makedirs('truth', exist_ok=True)
        os.chdir('truth')
        truth_file = self.get_data(*self.ref_loc,
                                 "jw80600012001_02101_00003_mirimage_assignwcsstep.fits")
        os.chdir(cwd)
        truth = CubeModel(truth_file)

        x, y = grid_from_bounding_box(result.meta.wcs.bounding_box)
        ra, dec, lam = result.meta.wcs(x, y)
        raref, decref, lamref = truth.meta.wcs(x, y)
        assert_allclose(ra, raref)
        assert_allclose(dec, decref)
        assert_allclose(lam, lamref)
Example #37
0
def compute_wavelength_array(slit):
    """
    Compute the wavelength array for a slit with gwcs object

    Parameters
    ----------
    slit : `~jwst.datamodels.SlitModel`
        JWST slit datamodel containing a meta.wcs GWCS object

    Returns
    -------
    wavelength : numpy.array
        The wavelength array
    """
    grid = grid_from_bounding_box(slit.meta.wcs.bounding_box)
    shape = grid[0].shape
    wavelength = np.empty(shape, dtype=np.float64)
    transform = slit.meta.wcs.forward_transform
    for j in range(shape[0]):
        for i in range(shape[1]):
            wavelength[j, i] = transform(grid[0][j, i], grid[1][j, i])[2]
    return wavelength
Example #38
0
    def test_miri_image_wcs(self):
        """
        Regression test of creating a WCS object and doing pixel to sky transformation.
        """

        input_file = self.get_data(self.test_dir,
                                    "jw00001001001_01101_00001_MIRIMAGE_ramp_fit.fits")
        result = AssignWcsStep.call(input_file, save_results=True)

        cwd = os.path.abspath('.')
        os.makedirs('truth', exist_ok=True)
        os.chdir('truth')
        truth_file = self.get_data(*self.ref_loc,
                                 "jw00001001001_01101_00001_MIRIMAGE_assign_wcs.fits")
        os.chdir(cwd)
        truth = ImageModel(truth_file)

        x, y = grid_from_bounding_box(result.meta.wcs.bounding_box)
        ra, dec = result.meta.wcs(x, y)
        raref, decref = truth.meta.wcs(x, y)
        assert_allclose(ra, raref)
        assert_allclose(dec, decref)
Example #39
0
    def test_miri_slitless_wcs(self):
        """
        Regression test of creating a WCS object and doing pixel to sky transformation.
        """
        input_file = self.get_data(self.test_dir,
                                   "jw80600012001_02101_00003_mirimage_rateints.fits")
        result = AssignWcsStep.call(input_file, save_results=True)

        cwd = os.path.abspath('.')
        os.makedirs('truth', exist_ok=True)
        os.chdir('truth')
        truth_file = self.get_data(*self.ref_loc,
                                 "jw80600012001_02101_00003_mirimage_assignwcsstep.fits")
        os.chdir(cwd)
        truth = CubeModel(truth_file)

        x, y = grid_from_bounding_box(result.meta.wcs.bounding_box)
        ra, dec, lam = result.meta.wcs(x, y)
        raref, decref, lamref = truth.meta.wcs(x, y)
        assert_allclose(ra, raref)
        assert_allclose(dec, decref)
        assert_allclose(lam, lamref)
Example #40
0
def test_spatial_transform():
    """
    Calling the backwards WCS transform gives the same results
    for ``negative RA`` and ``negative RA + 360``.
    """
    im = ImageModel()
    im.meta.wcsinfo._instance.update(wcsinfo)
    im.meta.instrument._instance.update(instrument)
    im.meta.exposure._instance.update(exposure)
    im.meta.observation._instance.update(observation)
    im.meta.subarray._instance.update(subarray)

    im = AssignWcsStep.call(im)
    im.data = np.random.rand(416, 72)
    im.error = np.random.rand(416, 72)
    im.dq = np.random.rand(416, 72)

    im = ResampleSpecStep.call(im)
    x, y = grid_from_bounding_box(im.meta.wcs.bounding_box)
    ra, dec, lam = im.meta.wcs(x, y)
    ra1 = np.where(ra < 0, 360 + ra, ra)
    assert_allclose(im.meta.wcs.invert(ra, dec, lam),
                    im.meta.wcs.invert(ra1, dec, lam))
Example #41
0
    def test_nirspec_masterbackground_mos_user1d(self):
        """
        Regression test of master background subtraction for NRS MOS when a user 1-D spectrum is provided.

        """
        # input file has 2-D background image added to it
        input_file = self.get_data(*self.test_dir,
                                    'nrs_mos_sci+bkg_cal.fits')
        # user provide 1-D background was created from the 2-D background image
        input_1dbkg_file = self.get_data(*self.test_dir,
                                          'nrs_mos_bkg_x1d.fits')

        result = MasterBackgroundStep.call(input_file,
                                           user_background=input_1dbkg_file,
                                           save_results=True)
        # _________________________________________________________________________
        # One of out tests is to compare the 1-D extracted spectra from
        # the science image (no background added) and the masterbackground subtracted
        # data.

        # run resample_spec  on results from MasterBackground step
        result_2d = ResampleSpecStep.call(result)
        # run 1-D extract on results from MasterBackground step
        result_1d = Extract1dStep.call(result_2d)

        # get input science data with background added
        input_sci_cal_file = self.get_data(*self.test_dir,
                                            'nrs_mos_sci_cal.fits')
        # get 1-D extract on original science data without background
        # this reference data was also run through ResampleSpec
        input_sci_1d_file = self.get_data(*self.ref_loc,
                                            'nrs_mos_sci_extract1dstep.fits')

        input_sci = datamodels.open(input_sci_cal_file)
        sci_cal_1d = datamodels.open(input_sci_1d_file)
        num_spec = len(sci_cal_1d.spec)

        # the user 1D spectrum may not cover the entire wavelength range of the
        # science data.  Find the wavelength range of user 1-D spectra

        input_1dbkg_1d = datamodels.open(input_1dbkg_file)
        user_wave = input_1dbkg_1d.spec[0].spec_table['wavelength']
        user_flux = input_1dbkg_1d.spec[0].spec_table['flux']
        user_wave_valid = np.where(user_flux > 0)
        min_user_wave = np.amin(user_wave[user_wave_valid])
        max_user_wave = np.amax(user_wave[user_wave_valid])
        input_1dbkg_1d.close()

        # loop over each slit and perform 2 tests on each slit
        for i in range(num_spec):
            # ______________________________________________________________________
            # Test 1 compare extracted spectra data from the science data
            # to extracted spectra from the output
            # from MasterBackground subtraction.
            sci_spec_1d = sci_cal_1d.spec[i].spec_table['flux']
            sci_wave = sci_cal_1d.spec[i].spec_table['wavelength']
            result_spec_1d = result_1d.spec[i].spec_table['flux']

            # find the waverange covered by both user 1-D and science slit
            sci_wave_valid = np.where(sci_spec_1d > 0)
            min_wave = np.amin(sci_wave[sci_wave_valid])
            max_wave = np.amax(sci_wave[sci_wave_valid])
            if min_user_wave > min_wave:
                min_wave = min_user_wave
            if max_user_wave < max_wave:
                max_wave = max_user_wave

            sub_spec = sci_spec_1d - result_spec_1d
            valid = np.where(np.logical_and(sci_wave > min_wave, sci_wave < max_wave))
            sub_spec = sub_spec[valid]
            mean_sub = np.nanmean(sub_spec)
            atol = 1.5
            assert_allclose(mean_sub, 0, atol=atol)
            # ______________________________________________________________________
            # Test 2  compare the science  data with no background
            # to the output from the masterBackground Subtraction step
            # background subtracted science image.
            bb = input_sci.slits[i].meta.wcs.bounding_box
            x, y = grid_from_bounding_box(bb)
            ra, dec, lam = input_sci.slits[i].meta.wcs(x, y)
            valid = np.isfinite(lam)

            sci = input_sci.slits[i].data
            result_slit = result.slits[i].data

            # check for outliers in the science image that could cause test
            # to fail. These could be cosmic ray hits or other yeck that
            # messes up the science data - ignores these cases
            sci_mean = np.nanmean(sci[valid])
            sci_std = np.nanstd(sci[valid])
            upper = sci_mean + sci_std*5.0
            lower = sci_mean - sci_std*5.0
            mask_clean = np.logical_and(sci[valid] < upper, sci[valid] > lower)

            # for this slit subtract the background subtracted data from
            # the science data with no background added
            sub = result_slit - sci
            # do not look at outliers - they confuse things
            sub_valid = sub[valid]
            mean_sub = np.mean(sub_valid[mask_clean])
            atol = 0.1
            assert_allclose(np.absolute(mean_sub), 0, atol=atol)
        # ______________________________________________________________________
        # Test 3 Compare background sutracted science data (results)
        #  to a truth file. This data is MultiSlit data

        result_file = result.meta.filename
        ref_file = self.get_data(*self.ref_loc,
                                  'nrs_mos_sci+bkg_masterbackgroundstep.fits')

        outputs = [(result_file, ref_file)]
        self.compare_outputs(outputs)
        input_sci.close()
        result.close()
Example #42
0
def find_footprint_NIRSPEC(input, flag_data, coord_system):
#********************************************************************************
    """
    Short Summary
    -------------
    For each slice find:
    a. the min and max spatial coordinates (alpha,beta) or (V2-v3) depending on coordinate system.
      axis a = naxis 1, axis b = naxis2
    b. min and max wavelength is also determined. , beta and lambda for those slices


    Parameters
    ----------
    input: input model (or file)

    Returns
    -------
    min and max spaxial coordinates  and wavelength for channel.

    """
    # loop over all the region (Slices) in the Channel
    # based on regions mask (indexed by slice number) find all the detector
    # x,y values for slice. Then convert the x,y values to  v2,v3,lambda
    # return the min & max of spatial coords and wavelength  - these are of the pixel centers

    nslices = 30
    a_slice = np.zeros(nslices * 2)
    b_slice = np.zeros(nslices * 2)
    lambda_slice = np.zeros(nslices * 2)
    k = 0
    # for NIRSPEC there are 30 regions
    log.info('Looping over slices to determine cube size .. this takes a while')

    for i in range(nslices):
        slice_wcs = nirspec.nrs_wcs_set_input(input, i)
        x, y = wcstools.grid_from_bounding_box(slice_wcs.bounding_box, step=(1, 1), center=True)
        if coord_system == 'world':
            coord1, coord2, lam = slice_wcs(x, y)
        elif coord_system == 'alpha-beta':
            raise InvalidCoordSystem(" The Alpha-Beta Coordinate system is not valid (at this time) for NIRSPEC data")
#                detector2slicer = input.meta.wcs.get_transform('detector','slicer')
#                coord1,coord2,lam = detector2slicer(x,y)
        else:
            # error the coordinate system is not defined
            raise NoCoordSystem(" The output cube coordinate system is not definded")
#________________________________________________________________________________
# For each slice  test for 0/360 wrapping in ra.
# If exists it makes it difficult to determine  ra range of IFU cube.
        coord1_wrap = wrap_ra(coord1)
        a_min = np.nanmin(coord1_wrap)
        a_max = np.nanmax(coord1_wrap)

        a_slice[k] = a_min
        a_slice[k + 1] = a_max

        b_slice[k] = np.nanmin(coord2)
        b_slice[k + 1] = np.nanmax(coord2)

        lambda_slice[k] = np.nanmin(lam)
        lambda_slice[k + 1] = np.nanmax(lam)

        k = k + 2
#________________________________________________________________________________
# now test the ra slices for conistency. Adjust if needed.
    a_slice_wrap = wrap_ra(a_slice)
    a_min = np.nanmin(a_slice_wrap)
    a_max = np.nanmax(a_slice_wrap)

    b_min = min(b_slice)
    b_max = max(b_slice)

    lambda_min = min(lambda_slice)
    lambda_max = max(lambda_slice)

    if (a_min == 0.0 and a_max == 0.0 and b_min == 0.0 and b_max == 0.0):
        log.info('This NIRSPEC exposure has no IFU data on it - skipping file')

    return a_min, a_max, b_min, b_max, lambda_min, lambda_max
Example #43
0
    def build_interpolated_output_wcs(self, refmodel=None):
        """
        Create a spatial/spectral WCS output frame

        Creates output frame by linearly fitting RA, Dec along the slit and
        producing a lookup table to interpolate wavelengths in the dispersion
        direction.

        Parameters
        ----------
        refmodel : `~jwst.datamodels.DataModel`
            The reference input image from which the fiducial WCS is created.
            If not specified, the first image in self.input_models is used.

        Returns
        -------
        output_wcs : `~gwcs.WCS` object
            A gwcs WCS object defining the output frame WCS
        """
        if refmodel is None:
            refmodel = self.input_models[0]
        refwcs = refmodel.meta.wcs
        bb = refwcs.bounding_box

        grid = wcstools.grid_from_bounding_box(bb)
        ra, dec, lam = np.array(refwcs(*grid))

        spectral_axis = find_dispersion_axis(lam)
        spatial_axis = spectral_axis ^ 1

        # Compute the wavelength array, trimming NaNs from the ends
        wavelength_array = np.nanmedian(lam, axis=spectral_axis)
        wavelength_array = wavelength_array[~np.isnan(wavelength_array)]

        # Compute RA and Dec up the slit (spatial direction) at the center
        # of the dispersion.  Use spectral_axis to determine slicing dimension
        lam_center_index = int((bb[spectral_axis][1] - bb[spectral_axis][0]) / 2)
        if not spectral_axis:
            ra_array = ra.T[lam_center_index]
            dec_array = dec.T[lam_center_index]
        else:
            ra_array = ra[lam_center_index]
            dec_array = dec[lam_center_index]
        ra_array = ra_array[~np.isnan(ra_array)]
        dec_array = dec_array[~np.isnan(dec_array)]

        fitter = LinearLSQFitter()
        fit_model = Linear1D()
        pix_to_ra = fitter(fit_model, np.arange(ra_array.shape[0]), ra_array)
        pix_to_dec = fitter(fit_model, np.arange(dec_array.shape[0]), dec_array)

        # Tabular interpolation model, pixels -> lambda
        pix_to_wavelength = Tabular1D(lookup_table=wavelength_array,
            bounds_error=False, fill_value=None, name='pix2wavelength')

        # Tabular models need an inverse explicitly defined.
        # If the wavelength array is decending instead of ascending, both
        # points and lookup_table need to be reversed in the inverse transform
        # for scipy.interpolate to work properly
        points = wavelength_array
        lookup_table = np.arange(wavelength_array.shape[0])
        if not np.all(np.diff(wavelength_array) > 0):
            points = points[::-1]
            lookup_table = lookup_table[::-1]
        pix_to_wavelength.inverse = Tabular1D(points=points,
            lookup_table=lookup_table,
            bounds_error=False, fill_value=None, name='wavelength2pix')

        # For the input mapping, duplicate the spatial coordinate
        mapping = Mapping((spatial_axis, spatial_axis, spectral_axis))

        # Sometimes the slit is perpendicular to the RA or Dec axis.
        # For example, if the slit is perpendicular to RA, that means
        # the slope of pix_to_ra will be nearly zero, so make sure
        # mapping.inverse uses pix_to_dec.inverse.  The auto definition
        # of mapping.inverse is to use the 2nd spatial coordinate, i.e. Dec.
        if np.isclose(pix_to_dec.slope, 0, atol=1e-8):
            mapping_tuple = (0, 1)
            # Account for vertical or horizontal dispersion on detector
            if spatial_axis:
                mapping.inverse = Mapping(mapping_tuple[::-1])
            else:
                mapping.inverse = Mapping(mapping_tuple)

        # The final transform
        transform = mapping | pix_to_ra & pix_to_dec & pix_to_wavelength

        det = cf.Frame2D(name='detector', axes_order=(0, 1))
        sky = cf.CelestialFrame(name='sky', axes_order=(0, 1),
            reference_frame=coord.ICRS())
        spec = cf.SpectralFrame(name='spectral', axes_order=(2,),
            unit=(u.micron,), axes_names=('wavelength',))
        world = cf.CompositeFrame([sky, spec], name='world')

        pipeline = [(det, transform),
                    (world, None)]

        output_wcs = WCS(pipeline)

        # compute the output array size in WCS axes order, i.e. (x, y)
        output_array_size = [0, 0]
        output_array_size[spectral_axis] = len(wavelength_array)
        output_array_size[spatial_axis] = len(ra_array)

        # turn the size into a numpy shape in (y, x) order
        self.data_size = tuple(output_array_size[::-1])

        bounding_box = resample_utils.wcs_bbox_from_shape(self.data_size)
        output_wcs.bounding_box = bounding_box

        return output_wcs
Example #44
0
    def blot_images(self):
        """
        Short Summary
        ------------
        Core blotting module
        Initialize blot_model = input_model
        1. Loop over every data model to be blotted and find ra,dec,wavelength
           for every slice pixel.
        2. Using WCS of input image convert ra,dec of input model to tangent
           plane values: xi,eta
        3. For the median sky cube convert the ra,dec of each x,y in this cube
           to xi,eta using the wcs of the imput image
        4. a. Loop over  every input_model valid IFU slice pixel and find the
            median image pixels that fall within the ROI of the center of pixel.
            The ROI parameters are the same as those used to construct the
            median sky cube and are stored in the meta data of the Median Cube.
            b. After all the overlapping median pixels have been found find the
            weighted flux using this overlapping pixels. The weighting is based
            on the distance between the detector pixel and the median flux pixel
            in tangent plane plane. Additional weighting parameters are read in
            from the median cube meta data.
            c. The blotted flux (blot.data) = the weighted flux determined in
            step b.

        """
        t0 = time.time()
        blot_models = datamodels.ModelContainer()
        lower_limit = 0.01
        instrument_info = instrument_defaults.InstrumentInfo()

        for model in self.input_models:
            blot = model.copy()
            blot.err = None
            blot.dq = None

            filename = model.meta.filename
            indx = filename.rfind('.fits')

            blot_flux = np.zeros(model.shape, dtype=np.float32)
#________________________________________________________________________________
# From the x,y pixel for detector. For MIRI we only work on one channel at a time

            if self.instrument == 'MIRI':
                this_par1 = self.channel # only one channel is blotted at a time
                ch_name = '_ch' + this_par1
                blot.meta.filename = filename[:indx] + ch_name + '_blot.fits'

                # get the detector values for this model
                xstart, xend = instrument_info.GetMIRISliceEndPts(this_par1)
                ydet, xdet = np.mgrid[:1024, :1032]

                #mask out the side channel we aren not working on
                pixel_mask = np.full(model.shape, False, dtype=bool)
                pixel_mask[:, xstart:xend] = True
                ra_det, dec_det, lam_det = model.meta.wcs(xdet, ydet)

            elif self.instrument == 'NIRSPEC':
                blot.meta.filename = filename[:indx] + '_blot.fits'
                # initialize the ra,dec, and wavelength arrays
                # we will loop over slices and fill in values
                # the flag_det will be set when a slice pixel is filled in
                #   at the end we will use this flag to pull out valid data
                ra_det = np.zeros((2048, 2048))
                dec_det = np.zeros((2048, 2048))
                lam_det = np.zeros((2048, 2048))
                flag_det = np.zeros((2048, 2048))

                # for NIRSPEC each file has 30 slices
                # wcs information access seperately for each slice

                nslices = 30
                log.info('Looping over 30 slices on NIRSPEC detector, this takes a little while')
                for ii in range(nslices):
                    slice_wcs = nirspec.nrs_wcs_set_input(model, ii)
                    x, y = wcstools.grid_from_bounding_box(slice_wcs.bounding_box)
                    ra, dec, lam = slice_wcs(x, y)

                    # the slices are curved on detector so a rectangular region
                    # returns NaNs
                    valid = ~np.isnan(lam)
                    ra = ra[valid]
                    dec = dec[valid]
                    lam = lam[valid]
                    x = x[valid]
                    y = y[valid]

                    xind = _toindex(x)
                    yind = _toindex(y)
                    xind = np.ndarray.flatten(xind)
                    yind = np.ndarray.flatten(yind)
                    ra = np.ndarray.flatten(ra)
                    dec = np.ndarray.flatten(dec)
                    lam = np.ndarray.flatten(lam)
                    ra_det[yind, xind] = ra
                    dec_det[yind, xind] = dec
                    lam_det[yind, xind] = lam
                    flag_det[yind, xind] = 1

# Done looping over slices
            log.info('Blotting back %s', model.meta.filename)

            if self.instrument == 'MIRI':
                valid3 = np.isfinite(lam_det)
                good_data1 = valid3 & pixel_mask
                good_data = np.where(good_data1)
            elif self.instrument == 'NIRSPEC':
                good_data = np.where(flag_det == 1)

            y, x = good_data
            ra_blot = ra_det[good_data]
            dec_blot = dec_det[good_data]
            wave_blot = lam_det[good_data]
            crval1 = model.meta.wcsinfo.crval1
            crval2 = model.meta.wcsinfo.crval2

            # x,y detector pixels --> xi, eta
            xi_blot, eta_blot = coord.radec2std(crval1, crval2,
                                               ra_blot, dec_blot)

            # cube spaxel ra,dec values --> xi, eta
            xi_cube, eta_cube = coord.radec2std(crval1, crval2,
                                               self.cube_ra, self.cube_dec)
            nplane = self.naxis1 * self.naxis2
            self.xi_centers = np.reshape(xi_cube[0, :, :], nplane)
            self.eta_centers = np.reshape(eta_cube[0, :, :], nplane)

            num = ra_blot.size
#________________________________________________________________________________
# For every detector pixel find the overlapping median cube spaxels.
# A median spaxel that falls withing the ROI of the center of the detector pixel
# in the tangent plane is flagged as an overlapping pixel

            for ipt in range(0, num - 1):
                # xx,yy are the index value of the orginal detector frame -
                # blot image
                yy = y[ipt]
                xx = x[ipt]
                # find the cube values that fall withing ROI of detector xx,yy
                xdistance = (xi_blot[ipt] - self.xi_centers)
                ydistance = (eta_blot[ipt] - self.eta_centers)
                radius = np.sqrt(xdistance * xdistance + ydistance * ydistance)
                # indexr holds the index of the sky median spaxels that fall within
                # the spatial  ROI of xx,yy location
                indexr = np.where(radius <= self.rois)
                #indexz holds the index of the sky median spaxels that fall within
                # the spectral ROI of wave length assocation with xx,yy
                indexz = np.where(abs(self.lam_centers - wave_blot[ipt]) <= self.roiw)
                # Pull out the Cube spaxels falling with ROI regions

                wave_found = self.lam_centers[indexz]
                xi_found = self.xi_centers[indexr]
                eta_found = self.eta_centers[indexr]
#________________________________________________________________________________
                # form the arrays to be used calculated the weighting
                d1 = np.array(xi_found - xi_blot[ipt]) / self.cdelt1
                d2 = np.array(eta_found - eta_blot[ipt]) / self.cdelt2
                d3 = np.array(wave_found - wave_blot[ipt]) / self.cdelt3

                dxy = d1 * d1 + d2 * d2
                dxy_matrix = np.tile(dxy[np.newaxis].T, [1, d3.shape[0]])
                d3_matrix = np.tile(d3 * d3, [dxy_matrix.shape[0], 1])

                wdistance = dxy_matrix + d3_matrix
                weight_distance = np.power(np.sqrt(wdistance), self.weight_power)
                weight_distance[weight_distance < lower_limit] = lower_limit
                weight_distance = 1.0 / weight_distance

                # determine the spaxel xx_cube,yy_cube values of these spaxels in
                # the ROI so they can be used to pull out the flux of the median
                # sky cube.
                yy_cube = (indexr[0] / self.naxis1).astype(np.int)
                xx_cube = indexr[0] - yy_cube * self.naxis1
                scf = np.array([self.cube_flux[zz, yy_cube[ir], xx_cube[ir]]
                                for ir, rr in enumerate(indexr[0]) for zz in indexz[0]])
                scf = np.reshape(scf, weight_distance.shape)
                blot_flux[yy, xx] = np.sum(weight_distance * scf)
                blot_weight = np.sum(weight_distance)

                # check for blot_weight !=0
                if blot_weight == 0:
                    blot_flux[yy, xx] = 0
                else:
                    blot_flux[yy, xx] = blot_flux[yy, xx] / blot_weight
#________________________________________________________________________________
            blot.data = blot_flux
            blot_models.append(blot)
        t1 = time.time()
        log.info("Time Blot images = %.1f.s" % (t1 - t0,))
        return blot_models
Example #45
0
def extract_slit(input_model, slit, exp_type):
    """
    Extract a slit from a full frame image.

    Parameters
    ----------
    input_model : `~jwst.datamodels.image.ImageModel` or `~jwst.datamodels.cube.CubeModel`
        The input model.
    slit : `~jwst.transforms.models.Slit`
        A slit object.
    exp_type : str
        The exposure type.

    Returns
    -------
    new_model : `~jwst.datamodels.SlitModel`
        The slit data model with WCS attached to it.
    """
    slit_wcs = nirspec.nrs_wcs_set_input(input_model, slit.name)
    xlo, xhi, ylo, yhi = offset_wcs(slit_wcs)
    log.info('Name of subarray extracted: %s', slit.name)
    log.info('Subarray x-extents are: %s %s', xlo, xhi)
    log.info('Subarray y-extents are: %s %s', ylo, yhi)
    ndim = len(input_model.data.shape)
    if ndim == 2:
        slit_slice = np.s_[ylo: yhi, xlo: xhi]
        ext_data = input_model.data[slit_slice].copy()
        ext_err = input_model.err[slit_slice].copy()
        ext_dq = input_model.dq[slit_slice].copy()
        ext_var_rnoise = input_model.var_rnoise[slit_slice].copy()
        ext_var_poisson = input_model.var_poisson[slit_slice].copy()
        int_times = None
    elif ndim == 3:
        slit_slice = np.s_[:, ylo: yhi, xlo: xhi]
        ext_data = input_model.data[slit_slice].copy()
        ext_err = input_model.err[slit_slice].copy()
        ext_dq = input_model.dq[slit_slice].copy()
        ext_var_rnoise = input_model.var_rnoise[slit_slice].copy()
        ext_var_poisson = input_model.var_poisson[slit_slice].copy()
        if (pipe_utils.is_tso(input_model) and
            hasattr(input_model, 'int_times')):
                log.debug("TSO data, so copying the INT_TIMES table.")
                int_times = input_model.int_times.copy()
        else:
                int_times = None
    else:
        raise ValueError("extract_2d does not work with "
                         "{0} dimensional data".format(ndim))

    slit_wcs.bounding_box = util.bounding_box_from_shape(ext_data.shape)

    # compute wavelengths
    x, y = wcstools.grid_from_bounding_box(slit_wcs.bounding_box, step=(1, 1))
    ra, dec, lam = slit_wcs(x, y)
    lam = lam.astype(np.float32)
    new_model = datamodels.SlitModel(data=ext_data, err=ext_err, dq=ext_dq, wavelength=lam,
                                     var_rnoise=ext_var_rnoise, var_poisson=ext_var_poisson,
                                     int_times=int_times)
    log.info('Input model type is {}'.format(input_model.__class__.__name__))
    new_model.update(input_model)
    new_model.meta.wcs = slit_wcs
    return new_model, xlo, xhi, ylo, yhi
Example #46
0
def do_correction(input_model, barshadow_model):
    """Do the Bar Shadow Correction

    Parameters
    ----------
    input_model: MultiSlitModel datamodel object
        science data model to be corrected

    barshadow_model: BarshadowModel datamodel object
        bar shadow datamodel from reference file

    Returns
    -------
    output_model: MultiSlitModel datamodel object
        Science datamodel with bar shadow extensions added

    """
#
# Input is a MultiSlitModel science data model 
# A MultislitModel has a member .slits that behaves like
# a list of Slits, each of which has several data arrays and
# keyword metadata items associated 
#
# At this point we're going to have to assume that a Slit is composed
# of a set of slit[].nshutters in a vertical line
#
# Reference file information is a 1x1 ref file and a 1x3 ref file
# Both the 1x1 and 1x3 ref files are 1001 pixel high and go from
# -1 to 1 in their Y value WCS.  
# 
# 
    exp_type = input_model.meta.exposure.type
    log.info(exp_type)
    #
    # Create the pieces that are put together to make the barshadow model
    shutter_elements = create_shutter_elements(barshadow_model)
    w0 = barshadow_model.crval1
    wave_increment = barshadow_model.cdelt1
    y_increment = barshadow_model.cdelt2
    shutter_height = 1.0 / y_increment
    # For each slitlet
    for slitlet in input_model.slits:
        slitlet_number = slitlet.slitlet_id
        log.info('Working on slitlet %d' % slitlet_number)
        if has_uniform_source(slitlet):
            shutter_status = slitlet.shutter_state
            if len(shutter_status) > 0:
                shadow = create_shadow(shutter_elements, shutter_status)
                #
                # For each pixel in the slit subarray
                #   Make a grid of indices for pixels in the subarray
                x, y = wcstools.grid_from_bounding_box(slitlet.meta.wcs.bounding_box, step=(1,1))
                #   Create the transformation from slit_frame to detector
                det2slit = slitlet.meta.wcs.get_transform('detector', 'slit_frame')
                #   Use this transformation to calculate x, y and wavelength
                xslit, yslit, wavelength = det2slit(x, y)
                #   The returned y values are scaled to where the slit height is 1
                # (i.e. a slit goes from -0.5 to 0.5).  The barshadow array is scaled
                # so that the separation between the slit centers is 1, i.e. slit height
                # + interslit bar
                yslit = yslit / SLITRATIO
                #   Convert the Y and wavelength to a pixel location
                #   in the  bar shadow array
                index_of_fiducial = shutter_status.find('x')
                #
                # The shutters go downwards, i.e. the first shutter in shutter_status corresponds to
                # the last in the shadow array.  So the center of the first shutter referred to in
                # shutter_status has an index of shadow.shape[0] - shutter_height.  Each subsequent
                # shutter center has an index shutter_height greater.
                index_of_fiducial_in_array = shadow.shape[0] - shutter_height * (1 + index_of_fiducial)
                yrow = index_of_fiducial_in_array - yslit * shutter_height
                wcol = (wavelength - w0)/wave_increment
                # Interpolate the bar shadow correction for non-Nan pixels
                correction = interpolate(yrow, wcol, shadow)
                # Add the correction array and variance to the datamodel
                slitlet.barshadow = correction
            else:
                log.info("Slitlet %d has zero length, correction skipped" % slitlet_number)
                #
                # Put an array of ones in a correction extension
                slitlet.barshadow = np.ones(slitlet.data.shape)
        else:
            log.info("Bar shadow correction skipped for slitlet %d (source not uniform)" % slitlet_number)
            #
            # Put an array of ones in a correction extension
            slitlet.barshadow = np.ones(slitlet.data.shape)
    return input_model
    def test_nirspec_ifu_masterbg_user(self):
        """
        Regression test of master background subtraction for NRS IFU when a
        user 1-D spectrum is provided.
        """
        # input file has 2-D background image added to it
        input_file = self.get_data(*self.test_dir, 'prism_sci_bkg_cal.fits')

        # user-provided 1-D background was created from the 2-D background image
        user_background = self.get_data(*self.test_dir, 'prism_bkg_x1d.fits')

        result = MasterBackgroundStep.call(input_file,
                                           user_background=user_background,
                                           save_results=True)

        # Test 1 compare extracted spectra data with
        # no background added to extracted spectra from the output
        # from MasterBackground subtraction. First cube_build has to be run
        # on the data.
        result_s3d = CubeBuildStep.call(result)
        # run 1-D extract on results from MasterBackground step
        result_1d = Extract1dStep.call(result_s3d, subtract_background=False)

        # get the 1-D extracted spectrum from the science data in truth directory
        input_sci_1d_file = self.get_data(*self.ref_loc, 'prism_sci_extract1d.fits')
        sci_1d = datamodels.open(input_sci_1d_file)

        # read in the valid wavelengths of the user-1d
        user_background_model = datamodels.open(user_background)
        user_wave = user_background_model.spec[0].spec_table['wavelength']
        user_flux = user_background_model.spec[0].spec_table['net']
        user_wave_valid = np.where(user_flux > 0)
        min_user_wave = np.amin(user_wave[user_wave_valid])
        max_user_wave = np.amax(user_wave[user_wave_valid])
        user_background_model.close()
        # find the waverange covered by both user and science
        sci_spec_1d = sci_1d.spec[0].spec_table['net']
        sci_spec_wave = sci_1d.spec[0].spec_table['wavelength']

        result_spec_1d = result_1d.spec[0].spec_table['net']

        sci_wave_valid = np.where(sci_spec_1d > 0)
        min_wave = np.amin(sci_spec_wave[sci_wave_valid])
        max_wave = np.amax(sci_spec_wave[sci_wave_valid])
        if min_user_wave > min_wave:
            min_wave = min_user_wave
        if max_user_wave < max_wave:
            max_wave = max_user_wave

        sub_spec = sci_spec_1d - result_spec_1d
        valid = np.where(np.logical_and(sci_spec_wave > min_wave, sci_spec_wave < max_wave))
        sub_spec = sub_spec[valid]
        sub_spec = sub_spec[1:-2]  # endpoints are wacky

        mean_sub = np.absolute(np.nanmean(sub_spec))
        atol = 5.0
        assert_allclose(mean_sub, 0, atol=atol)

        # Test 2  compare the science  data with no background
        # to the output from the masterBackground Subtraction step
        # background subtracted science image.
        input_sci_cal_file = self.get_data(*self.test_dir,
                                            'prism_sci_cal.fits')
        input_sci_model = datamodels.open(input_sci_cal_file)

        # We don't want the slices gaps to impact the statisitic
        # loop over the 30 Slices
        for i in range(30):
            slice_wcs = nirspec.nrs_wcs_set_input(input_sci_model, i)
            x, y = grid_from_bounding_box(slice_wcs.bounding_box)
            ra, dec, lam = slice_wcs(x, y)
            valid = np.isfinite(lam)
            result_slice_region = result.data[y.astype(int), x.astype(int)]
            sci_slice_region = input_sci_model.data[y.astype(int),
                                                    x.astype(int)]
            sci_slice = sci_slice_region[valid]
            result_slice = result_slice_region[valid]
            sub = result_slice - sci_slice

            # check for outliers in the science image
            sci_mean = np.nanmean(sci_slice)
            sci_std = np.nanstd(sci_slice)
            upper = sci_mean + sci_std*5.0
            lower = sci_mean - sci_std*5.0
            mask_clean = np.logical_and(sci_slice < upper, sci_slice > lower)

            sub_mean = np.absolute(np.nanmean(sub[mask_clean]))
            atol = 2.0
            assert_allclose(sub_mean, 0, atol=atol)

        # Test 3 Compare background sutracted science data (results)
        #  to a truth file. This data is MultiSlit data

        input_sci_model.close()
        result_file = result.meta.filename
        truth_file = self.get_data(*self.ref_loc,
                                  'prism_sci_bkg_masterbackgroundstep.fits')

        outputs = [(result_file, truth_file)]
        self.compare_outputs(outputs)
        input_sci_model.close()
        result.close()
Example #48
0
def bkg_for_ifu_image(input, tab_wavelength, tab_background):
    """Create a 2-D background for an IFUImageModel

    Parameters
    ----------
    input : `~jwst.datamodels.IFUImageModel`
        The input science data.

    tab_wavelength : 1-D ndarray
        The wavelength column read from the 1-D background table.

    tab_background : 1-D ndarray
        The flux column read from the 1-D background table, divided by
        the npixels column.

    Returns
    -------
    background : `~jwst.datamodels.IFUImageModel`
        A copy of `input` but with the data replaced by the background,
        "expanded" from 1-D to 2-D. The dq flags are set to DO_NOT_USE
        for the pixels outside the region provided in the X1D background
        wavelength table.

    """

    background = input.copy()
    background.data[:, :] = 0.
    min_wave = np.amin(tab_wavelength)
    max_wave = np.amax(tab_wavelength)

    if input.meta.instrument.name.upper() == "NIRSPEC":
        list_of_wcs = nirspec.nrs_ifu_wcs(input)
        for ifu_wcs in list_of_wcs:
            x, y = grid_from_bounding_box(ifu_wcs.bounding_box)
            wl_array = ifu_wcs(x, y)[2]
            wl_array[np.isnan(wl_array)] = -1.

            # mask wavelengths not covered by the master background
            mask_limit = (wl_array > max_wave) | (wl_array < min_wave)
            wl_array[mask_limit] = -1

            # mask_limit is indices into each WCS slice grid.  Need them in
            # full frame coordinates, so we use x and y, which are full-frame
            full_frame_ind = y[mask_limit].astype(int), x[mask_limit].astype(int)
            # TODO - add another DQ Flag something like NO_BACKGROUND when we have space in dqflags
            background.dq[full_frame_ind] = np.bitwise_or(background.dq[full_frame_ind],
                                                          dqflags.pixel['DO_NOT_USE'])

            bkg_flux = np.interp(wl_array, tab_wavelength, tab_background,
                                 left=0., right=0.)
            background.data[y.astype(int), x.astype(int)] = bkg_flux.copy()

    elif input.meta.instrument.name.upper() == "MIRI":
        shape = input.data.shape
        grid = np.indices(shape, dtype=np.float64)
        wl_array = input.meta.wcs(grid[1], grid[0])[2]
        # first remove the nans from wl_array and replace with -1
        mask = np.isnan(wl_array)
        wl_array[mask] = -1.
        # next look at the limits of the wavelength table
        mask_limit = (wl_array > max_wave) | (wl_array < min_wave)
        wl_array[mask_limit] = -1

        # TODO - add another DQ Flag something like NO_BACKGROUND when we have space in dqflags
        background.dq[mask_limit] = np.bitwise_or(background.dq[mask_limit],
                                                  dqflags.pixel['DO_NOT_USE'])
        bkg_flux = np.interp(wl_array, tab_wavelength, tab_background,
                             left=0., right=0.)
        background.data[:, :] = bkg_flux.copy()
    else:
        raise RuntimeError("Exposure type {} is not supported."
                           .format(input.meta.exposure.type))

    return background
Example #49
0
def _nanminmax(wcsobj):
    x, y = grid_from_bounding_box(wcsobj.bounding_box)
    ra, dec, lam = wcsobj(x, y)
    return np.nanmin(ra), np.nanmax(ra), np.nanmin(dec), np.nanmax(dec)
Example #50
0
def do_correction(input_model, pathloss_model):
    """
    Short Summary
    -------------
    Execute all tasks for Path Loss Correction

    Parameters
    ----------
    input_model : data model object
        science data to be corrected

    pathloss_model : pathloss model object
        pathloss correction data

    Returns
    -------
    output_model : data model object
        Science data with pathloss extensions added

    """
    exp_type = input_model.meta.exposure.type
    log.info(exp_type)
    output_model = input_model.copy()
    if exp_type == 'NRS_MSASPEC':
        slit_number = 0
        for slit in output_model.slits:
            slit_number = slit_number + 1
            log.info('Working on slit {}'.format(slit_number))
            size = slit.data.size
            # That has data.size > 0
            if size > 0:
                # Get centering
                xcenter, ycenter = get_center(exp_type, slit)
                # Calculate the 1-d wavelength and pathloss vectors
                # for the source position
                # Get the aperture from the reference file that matches the slit
                nshutters = util.get_num_msa_open_shutters(slit.shutter_state)
                aperture = get_aperture_from_model(pathloss_model, nshutters)
                if aperture is not None:
                    (wavelength_pointsource,
                     pathloss_pointsource_vector,
                     is_inside_slitlet) = calculate_pathloss_vector(aperture.pointsource_data,
                                                                    aperture.pointsource_wcs,
                                                                    xcenter, ycenter)
                    (wavelength_uniformsource,
                     pathloss_uniform_vector,
                     dummy) = calculate_pathloss_vector(aperture.uniform_data,
                                                        aperture.uniform_wcs,
                                                        xcenter, ycenter)
                    if is_inside_slitlet:

                        # Wavelengths in the reference file are in meters,
                        #need them to be in microns
                        wavelength_pointsource *= 1.0e6
                        wavelength_uniformsource *= 1.0e6

                        wavelength_array = slit.wavelength

                        # Compute the pathloss 2D correction
                        if is_pointsource(slit.source_type):
                            pathloss_2d = interpolate_onto_grid(
                                wavelength_array,
                                wavelength_pointsource,
                                pathloss_pointsource_vector)
                        else:
                            pathloss_2d = interpolate_onto_grid(
                                wavelength_array,
                                wavelength_uniformsource,
                                pathloss_uniform_vector)
                        # Apply the pathloss 2D correction and attach to datamodel
                        slit.data /= pathloss_2d
                        slit.err /= pathloss_2d
                        slit.var_poisson /= pathloss_2d**2
                        slit.var_rnoise /= pathloss_2d**2
                        slit.pathloss = pathloss_2d
                    else:
                        log.warning("Source is outside slit.  Skipping "
                        "pathloss correction for slit {}".format(slit_number))
                else:
                    log.warning("Cannot find matching pathloss model for slit "
                        "with {} shutters, skipping pathloss correction for this "
                        "slit".format(nshutters))
                    continue
            else:
                log.warning("Slit has data size = {}, skipping "
                    "pathloss correction for this slitlet".format(size))
        output_model.meta.cal_step.pathloss = 'COMPLETE'
    elif exp_type in ['NRS_FIXEDSLIT', 'NRS_BRIGHTOBJ']:
        slit_number = 0
        is_inside_slit = True
        # For each slit
        for slit in output_model.slits:
            log.info(slit.name)
            slit_number = slit_number + 1
            # Get centering
            xcenter, ycenter = get_center(exp_type, slit)
            # Calculate the 1-d wavelength and pathloss vectors
            # for the source position
            # Get the aperture from the reference file that matches the slit
            aperture = get_aperture_from_model(pathloss_model, slit.name)
            if aperture is not None:
                log.info("Using aperture {}".format(aperture.name))
                (wavelength_pointsource,
                 pathloss_pointsource_vector,
                 is_inside_slit) = calculate_pathloss_vector(aperture.pointsource_data,
                                                             aperture.pointsource_wcs,
                                                             xcenter, ycenter)
                (wavelength_uniformsource,
                 pathloss_uniform_vector,
                 dummy) = calculate_pathloss_vector(aperture.uniform_data,
                                                    aperture.uniform_wcs,
                                                    xcenter, ycenter)
                if is_inside_slit:

                    # Wavelengths in the reference file are in meters, need them to be
                    # in microns
                    wavelength_pointsource *= 1.0e6
                    wavelength_uniformsource *= 1.0e6

                    wavelength_array = slit.wavelength

                    # Compute the pathloss 2D correction
                    if is_pointsource(slit.source_type):
                        pathloss_2d = interpolate_onto_grid(
                            wavelength_array,
                            wavelength_pointsource,
                            pathloss_pointsource_vector)
                    else:
                        pathloss_2d = interpolate_onto_grid(
                            wavelength_array,
                            wavelength_uniformsource,
                            pathloss_uniform_vector)
                    # Apply the pathloss 2D correction and attach to datamodel
                    slit.data /= pathloss_2d
                    slit.err /= pathloss_2d
                    slit.var_poisson /= pathloss_2d**2
                    slit.var_rnoise /= pathloss_2d**2
                    slit.pathloss = pathloss_2d
                else:
                    log.warning("Source is outside slit.  Skipping "
                        "pathloss correction for slit {}".format(slit.name))
            else:
                log.warning("Cannot find matching pathloss model for aperture {} "
                    "skipping pathloss correction for this slit".format(slit.name))
                continue
        output_model.meta.cal_step.pathloss = 'COMPLETE'
    elif exp_type == 'NRS_IFU':
        # IFU targets are always inside slit
        # Get centering
        xcenter, ycenter = get_center(exp_type, None)
        # Calculate the 1-d wavelength and pathloss vectors
        # for the source position
        aperture = pathloss_model.apertures[0]
        (wavelength_pointsource,
         pathloss_pointsource_vector,
         dummy) = calculate_pathloss_vector(aperture.pointsource_data,
                                            aperture.pointsource_wcs,
                                            xcenter, ycenter)
        (wavelength_uniformsource,
         pathloss_uniform_vector,
         dummy) = calculate_pathloss_vector(aperture.uniform_data,
                                            aperture.uniform_wcs,
                                            xcenter, ycenter)
        # Wavelengths in the reference file are in meters, need them to be
        # in microns
        wavelength_pointsource *= 1.0e6
        wavelength_uniformsource *= 1.0e6

        # Create the 2-d pathloss arrays, initialize with NaNs
        wavelength_array = np.zeros(input_model.shape, dtype=np.float32)
        wavelength_array.fill(np.nan)
        for slice in NIRSPEC_IFU_SLICES:
            slice_wcs = nirspec.nrs_wcs_set_input(input_model, slice)
            x, y = wcstools.grid_from_bounding_box(slice_wcs.bounding_box)
            xmin = int(x.min())
            xmax = int(x.max())
            ymin = int(y.min())
            ymax = int(y.max())
            ra, dec, wavelength = slice_wcs(x, y)
            wavelength_array[ymin:ymax+1, xmin:xmax+1] = wavelength

        # Compute the pathloss 2D correction
        if is_pointsource(input_model.meta.target.source_type):
            pathloss_2d = interpolate_onto_grid(
                wavelength_array,
                wavelength_pointsource,
                pathloss_pointsource_vector)
        else:
            pathloss_2d = interpolate_onto_grid(
                wavelength_array,
                wavelength_uniformsource,
                pathloss_uniform_vector)
        # Apply the pathloss 2D correction and attach to datamodel
        output_model.data /= pathloss_2d
        output_model.err /= pathloss_2d
        output_model.var_poisson /= pathloss_2d**2
        output_model.var_rnoise /= pathloss_2d**2
        output_model.pathloss = pathloss_2d

        # This might be useful to other steps
        output_model.wavelength = wavelength_array

        output_model.meta.cal_step.pathloss = 'COMPLETE'

    elif exp_type == 'NIS_SOSS':
        """NIRISS SOSS pathloss correction is basically a correction for the
        flux from the 2nd and 3rd order dispersion that falls outside the
        subarray aperture.  The correction depends
        on the pupil wheel position and column number (or wavelength).  The
        simple option is to do the correction by column number, then the only
        interpolation needed is a 1-d interpolation into the pupil wheel position
        dimension."""

        # Omit correction if this is a TSO observation
        if input_model.meta.visit.tsovisit:
            log.warning("NIRISS SOSS TSO observations skip the pathloss step")
            output_model.meta.cal_step.pathloss = 'SKIPPED'
            return output_model

        pupil_wheel_position = input_model.meta.instrument.pupil_position
        if pupil_wheel_position is None:
            log.warning("Unable to get pupil wheel position from PWCPOS keyword "
                "for {}".format(input_model.meta.filename))
            log.warning("Pathloss correction skipped")
            output_model.meta.cal_step.pathloss = 'SKIPPED'
            return output_model

        subarray = input_model.meta.subarray.name
        # Get the aperture from the reference file that matches the subarray
        aperture = get_aperture_from_model(pathloss_model, subarray)
        if aperture is None:
            log.warning("Unable to get Aperture from reference file "
                "for subarray {}".format(subarray))
            log.warning("Pathloss correction skipped")
            output_model.meta.cal_step.pathloss = 'SKIPPED'
            return output_model

        else:
            log.info("Aperture {} selected from reference file".format(aperture.name))
        pathloss_array = aperture.pointsource_data[0]
        nrows, ncols = pathloss_array.shape
        _, data_ncols = input_model.data.shape
        correction = np.ones(data_ncols, dtype=np.float32)
        crpix1 = aperture.pointsource_wcs.crpix1
        crval1 = aperture.pointsource_wcs.crval1
        cdelt1 = aperture.pointsource_wcs.cdelt1
        pupil_wheel_index = crpix1 + (pupil_wheel_position - crval1) / cdelt1 - 1

        if pupil_wheel_index < 0 or pupil_wheel_index > (ncols - 2):
            log.info("Pupil Wheel position outside reference file coverage")
            log.info("Setting pathloss correction to 1.0")
        else:
            ix = int(pupil_wheel_index)
            dx = pupil_wheel_index - ix
            crpix2 = aperture.pointsource_wcs.crpix2
            crval2 = aperture.pointsource_wcs.crval2
            cdelt2 = aperture.pointsource_wcs.cdelt2
            for row in range(data_ncols):
                row_1indexed = row + 1
                refrow_index = math.floor(crpix2 + (row_1indexed - crval2) / cdelt2 - 0.5)
                if refrow_index < 0 or refrow_index > (nrows - 1):
                    correction[row] = 1.0
                else:
                    correction[row] = (1.0 - dx) * pathloss_array[refrow_index, ix] + \
                                      dx * pathloss_array[refrow_index, ix + 1]

        pathloss_2d = np.broadcast_to(correction, input_model.data.shape)
        output_model.data /= pathloss_2d
        output_model.err /= pathloss_2d
        output_model.var_poisson /= pathloss_2d**2
        output_model.var_rnoise /= pathloss_2d**2
        output_model.pathloss = pathloss_2d

        output_model.meta.cal_step.pathloss = 'COMPLETE'

    return output_model
Example #51
0
    def __init__(self, median_model, input_models):
        """
        Short Summary
        -------------
        Class Blot cube holds all the main varibles for blotting an IFU Cube back to
        the detector
        Information is pulled out of the Median Sky Cube created by a previous run
        of cube_build in single mode.

        Basic parameters of the instrument the  data is for is stored.
        The ra,dec, and wavelenth of the median sky cube is set up

        Parameters
        ---------
        median_model: median input sky cube created from a median stack of all the
           individual input_models mapped to the full IFU cube imprint on the sky
        input_models: data model
           a blotted image is created for each science image

        Returns
        -------
        CubeBlot class initialzied
        """
        #Pull out the needed information from the Median IFUCube
        self.median_skycube = median_model
        self.instrument = median_model.meta.instrument.name
        self.detector = median_model.meta.instrument.detector

        #information on how the IFUCube was constructed
        self.weight_power = median_model.meta.ifu.weight_power
        self.weighting = median_model.meta.ifu.weighting
        self.rois = median_model.meta.ifu.roi_spatial
        self.roiw = median_model.meta.ifu.roi_wave

        #basic information about the type of data
        self.grating = None
        self.filter = None
        self.subchannel = None
        self.channel = None

        if self.instrument == 'MIRI':
            self.channel = median_model.meta.instrument.channel
            self.subchannel = median_model.meta.instrument.band.lower()
        elif self.instrument == 'NIRSPEC':
            self.grating = median_model.meta.instrument.grating
            self.filter = median_model.meta.instrument.filter

        # find the ra,dec,lambda of each element of the IFUCube
        self.naxis1 = self.median_skycube.data.shape[2]
        self.naxis2 = self.median_skycube.data.shape[1]
        self.naxis3 = self.median_skycube.data.shape[0]
        self.cdelt1 = median_model.meta.wcsinfo.cdelt1 * 3600.0
        self.cdelt2 = median_model.meta.wcsinfo.cdelt2 * 3600.0
        self.cdelt3 = median_model.meta.wcsinfo.cdelt3 * 3600.0
#_______________________________________________________________________________
        xcube, ycube, zcube = wcstools.grid_from_bounding_box(
            self.median_skycube.meta.wcs.bounding_box,
            step=(1, 1, 1))

        self.cube_ra, self.cube_dec, self.cube_wave = self.median_skycube.meta.wcs(
            xcube,
            ycube,
            zcube)

        flux = self.median_skycube.data
        self.cube_flux = flux
#wavelength slices
        self.lam_centers = self.cube_wave[:, 0, 0]
# initialize blotted images to be original input images

        self.input_models = input_models