Exemplo n.º 1
0
def make_channel_models(channel):
    f = fits.open('MIRI_FM_LW_A_D2C_01.00.00.fits')
    if channel == 3:
        slice_mask = f[3].data[:, :500]
        b1 = f[0].header['B_DEL3']
        b0 = f[0].header['B_MIN3']

    elif channel == 4:
        slice_mask = f[3].data[:, 500:]
        b1 = f[0].header['B_DEL4']
        b0 = f[0].header['B_MIN4']

    slices = np.unique(slice_mask)
    slices = np.asarray(slices, dtype=np.int16).tolist()
    slices.remove(0)

    #read alpha and lambda planes from pixel maps file
    lam = f[1].data
    alpha = f[2].data
    # create a model to fit to each slice in alpha plane
    amodel = models.Chebyshev2D(x_degree=2, y_degree=1)
    # a model to be fitted to each slice in lambda plane
    lmodel = models.Chebyshev2D(x_degree=1, y_degree=1)
    lmodel.c0_1.fixed = True
    lmodel.c1_1.fixed = True
    fitter = fitting.LinearLSQFitter()
    reg_models = {}
    for sl in slices:
        #print('sl', sl)
        ind = (
            slice_mask == sl).nonzero()  #(slice_mask[:, :500] ==sl).nonzero()
        x0 = ind[0].min()
        x1 = ind[0].max()
        y0 = ind[1].min()
        y1 = ind[1].max()
        if channel == 4:
            y0 += 500
            y1 += 500
        x, y = np.mgrid[x0:x1, y0:y1]
        sllam = lam[x0:x1, y0:y1]
        slalpha = alpha[x0:x1, y0:y1]
        lfitted = fitter(lmodel, x, y, sllam)
        afitted = fitter(amodel, x, y, slalpha)

        if channel == 4:
            beta_model = models.Const1D(b0 + b1 * (sl + 12))
            reg_models[sl + 12] = lfitted, afitted, beta_model, (x0, x1, y0,
                                                                 y1)
        else:
            beta_model = models.Const1D(b0 + b1 * sl)
            reg_models[sl] = lfitted, afitted, beta_model, (x0, x1, y0, y1)

    return reg_models
Exemplo n.º 2
0
def test_window_orthopoly(tmpdir):
    model1d = astmodels.Chebyshev1D(2,
                                    c0=2,
                                    c1=3,
                                    c2=0.5,
                                    domain=[-2, 2],
                                    window=[-0.5, 0.5])
    model2d = astmodels.Chebyshev2D(1,
                                    1,
                                    c0_0=1,
                                    c0_1=2,
                                    c1_0=3,
                                    x_domain=[-2, 2],
                                    y_domain=[-2, 2],
                                    x_window=[-0.5, 0.5],
                                    y_window=[-0.1, 0.5])
    fa = AsdfFile()
    fa.tree['model1d'] = model1d
    fa.tree['model2d'] = model2d

    file_path = str(tmpdir.join('orthopoly_window.asdf'))
    fa.write_to(file_path)
    with asdf.open(file_path) as f:
        assert f.tree['model1d'](1.8) == model1d(1.8)
        assert f.tree['model2d'](1.8, -1.5) == model2d(1.8, -1.5)
def fit_poly_surface_2D(x_norm,
                        y_norm,
                        z,
                        weights=None,
                        polytype='chebyshev',
                        poly_deg=5,
                        timit=False,
                        debug_level=0):
    """
    Calculate 2D polynomial fit to normalized x and y values.
    Wrapper function for using the astropy fitting library.
    
    INPUT:
    'x_norm'      : x-values (pixels) of all the lines, re-normalized to [-1,+1]
    'm_norm'      : order numbers of all the lines, re-normalized to [-1,+1]
    'z'           : the 2-dim array of 'observed' values
    'weights'     : weights to use in the fitting
    'polytype'    : types of polynomials to use (either '(p)olynomial' (default), '(l)egendre', or '(c)hebyshev' are accepted)
    'poly_deg'    : degree of the polynomials
    'timit'       : boolean - do you want to measure execution run time?
    'debug_level' : for debugging... 
        
    OUTPUT:
    'p'  : coefficients of the best-fit polynomials
    """

    if timit:
        start_time = time.time()

    if polytype.lower() in ['p', 'polynomial']:
        p_init = models.Polynomial2D(poly_deg)
        if debug_level > 0:
            print('OK, using standard polynomials...')
    elif polytype.lower() in ['c', 'chebyshev']:
        p_init = models.Chebyshev2D(poly_deg, poly_deg)
        if debug_level > 0:
            print('OK, using Chebyshev polynomials...')
    elif polytype.lower() in ['l', 'legendre']:
        p_init = models.Legendre2D(poly_deg, poly_deg)
        if debug_level > 0:
            print('OK, using Legendre polynomials...')
    else:
        print(
            "ERROR: polytype not recognised ['(P)olynomial' / '(C)hebyshev' / '(L)egendre']"
        )
        return

    fit_p = fitting.LevMarLSQFitter()

    with warnings.catch_warnings():
        # Ignore model linearity warning from the fitter
        warnings.simplefilter('ignore')
        p = fit_p(p_init, x_norm, y_norm, z, weights=weights)

    if timit:
        print('Time elapsed: ' +
              np.round(time.time() - start_time, 2).astype(str) +
              ' seconds...')

    return p
Exemplo n.º 4
0
 def test_chebyshev2D_nonlinear_fitting(self):
     cheb2d = models.Chebyshev2D(2, 2)
     cheb2d.parameters = np.arange(9)
     z = cheb2d(self.x, self.y)
     cheb2d.parameters = [0.1, .6, 1.8, 2.9, 3.7, 4.9, 6.7, 7.5, 8.9]
     nlfitter = LevMarLSQFitter()
     model = nlfitter(cheb2d, self.x, self.y, z)
     assert_allclose(model.parameters, [0, 1, 2, 3, 4, 5, 6, 7, 8],
                     atol=10**-9)
Exemplo n.º 5
0
 def test_chebyshev2D_nonlinear_fitting(self):
     cheb2d = models.Chebyshev2D(2, 2)
     cheb2d.parameters = np.arange(9)
     z = cheb2d(self.x, self.y)
     cheb2d.parameters = [0.1, .6, 1.8, 2.9, 3.7, 4.9, 6.7, 7.5, 8.9]
     nlfitter = LevMarLSQFitter()
     with pytest.warns(AstropyUserWarning,
                       match=r'Model is linear in parameters'):
         model = nlfitter(cheb2d, self.x, self.y, z)
     assert_allclose(model.parameters, [0, 1, 2, 3, 4, 5, 6, 7, 8],
                     atol=10**-9)
Exemplo n.º 6
0
    def test_chebyshev2D_nonlinear_fitting_with_weights(self, fitter):
        fitter = fitter()

        cheb2d = models.Chebyshev2D(2, 2)
        cheb2d.parameters = np.arange(9)
        z = cheb2d(self.x, self.y)
        cheb2d.parameters = [0.1, .6, 1.8, 2.9, 3.7, 4.9, 6.7, 7.5, 8.9]
        weights = np.ones_like(self.y)
        with pytest.warns(AstropyUserWarning,
                          match=r'Model is linear in parameters'):
            model = fitter(cheb2d, self.x, self.y, z, weights=weights)
        assert_allclose(model.parameters, [0, 1, 2, 3, 4, 5, 6, 7, 8],
                        atol=10**-9)
Exemplo n.º 7
0
def dict_to_chebyshev(model_dict):
    """
    This is the inverse of chebyshev_to_dict(), taking a dict of property/
    parameter names and their values and making a ChebyshevND model instance.

    Parameters
    ----------
    model_dict: dict
        Dictionary with pair/value that defines the Chebyshev model.

    Returns
    -------
    models.ChebyshevND or None
        Returns the models if it is parsed successfully. If not, it will return
        None.

    Examples
    --------

    .. code-block:: python

        my_model = dict(
            zip(
                ad[0].WAVECAL['name'], ad[0].WAVECAL['coefficient']
            )
        )

    """
    try:
        ndim = int(model_dict.pop('ndim'))
        if ndim == 1:
            model = models.Chebyshev1D(degree=int(model_dict.pop('degree')))
        elif ndim == 2:
            model = models.Chebyshev2D(x_degree=int(model_dict.pop('x_degree')),
                                       y_degree=int(model_dict.pop('y_degree')))
        else:
            return None
    except KeyError:
        return None

    for k, v in model_dict.items():
        try:
            if k.endswith('domain_start'):
                setattr(model, k.replace('_start', ''), [v, model_dict[k.replace('start', 'end')]])
            elif k and not k.endswith('domain_end'):  # ignore k==""
                setattr(model, k, v)
        except (KeyError, AttributeError):
            return None

    return model
Exemplo n.º 8
0
def fit_background(data, mask, npx=4, npy=4):
    """Fit a polynomial surface to all elements of a 2D `data` array where
the corresponding `mask` is True.  Return the fit evaluated at each
point of the original data array.

    """
    assert data.shape == mask.shape
    ny, nx = data.shape
    # y = np.arange(ny).reshape((ny,1))
    # x = np.arange(nx).reshape((1,nx))
    y, x = np.mgrid[:ny, :nx]
    p_init = models.Chebyshev2D(x_degree=npx, y_degree=npy)
    fit_p = fitting.LevMarLSQFitter()
    p = fit_p(p_init, x[mask], y[mask], data[mask])
    return p(x, y)
Exemplo n.º 9
0
    def getmod(self):
        """ Return model for current attributes
        """

        if self.type == 'poly':
            mod = models.Polynomial1D(degree=self.degree)
        elif self.type == 'chebyshev':
            mod = models.Chebyshev1D(degree=self.degree)
        elif self.type == 'chebyshev2D':
            sz = self.spectrum.data.shape
            mod = models.Chebyshev2D(x_degree=self.degree,
                                     y_degree=self.ydegree,
                                     x_domain=[0, sz[1]],
                                     y_domain=[0, sz[0]])
        else:
            raise ValueError('unknown fitting type: ' + self.type)
            return
        return mod
Exemplo n.º 10
0
    def fit2d(self, deg=(6,3)):
        for i, p in enumerate(self.model.param_names):
            if self.ord_len == 1:
                cheb = models.Chebyshev1D(deg[0])
            else:
                cheb = models.Chebyshev2D(deg[0], deg[1])
            fit = fitting.LinearLSQFitter()
            chebfit = fit(cheb, self.x_step, self.ord_step, self.val_step[:, i])
            self.val_full[:, i] = chebfit(self.x_full, self.ord_full)
            #print chebfit.__dict__#fit_info
            #print chebfit.c0_0
#            print chebfit.coeffs
#            print chebfit._parameters
#            prova = chebfit.evaluate(self.x_full, self.ord_full, chebfit._parameters)
            if self.plots:
                plt.scatter(self.x_step, self.val_step[:, i], s=2)
                plt.scatter(self.x_full, self.val_full[:, i], s=2)
#                plt.scatter(self.x_full, prova, s=2)
                plt.show()
Exemplo n.º 11
0
 def setup_class(self):
     self.pmodel = models.Polynomial2D(2)
     self.y, self.x = np.mgrid[:5, :5]
     self.z = self.pmodel(self.x, self.y)
     self.cheb2 = models.Chebyshev2D(2, 2)
     self.fitter = LinearLSQFitter()
Exemplo n.º 12
0
    p4 = astmodels.Polynomial1D(1)
    m1 = p1 & p2
    m2 = p3 & p4
    m1.inverse = m2
    return m1


test_models = [
    astmodels.Identity(2),
    astmodels.Polynomial1D(2, c0=1, c1=2, c2=3),
    astmodels.Polynomial2D(1, c0_0=1, c0_1=2, c1_0=3),
    astmodels.Shift(2.),
    astmodels.Hermite1D(2, c0=2, c1=3, c2=0.5),
    astmodels.Legendre1D(2, c0=2, c1=3, c2=0.5),
    astmodels.Chebyshev1D(2, c0=2, c1=3, c2=0.5),
    astmodels.Chebyshev2D(1, 1, c0_0=1, c0_1=2, c1_0=3),
    astmodels.Legendre2D(1, 1, c0_0=1, c0_1=2, c1_0=3),
    astmodels.Hermite2D(1, 1, c0_0=1, c0_1=2, c1_0=3),
    astmodels.Scale(3.4),
    astmodels.RotateNative2Celestial(5.63, -72.5, 180),
    astmodels.Multiply(3),
    astmodels.Multiply(10 * u.m),
    astmodels.RotateCelestial2Native(5.63, -72.5, 180),
    astmodels.EulerAngleRotation(23, 14, 2.3, axes_order='xzx'),
    astmodels.Mapping((0, 1), n_inputs=3),
    astmodels.Shift(2. * u.deg),
    astmodels.Scale(3.4 * u.deg),
    astmodels.RotateNative2Celestial(5.63 * u.deg, -72.5 * u.deg, 180 * u.deg),
    astmodels.RotateCelestial2Native(5.63 * u.deg, -72.5 * u.deg, 180 * u.deg),
    astmodels.RotationSequence3D([1.2, 2.3, 3.4, .3], 'xyzx'),
    astmodels.SphericalRotationSequence([1.2, 2.3, 3.4, .3], 'xyzy'),
Exemplo n.º 13
0
    def makeSlitIllum(self, adinputs=None, **params):
        """
        Makes the processed Slit Illumination Function by binning a 2D
        spectrum along the dispersion direction, fitting a smooth function
        for each bin, fitting a smooth 2D model, and reconstructing the 2D
        array using this last model.

        Its implementation based on the IRAF's `noao.twodspec.longslit.illumination`
        task following the algorithm described in [Valdes, 1968].

        It expects an input calibration image to be an a dispersed image of the
        slit without illumination problems (e.g, twilight flat). The spectra is
        not required to be smooth in wavelength and may contain strong emission
        and absorption lines. The image should contain a `.mask` attribute in
        each extension, and it is expected to be overscan and bias corrected.

        Parameters
        ----------
        adinputs : list
            List of AstroData objects containing the dispersed image of the
            slit of a source free of illumination problems. The data needs to
            have been overscan and bias corrected and is expected to have a
            Data Quality mask.
        bins : {None, int}, optional
            Total number of bins across the dispersion axis. If None,
            the number of bins will match the number of extensions on each
            input AstroData object. It it is an int, it will create N bins
            with the same size.
        border : int, optional
            Border size that is added on every edge of the slit illumination
            image before cutting it down to the input AstroData frame.
        smooth_order : int, optional
            Order of the spline that is used in each bin fitting to smooth
            the data (Default: 3)
        x_order : int, optional
            Order of the x-component in the Chebyshev2D model used to
            reconstruct the 2D data from the binned data.
        y_order : int, optional
            Order of the y-component in the Chebyshev2D model used to
            reconstruct the 2D data from the binned data.

        Return
        ------
        List of AstroData : containing an AstroData with the Slit Illumination
            Response Function for each of the input object.

        References
        ----------
        .. [Valdes, 1968] Francisco Valdes "Reduction Of Long Slit Spectra With
           IRAF", Proc. SPIE 0627, Instrumentation in Astronomy VI,
           (13 October 1986); https://doi.org/10.1117/12.968155
        """
        log = self.log
        log.debug(gt.log_message("primitive", self.myself(), "starting"))
        timestamp_key = self.timestamp_keys[self.myself()]

        suffix = params["suffix"]
        bins = params["bins"]
        border = params["border"]
        debug_plot = params["debug_plot"]
        smooth_order = params["smooth_order"]
        cheb2d_x_order = params["x_order"]
        cheb2d_y_order = params["y_order"]

        ad_outputs = []
        for ad in adinputs:

            if len(ad) > 1 and "mosaic" not in ad[0].wcs.available_frames:

                log.info('Add "mosaic" gWCS frame to input data')
                geotable = import_module('.geometry_conf', self.inst_lookups)

                # deepcopy prevents modifying input `ad` inplace
                ad = transform.add_mosaic_wcs(deepcopy(ad), geotable)

                log.info("Temporarily mosaicking multi-extension file")
                mosaicked_ad = transform.resample_from_wcs(
                    ad,
                    "mosaic",
                    attributes=None,
                    order=1,
                    process_objcat=False)

            else:

                log.info('Input data already has one extension and has a '
                         '"mosaic" frame.')

                # deepcopy prevents modifying input `ad` inplace
                mosaicked_ad = deepcopy(ad)

            log.info("Transposing data if needed")
            dispaxis = 2 - mosaicked_ad[0].dispersion_axis()  # python sense
            should_transpose = dispaxis == 1

            data, mask, variance = _transpose_if_needed(
                mosaicked_ad[0].data,
                mosaicked_ad[0].mask,
                mosaicked_ad[0].variance,
                transpose=should_transpose)

            log.info("Masking data")
            data = np.ma.masked_array(data, mask=mask)
            variance = np.ma.masked_array(variance, mask=mask)
            std = np.sqrt(variance)  # Easier to work with

            log.info("Creating bins for data and variance")
            height = data.shape[0]
            width = data.shape[1]

            if bins is None:
                nbins = max(len(ad), 12)
                bin_limits = np.linspace(0, height, nbins + 1, dtype=int)
            elif isinstance(bins, int):
                nbins = bins
                bin_limits = np.linspace(0, height, nbins + 1, dtype=int)
            else:
                # ToDo: Handle input bins as array
                raise TypeError("Expected None or Int for `bins`. "
                                "Found: {}".format(type(bins)))

            bin_top = bin_limits[1:]
            bin_bot = bin_limits[:-1]
            binned_data = np.zeros_like(data)
            binned_std = np.zeros_like(std)

            log.info("Smooth binned data and variance, and normalize them by "
                     "smoothed central value")
            for bin_idx, (b0, b1) in enumerate(zip(bin_bot, bin_top)):

                rows = np.arange(width)

                avg_data = np.ma.mean(data[b0:b1], axis=0)
                model_1d_data = astromodels.UnivariateSplineWithOutlierRemoval(
                    rows, avg_data, order=smooth_order)

                avg_std = np.ma.mean(std[b0:b1], axis=0)
                model_1d_std = astromodels.UnivariateSplineWithOutlierRemoval(
                    rows, avg_std, order=smooth_order)

                slit_central_value = model_1d_data(rows)[width // 2]
                binned_data[b0:b1] = model_1d_data(rows) / slit_central_value
                binned_std[b0:b1] = model_1d_std(rows) / slit_central_value

            log.info("Reconstruct 2D mosaicked data")
            bin_center = np.array(0.5 * (bin_bot + bin_top), dtype=int)
            cols_fit, rows_fit = np.meshgrid(np.arange(width), bin_center)

            fitter = fitting.SLSQPLSQFitter()
            model_2d_init = models.Chebyshev2D(x_degree=cheb2d_x_order,
                                               x_domain=(0, width),
                                               y_degree=cheb2d_y_order,
                                               y_domain=(0, height))

            model_2d_data = fitter(model_2d_init, cols_fit, rows_fit,
                                   binned_data[rows_fit, cols_fit])

            model_2d_std = fitter(model_2d_init, cols_fit, rows_fit,
                                  binned_std[rows_fit, cols_fit])

            rows_val, cols_val = \
                np.mgrid[-border:height+border, -border:width+border]

            slit_response_data = model_2d_data(cols_val, rows_val)
            slit_response_mask = np.pad(
                mask, border, mode='edge')  # ToDo: any update to the mask?
            slit_response_std = model_2d_std(cols_val, rows_val)
            slit_response_var = slit_response_std**2

            del cols_fit, cols_val, rows_fit, rows_val

            _data, _mask, _variance = _transpose_if_needed(
                slit_response_data,
                slit_response_mask,
                slit_response_var,
                transpose=dispaxis == 1)

            log.info("Update slit response data and data_section")
            slit_response_ad = deepcopy(mosaicked_ad)
            slit_response_ad[0].data = _data
            slit_response_ad[0].mask = _mask
            slit_response_ad[0].variance = _variance

            if "mosaic" in ad[0].wcs.available_frames:

                log.info(
                    "Map coordinates between slit function and mosaicked data"
                )  # ToDo: Improve message?
                slit_response_ad = _split_mosaic_into_extensions(
                    ad, slit_response_ad, border_size=border)

            elif len(ad) == 1:

                log.info("Trim out borders")

                slit_response_ad[0].data = \
                    slit_response_ad[0].data[border:-border, border:-border]
                slit_response_ad[0].mask = \
                    slit_response_ad[0].mask[border:-border, border:-border]
                slit_response_ad[0].variance = \
                    slit_response_ad[0].variance[border:-border, border:-border]

            log.info("Update metadata and filename")
            gt.mark_history(slit_response_ad,
                            primname=self.myself(),
                            keyword=timestamp_key)

            slit_response_ad.update_filename(suffix=suffix, strip=True)
            ad_outputs.append(slit_response_ad)

            # Plotting ------
            if debug_plot:

                log.info("Creating plots")
                palette = copy(plt.cm.cividis)
                palette.set_bad('r', 0.75)

                norm = vis.ImageNormalize(data[~data.mask],
                                          stretch=vis.LinearStretch(),
                                          interval=vis.PercentileInterval(97))

                fig = plt.figure(num="Slit Response from MEF - {}".format(
                    ad.filename),
                                 figsize=(12, 9),
                                 dpi=110)

                gs = gridspec.GridSpec(nrows=2, ncols=3, figure=fig)

                # Display raw mosaicked data and its bins ---
                ax1 = fig.add_subplot(gs[0, 0])
                im1 = ax1.imshow(data,
                                 cmap=palette,
                                 origin='lower',
                                 vmin=norm.vmin,
                                 vmax=norm.vmax)

                ax1.set_title("Mosaicked Data\n and Spectral Bins",
                              fontsize=10)
                ax1.set_xlim(-1, data.shape[1])
                ax1.set_xticks([])
                ax1.set_ylim(-1, data.shape[0])
                ax1.set_yticks(bin_center)
                ax1.tick_params(axis=u'both', which=u'both', length=0)

                ax1.set_yticklabels(
                    ["Bin {}".format(i) for i in range(len(bin_center))],
                    fontsize=6)

                _ = [ax1.spines[s].set_visible(False) for s in ax1.spines]
                _ = [ax1.axhline(b, c='w', lw=0.5) for b in bin_limits]

                divider = make_axes_locatable(ax1)
                cax1 = divider.append_axes("right", size="5%", pad=0.05)
                plt.colorbar(im1, cax=cax1)

                # Display non-smoothed bins ---
                ax2 = fig.add_subplot(gs[0, 1])
                im2 = ax2.imshow(binned_data, cmap=palette, origin='lower')

                ax2.set_title("Binned, smoothed\n and normalized data ",
                              fontsize=10)
                ax2.set_xlim(0, data.shape[1])
                ax2.set_xticks([])
                ax2.set_ylim(0, data.shape[0])
                ax2.set_yticks(bin_center)
                ax2.tick_params(axis=u'both', which=u'both', length=0)

                ax2.set_yticklabels(
                    ["Bin {}".format(i) for i in range(len(bin_center))],
                    fontsize=6)

                _ = [ax2.spines[s].set_visible(False) for s in ax2.spines]
                _ = [ax2.axhline(b, c='w', lw=0.5) for b in bin_limits]

                divider = make_axes_locatable(ax2)
                cax2 = divider.append_axes("right", size="5%", pad=0.05)
                plt.colorbar(im2, cax=cax2)

                # Display reconstructed slit response ---
                vmin = slit_response_data.min()
                vmax = slit_response_data.max()

                ax3 = fig.add_subplot(gs[1, 0])
                im3 = ax3.imshow(slit_response_data,
                                 cmap=palette,
                                 origin='lower',
                                 vmin=vmin,
                                 vmax=vmax)

                ax3.set_title("Reconstructed\n Slit response", fontsize=10)
                ax3.set_xlim(0, data.shape[1])
                ax3.set_xticks([])
                ax3.set_ylim(0, data.shape[0])
                ax3.set_yticks([])
                ax3.tick_params(axis=u'both', which=u'both', length=0)
                _ = [ax3.spines[s].set_visible(False) for s in ax3.spines]

                divider = make_axes_locatable(ax3)
                cax3 = divider.append_axes("right", size="5%", pad=0.05)
                plt.colorbar(im3, cax=cax3)

                # Display extensions ---
                ax4 = fig.add_subplot(gs[1, 1])
                ax4.set_xticks([])
                ax4.set_yticks([])
                _ = [ax4.spines[s].set_visible(False) for s in ax4.spines]

                sub_gs4 = gridspec.GridSpecFromSubplotSpec(nrows=len(ad),
                                                           ncols=1,
                                                           subplot_spec=gs[1,
                                                                           1],
                                                           hspace=0.03)

                # The [::-1] is needed to put the fist extension in the bottom
                for i, ext in enumerate(slit_response_ad[::-1]):

                    ext_data, ext_mask, ext_variance = _transpose_if_needed(
                        ext.data,
                        ext.mask,
                        ext.variance,
                        transpose=dispaxis == 1)

                    ext_data = np.ma.masked_array(ext_data, mask=ext_mask)

                    sub_ax = fig.add_subplot(sub_gs4[i])

                    im4 = sub_ax.imshow(ext_data,
                                        origin="lower",
                                        vmin=vmin,
                                        vmax=vmax,
                                        cmap=palette)

                    sub_ax.set_xlim(0, ext_data.shape[1])
                    sub_ax.set_xticks([])
                    sub_ax.set_ylim(0, ext_data.shape[0])
                    sub_ax.set_yticks([ext_data.shape[0] // 2])

                    sub_ax.set_yticklabels(
                        ["Ext {}".format(len(slit_response_ad) - i - 1)],
                        fontsize=6)

                    _ = [
                        sub_ax.spines[s].set_visible(False)
                        for s in sub_ax.spines
                    ]

                    if i == 0:
                        sub_ax.set_title(
                            "Multi-extension\n Slit Response Function")

                divider = make_axes_locatable(ax4)
                cax4 = divider.append_axes("right", size="5%", pad=0.05)
                plt.colorbar(im4, cax=cax4)

                # Display Signal-To-Noise Ratio ---
                snr = data / np.sqrt(variance)

                norm = vis.ImageNormalize(snr[~snr.mask],
                                          stretch=vis.LinearStretch(),
                                          interval=vis.PercentileInterval(97))

                ax5 = fig.add_subplot(gs[0, 2])

                im5 = ax5.imshow(snr,
                                 cmap=palette,
                                 origin='lower',
                                 vmin=norm.vmin,
                                 vmax=norm.vmax)

                ax5.set_title("Mosaicked Data SNR", fontsize=10)
                ax5.set_xlim(-1, data.shape[1])
                ax5.set_xticks([])
                ax5.set_ylim(-1, data.shape[0])
                ax5.set_yticks(bin_center)
                ax5.tick_params(axis=u'both', which=u'both', length=0)

                ax5.set_yticklabels(
                    ["Bin {}".format(i) for i in range(len(bin_center))],
                    fontsize=6)

                _ = [ax5.spines[s].set_visible(False) for s in ax5.spines]
                _ = [ax5.axhline(b, c='w', lw=0.5) for b in bin_limits]

                divider = make_axes_locatable(ax5)
                cax5 = divider.append_axes("right", size="5%", pad=0.05)
                plt.colorbar(im5, cax=cax5)

                # Display Signal-To-Noise Ratio of Slit Illumination ---
                slit_response_snr = np.ma.masked_array(
                    slit_response_data / np.sqrt(slit_response_var),
                    mask=slit_response_mask)

                ax6 = fig.add_subplot(gs[1, 2])

                im6 = ax6.imshow(slit_response_snr,
                                 origin="lower",
                                 vmin=norm.vmin,
                                 vmax=norm.vmax,
                                 cmap=palette)

                ax6.set_xlim(0, slit_response_snr.shape[1])
                ax6.set_xticks([])
                ax6.set_ylim(0, slit_response_snr.shape[0])
                ax6.set_yticks([])
                ax6.set_title("Reconstructed\n Slit Response SNR")

                _ = [ax6.spines[s].set_visible(False) for s in ax6.spines]

                divider = make_axes_locatable(ax6)
                cax6 = divider.append_axes("right", size="5%", pad=0.05)
                plt.colorbar(im6, cax=cax6)

                # Save plots ---
                fig.tight_layout(rect=[0, 0, 0.95, 1], pad=0.5)
                fname = slit_response_ad.filename.replace(".fits", ".png")
                log.info("Saving plots to {}".format(fname))
                plt.savefig(fname)

        return ad_outputs
Exemplo n.º 14
0
def test_round_trip_gwcs(tmpdir):
    """
    Add a 2-step gWCS instance to NDAstroData, save to disk, reload & compare.
    """

    from gwcs import coordinate_frames as cf
    from gwcs import WCS

    arr = np.zeros((10, 10), dtype=np.float32)
    ad1 = astrodata.create(fits.PrimaryHDU(), [fits.ImageHDU(arr, name='SCI')])

    # Transformation from detector pixels to pixels in some reference row,
    # removing relative distortions in wavelength:
    det_frame = cf.Frame2D(name='det_mosaic',
                           axes_names=('x', 'y'),
                           unit=(u.pix, u.pix))
    dref_frame = cf.Frame2D(name='dist_ref_row',
                            axes_names=('xref', 'y'),
                            unit=(u.pix, u.pix))

    # A made-up example model that looks vaguely like some real distortions:
    fdist = models.Chebyshev2D(2,
                               2,
                               c0_0=4.81125,
                               c1_0=5.43375,
                               c0_1=-0.135,
                               c1_1=-0.405,
                               c0_2=0.30375,
                               c1_2=0.91125,
                               x_domain=[0., 9.],
                               y_domain=[0., 9.])

    # This is not an accurate inverse, but will do for this test:
    idist = models.Chebyshev2D(2,
                               2,
                               c0_0=4.89062675,
                               c1_0=5.68581232,
                               c2_0=-0.00590263,
                               c0_1=0.11755526,
                               c1_1=0.35652358,
                               c2_1=-0.01193828,
                               c0_2=-0.29996306,
                               c1_2=-0.91823397,
                               c2_2=0.02390594,
                               x_domain=[-1.5, 12.],
                               y_domain=[0., 9.])

    # The resulting 2D co-ordinate mapping from detector to ref row pixels:
    distrans = models.Mapping((0, 1, 1)) | (fdist & models.Identity(1))
    distrans.inverse = models.Mapping((0, 1, 1)) | (idist & models.Identity(1))

    # Transformation from reference row pixels to linear, row-stacked spectra:
    spec_frame = cf.SpectralFrame(axes_order=(0, ),
                                  unit=u.nm,
                                  axes_names='lambda',
                                  name='wavelength')
    row_frame = cf.CoordinateFrame(1,
                                   'SPATIAL',
                                   axes_order=(1, ),
                                   unit=u.pix,
                                   axes_names='y',
                                   name='row')
    rss_frame = cf.CompositeFrame([spec_frame, row_frame])

    # Toy wavelength model & approximate inverse:
    fwcal = models.Chebyshev1D(2, c0=500.075, c1=0.05, c2=0.001, domain=[0, 9])
    iwcal = models.Chebyshev1D(2,
                               c0=4.59006292,
                               c1=4.49601817,
                               c2=-0.08989608,
                               domain=[500.026, 500.126])

    # The resulting 2D co-ordinate mapping from ref pixels to wavelength:
    wavtrans = fwcal & models.Identity(1)
    wavtrans.inverse = iwcal & models.Identity(1)

    # The complete WCS chain for these 2 transformation steps:
    ad1[0].nddata.wcs = WCS([(det_frame, distrans), (dref_frame, wavtrans),
                             (rss_frame, None)])

    # Save & re-load the AstroData instance with its new WCS attribute:
    testfile = str(tmpdir.join('round_trip_gwcs.fits'))
    ad1.write(testfile)
    ad2 = astrodata.open(testfile)

    wcs1 = ad1[0].nddata.wcs
    wcs2 = ad2[0].nddata.wcs

    # # Temporary workaround for issue #9809, to ensure the test is correct:
    # wcs2.forward_transform[1].x_domain = (0, 9)
    # wcs2.forward_transform[1].y_domain = (0, 9)
    # wcs2.forward_transform[3].domain = (0, 9)
    # wcs2.backward_transform[0].domain = (500.026, 500.126)
    # wcs2.backward_transform[3].x_domain = (-1.5, 12.)
    # wcs2.backward_transform[3].y_domain = (0, 9)

    # Did we actually get a gWCS instance back?
    assert isinstance(wcs2, WCS)

    # Do the transforms have the same number of submodels, with the same types,
    # degrees, domains & parameters? Here the inverse gets checked redundantly
    # as both backward_transform and forward_transform.inverse, but it would be
    # convoluted to ensure that both are correct otherwise (since the transforms
    # get regenerated as new compound models each time they are accessed).
    compare_models(wcs1.forward_transform, wcs2.forward_transform)
    compare_models(wcs1.backward_transform, wcs2.backward_transform)

    # Do the instances have matching co-ordinate frames?
    for f in wcs1.available_frames:
        assert repr(getattr(wcs1, f)) == repr(getattr(wcs2, f))

    # Also compare a few transformed values, as the "proof of the pudding":
    y, x = np.mgrid[0:9:2, 0:9:2]
    np.testing.assert_allclose(wcs1(x, y), wcs2(x, y), rtol=1e-7, atol=0.)

    y, w = np.mgrid[0:9:2, 500.025:500.12:0.0225]
    np.testing.assert_allclose(wcs1.invert(w, y),
                               wcs2.invert(w, y),
                               rtol=1e-7,
                               atol=0.)
Exemplo n.º 15
0
    astropy.modeling.math_functions.True_divideUfunc(),

    # astropy.modeling.physical_models
    astropy_models.BlackBody(scale=10.0, temperature=6000. * u.K),
    astropy_models.Drude1D(amplitude=10.0, x_0=0.5, fwhm=2.5),
    # TODO: NFW

    # astropy.modeling.polynomial
    astropy_models.Chebyshev1D(2, c0=2, c1=3, c2=0.5),
    astropy_models.Chebyshev1D(2,
                               c0=2,
                               c1=3,
                               c2=0.5,
                               domain=(0.0, 1.0),
                               window=(1.5, 2.5)),
    astropy_models.Chebyshev2D(1, 1, c0_0=1, c0_1=2, c1_0=3),
    astropy_models.Chebyshev2D(1,
                               1,
                               c0_0=1,
                               c0_1=2,
                               c1_0=3,
                               x_domain=(1.0, 2.0),
                               y_domain=(3.0, 4.0),
                               x_window=(5.0, 6.0),
                               y_window=(7.0, 8.0)),
    astropy_models.Hermite1D(2, c0=2, c1=3, c2=0.5),
    astropy_models.Hermite2D(1, 1, c0_0=1, c0_1=2, c1_0=3),
    astropy_models.Legendre1D(2, c0=2, c1=3, c2=0.5),
    astropy_models.Legendre2D(1, 1, c0_0=1, c0_1=2, c1_0=3),
    astropy_models.Polynomial1D(2, c0=1, c1=2, c2=3),
    astropy_models.Polynomial2D(1, c0_0=1, c0_1=2, c1_0=3),